LibreOffice Module sc (master)  1
column3.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <column.hxx>
21 
22 #include <scitems.hxx>
23 #include <formulacell.hxx>
24 #include <document.hxx>
25 #include <attarray.hxx>
26 #include <patattr.hxx>
27 #include <cellform.hxx>
28 #include <typedstrdata.hxx>
29 #include <formula/errorcodes.hxx>
30 #include <formula/token.hxx>
31 #include <brdcst.hxx>
32 #include <docoptio.hxx>
33 #include <subtotal.hxx>
34 #include <markdata.hxx>
35 #include <stringutil.hxx>
36 #include <docpool.hxx>
37 #include <cellvalue.hxx>
38 #include <tokenarray.hxx>
39 #include <clipcontext.hxx>
40 #include <columnspanset.hxx>
41 #include <mtvcellfunc.hxx>
42 #include <scopetools.hxx>
43 #include <editutil.hxx>
44 #include <sharedformula.hxx>
45 #include <listenercontext.hxx>
46 #include <filterentries.hxx>
47 #include <conditio.hxx>
48 #include <colorscale.hxx>
49 #include <stlpool.hxx>
50 #include <editeng/brushitem.hxx>
51 #include <editeng/colritem.hxx>
52 
53 #include <com/sun/star/i18n/LocaleDataItem2.hpp>
54 #include <com/sun/star/lang/IllegalArgumentException.hpp>
55 
56 #include <memory>
57 
58 #include <rtl/tencinfo.h>
59 
60 #include <svl/numformat.hxx>
61 #include <svl/zforlist.hxx>
62 #include <svl/zformat.hxx>
63 #include <svl/sharedstringpool.hxx>
64 #include <osl/diagnose.h>
65 
66 #include <cstdio>
67 #include <refdata.hxx>
68 
69 using ::com::sun::star::i18n::LocaleDataItem2;
70 
71 using namespace formula;
72 
74 {
75  ScHint aHint(SfxHintId::ScDataChanged, ScAddress(nCol, nRow, nTab));
76  GetDoc().Broadcast(aHint);
77 }
78 
79 void ScColumn::BroadcastCells( const std::vector<SCROW>& rRows, SfxHintId nHint )
80 {
81  if (rRows.empty())
82  return;
83 
84  // Broadcast the changes.
85  ScDocument& rDocument = GetDoc();
86  ScHint aHint(nHint, ScAddress(nCol, 0, nTab));
87  for (const auto& rRow : rRows)
88  {
89  aHint.GetAddress().SetRow(rRow);
90  rDocument.Broadcast(aHint);
91  }
92 }
93 
94 void ScColumn::BroadcastRows( SCROW nStartRow, SCROW nEndRow, SfxHintId nHint )
95 {
96  sc::SingleColumnSpanSet aSpanSet(GetDoc().GetSheetLimits());
97  aSpanSet.scan(*this, nStartRow, nEndRow);
98  std::vector<SCROW> aRows;
99  aSpanSet.getRows(aRows);
100  BroadcastCells(aRows, nHint);
101 }
102 
103 namespace {
104 
105 struct DirtyCellInterpreter
106 {
107  void operator() (size_t, ScFormulaCell* p)
108  {
109  if (p->GetDirty())
110  p->Interpret();
111  }
112 };
113 
114 }
115 
117 {
118  if (!GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2) || nRow1 > nRow2)
119  return;
120 
121  DirtyCellInterpreter aFunc;
122  sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
123 }
124 
125 void ScColumn::DeleteContent( SCROW nRow, bool bBroadcast )
126 {
127  sc::CellStoreType::position_type aPos = maCells.position(nRow);
128  sc::CellStoreType::iterator it = aPos.first;
129  if (it == maCells.end())
130  return;
131 
132  if (it->type == sc::element_type_formula)
133  {
134  ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
135  p->EndListeningTo(GetDoc());
137  }
138  maCells.set_empty(nRow, nRow);
139 
140  if (bBroadcast)
141  {
142  Broadcast(nRow);
143  CellStorageModified();
144  }
145 }
146 
148 {
149  DeleteContent(nRow, false);
150  maCellTextAttrs.set_empty(nRow, nRow);
151  maCellNotes.set_empty(nRow, nRow);
152 
153  Broadcast(nRow);
154  CellStorageModified();
155 }
156 
158 {
159  auto maxRowCount = GetDoc().GetSheetLimits().GetMaxRowCount();
160  // Keep a logical empty range of 0-rDoc.MaxRow() at all times.
161  maCells.clear();
162  maCells.resize(maxRowCount);
163  maCellTextAttrs.clear();
164  maCellTextAttrs.resize(maxRowCount);
165  maCellNotes.clear();
166  maCellNotes.resize(maxRowCount);
167  CellStorageModified();
168 }
169 
171 {
172  maCellNotes.clear();
173  maCellNotes.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
174 }
175 
176 namespace {
177 
178 class ShiftFormulaPosHandler
179 {
180 public:
181 
182  void operator() (size_t nRow, ScFormulaCell* pCell)
183  {
184  pCell->aPos.SetRow(nRow);
185  }
186 };
187 
188 }
189 
190 void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize, std::vector<ScAddress>* pGroupPos )
191 {
192  pAttrArray->DeleteRow( nStartRow, nSize );
193 
194  SCROW nEndRow = nStartRow + nSize - 1;
195 
196  maBroadcasters.erase(nStartRow, nEndRow);
197  maBroadcasters.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
198 
199  CellNotesDeleting(nStartRow, nEndRow, false);
200  maCellNotes.erase(nStartRow, nEndRow);
201  maCellNotes.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
202 
203  // See if we have any cells that would get deleted or shifted by deletion.
204  sc::CellStoreType::position_type aPos = maCells.position(nStartRow);
205  sc::CellStoreType::iterator itCell = aPos.first;
206  if (itCell->type == sc::element_type_empty)
207  {
208  // This is an empty block. If this is the last block, then there is no cells to delete or shift.
209  sc::CellStoreType::iterator itTest = itCell;
210  ++itTest;
211  if (itTest == maCells.end())
212  {
213  // No cells are affected by this deletion. Bail out.
214  CellStorageModified(); // broadcast array has been modified.
215  return;
216  }
217  }
218 
219  // Check if there are any cells below the end row that will get shifted.
220  bool bShiftCells = false;
221  if (nEndRow < GetDoc().MaxRow()) //only makes sense to do this if there *is* a row after the end row
222  {
223  aPos = maCells.position(itCell, nEndRow+1);
224  itCell = aPos.first;
225  if (itCell->type == sc::element_type_empty)
226  {
227  // This block is empty. See if there is any block that follows.
228  sc::CellStoreType::iterator itTest = itCell;
229  ++itTest;
230  if (itTest != maCells.end())
231  // Non-empty block follows -> cells that will get shifted.
232  bShiftCells = true;
233  }
234  else
235  bShiftCells = true;
236  }
237 
238  sc::SingleColumnSpanSet aNonEmptySpans(GetDoc().GetSheetLimits());
239  if (bShiftCells)
240  {
241  // Mark all non-empty cell positions below the end row.
243  aBlockPos.miCellPos = itCell;
244  aNonEmptySpans.scan(aBlockPos, *this, nEndRow+1, GetDoc().MaxRow());
245  }
246 
247  sc::AutoCalcSwitch aACSwitch(GetDoc(), false);
248 
249  // Remove the cells.
250  maCells.erase(nStartRow, nEndRow);
251  maCells.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
252 
253  // Get the position again after the container change.
254  aPos = maCells.position(nStartRow);
255 
256  // Shift the formula cell positions below the start row.
257  ShiftFormulaPosHandler aShiftFormulaFunc;
258  sc::ProcessFormula(aPos.first, maCells, nStartRow, GetDoc().MaxRow(), aShiftFormulaFunc);
259 
260  bool bJoined = sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
261  if (bJoined && pGroupPos)
262  pGroupPos->push_back(ScAddress(nCol, nStartRow, nTab));
263 
264  // Shift the text attribute array too (before the broadcast).
265  maCellTextAttrs.erase(nStartRow, nEndRow);
266  maCellTextAttrs.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
267 
268  CellStorageModified();
269 }
270 
271 sc::CellStoreType::iterator ScColumn::GetPositionToInsert( SCROW nRow, std::vector<SCROW>& rNewSharedRows,
272  bool bInsertFormula )
273 {
274  return GetPositionToInsert(maCells.begin(), nRow, rNewSharedRows, bInsertFormula);
275 }
276 
278  const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell )
279 {
280  // Check the previous row position for possible grouping.
281  if (aPos.first->type == sc::element_type_formula && aPos.second > 0)
282  {
283  ScFormulaCell& rPrev = *sc::formula_block::at(*aPos.first->data, aPos.second-1);
284  sc::CellStoreType::position_type aPosPrev = aPos;
285  --aPosPrev.second;
286  sc::SharedFormulaUtil::joinFormulaCells(aPosPrev, rPrev, rCell);
287  }
288 
289  // Check the next row position for possible grouping.
290  if (aPos.first->type == sc::element_type_formula && aPos.second+1 < aPos.first->size)
291  {
292  ScFormulaCell& rNext = *sc::formula_block::at(*aPos.first->data, aPos.second+1);
293  sc::SharedFormulaUtil::joinFormulaCells(aPos, rCell, rNext);
294  }
295 }
296 
298  const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, std::vector<SCROW>& rNewSharedRows )
299 {
300  if (!GetDoc().IsClipOrUndo())
301  {
302 #if USE_FORMULA_GROUP_LISTENER
303  if (rCell.IsShared() && rCell.GetSharedLength() > 1)
304  {
305  // Record new spans (shared or remaining single) that will result
306  // from unsharing to reestablish listeners.
307  // Same cases as in unshareFormulaCell().
308  // XXX NOTE: this is not part of unshareFormulaCell() because that
309  // is called in other contexts as well, for which passing and
310  // determining the rows vector would be superfluous. If that was
311  // needed, move it there.
312  const SCROW nSharedTopRow = rCell.GetSharedTopRow();
313  const SCROW nSharedLength = rCell.GetSharedLength();
314  if (rCell.aPos.Row() == nSharedTopRow)
315  {
316  // Top cell.
317  // Next row will be new shared top or single cell.
318  rNewSharedRows.push_back( nSharedTopRow + 1);
319  rNewSharedRows.push_back( nSharedTopRow + nSharedLength - 1);
320  }
321  else if (rCell.aPos.Row() == nSharedTopRow + nSharedLength - 1)
322  {
323  // Bottom cell.
324  // Current shared top row will be new shared top again or
325  // single cell.
326  rNewSharedRows.push_back( nSharedTopRow);
327  rNewSharedRows.push_back( rCell.aPos.Row() - 1);
328  }
329  else
330  {
331  // Some mid cell.
332  // Current shared top row will be new shared top again or
333  // single cell, plus a new shared top below or single cell.
334  rNewSharedRows.push_back( nSharedTopRow);
335  rNewSharedRows.push_back( rCell.aPos.Row() - 1);
336  rNewSharedRows.push_back( rCell.aPos.Row() + 1);
337  rNewSharedRows.push_back( nSharedTopRow + nSharedLength - 1);
338  }
339  }
340 #endif
341 
342  // Have the dying formula cell stop listening.
343  // If in a shared formula group this ends the group listening.
344  rCell.EndListeningTo(GetDoc());
345  }
346 
348 }
349 
350 void ScColumn::StartListeningUnshared( const std::vector<SCROW>& rNewSharedRows )
351 {
352  assert(rNewSharedRows.empty() || rNewSharedRows.size() == 2 || rNewSharedRows.size() == 4);
353  ScDocument& rDoc = GetDoc();
354  if (rNewSharedRows.empty() || rDoc.IsDelayedFormulaGrouping())
355  return;
356 
357  auto pPosSet = std::make_shared<sc::ColumnBlockPositionSet>(rDoc);
358  sc::StartListeningContext aStartCxt(rDoc, pPosSet);
359  sc::EndListeningContext aEndCxt(rDoc, pPosSet);
360  if (rNewSharedRows.size() >= 2)
361  {
362  if(!rDoc.CanDelayStartListeningFormulaCells( this, rNewSharedRows[0], rNewSharedRows[1]))
363  StartListeningFormulaCells(aStartCxt, aEndCxt, rNewSharedRows[0], rNewSharedRows[1]);
364  }
365  if (rNewSharedRows.size() >= 4)
366  {
367  if(!rDoc.CanDelayStartListeningFormulaCells( this, rNewSharedRows[2], rNewSharedRows[3]))
368  StartListeningFormulaCells(aStartCxt, aEndCxt, rNewSharedRows[2], rNewSharedRows[3]);
369  }
370 }
371 
372 namespace {
373 
374 class AttachFormulaCellsHandler
375 {
377 
378 public:
379  explicit AttachFormulaCellsHandler(sc::StartListeningContext& rCxt)
380  : mrCxt(rCxt) {}
381 
382  void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
383  {
384  pCell->StartListeningTo(mrCxt);
385  }
386 };
387 
388 class DetachFormulaCellsHandler
389 {
390  ScDocument& mrDoc;
392 
393 public:
394  DetachFormulaCellsHandler( ScDocument& rDoc, sc::EndListeningContext* pCxt ) :
395  mrDoc(rDoc), mpCxt(pCxt) {}
396 
397  void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
398  {
399  if (mpCxt)
400  pCell->EndListeningTo(*mpCxt);
401  else
402  pCell->EndListeningTo(mrDoc);
403  }
404 };
405 
406 }
407 
409  const sc::CellStoreType::position_type& aPos, size_t nLength, std::vector<SCROW>* pNewSharedRows )
410 {
411  const size_t nRow = aPos.first->position + aPos.second;
412  const size_t nNextTopRow = nRow + nLength; // start row of next formula group.
413 
414  bool bLowerSplitOff = false;
415  if (pNewSharedRows && !GetDoc().IsClipOrUndo())
416  {
418  if (pFC)
419  {
420  const SCROW nTopRow = pFC->GetSharedTopRow();
421  const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1;
422  // nTopRow <= nRow <= nBotRow, because otherwise pFC would not exist.
423  if (nTopRow < static_cast<SCROW>(nRow))
424  {
425  // Upper part will be split off.
426  pNewSharedRows->push_back(nTopRow);
427  pNewSharedRows->push_back(nRow - 1);
428  }
429  if (static_cast<SCROW>(nNextTopRow) <= nBotRow)
430  {
431  // Lower part will be split off.
432  pNewSharedRows->push_back(nNextTopRow);
433  pNewSharedRows->push_back(nBotRow);
434  bLowerSplitOff = true;
435  }
436  }
437  }
438 
439  // Split formula grouping at the top and bottom boundaries.
441 
442  if (nLength > 0 && GetDoc().ValidRow(nNextTopRow))
443  {
444  if (pNewSharedRows && !bLowerSplitOff && !GetDoc().IsClipOrUndo())
445  {
446  sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nNextTopRow-1);
448  if (pFC)
449  {
450  const SCROW nTopRow = pFC->GetSharedTopRow();
451  const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1;
452  // nRow < nTopRow < nNextTopRow <= nBotRow
453  if (static_cast<SCROW>(nNextTopRow) <= nBotRow)
454  {
455  // Lower part will be split off.
456  pNewSharedRows->push_back(nNextTopRow);
457  pNewSharedRows->push_back(nBotRow);
458  }
459  }
460  }
461 
462  sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nNextTopRow);
464  }
465 
466  if (GetDoc().IsClipOrUndo())
467  return;
468 
469  DetachFormulaCellsHandler aFunc(GetDoc(), nullptr);
470  sc::ProcessFormula(aPos.first, maCells, nRow, nNextTopRow-1, aFunc);
471 }
472 
474 {
475  sc::CellStoreType::position_type aPos = maCells.position(nRow1);
476  sc::CellStoreType::iterator it = aPos.first;
477 
479  if (GetDoc().ValidRow(nRow2+1))
480  {
481  aPos = maCells.position(it, nRow2+1);
483  }
484 
485  if (GetDoc().IsClipOrUndo())
486  return;
487 
488  AttachFormulaCellsHandler aFunc(rCxt);
489  sc::ProcessFormula(it, maCells, nRow1, nRow2, aFunc);
490 }
491 
493  std::vector<SCROW>* pNewSharedRows )
494 {
495  sc::CellStoreType::position_type aPos = maCells.position(nRow1);
496  sc::CellStoreType::iterator it = aPos.first;
497 
498  bool bLowerSplitOff = false;
499  if (pNewSharedRows && !GetDoc().IsClipOrUndo())
500  {
502  if (pFC)
503  {
504  const SCROW nTopRow = pFC->GetSharedTopRow();
505  const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1;
506  // nTopRow <= nRow1 <= nBotRow, because otherwise pFC would not exist.
507  if (nTopRow < nRow1)
508  {
509  // Upper part will be split off.
510  pNewSharedRows->push_back(nTopRow);
511  pNewSharedRows->push_back(nRow1 - 1);
512  }
513  if (nRow2 < nBotRow)
514  {
515  // Lower part will be split off.
516  pNewSharedRows->push_back(nRow2 + 1);
517  pNewSharedRows->push_back(nBotRow);
518  bLowerSplitOff = true;
519  }
520  }
521  }
522 
523  // Split formula grouping at the top and bottom boundaries.
525  if (GetDoc().ValidRow(nRow2+1))
526  {
527  if (pNewSharedRows && !bLowerSplitOff && !GetDoc().IsClipOrUndo())
528  {
529  sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nRow2);
531  if (pFC)
532  {
533  const SCROW nTopRow = pFC->GetSharedTopRow();
534  const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1;
535  // nRow1 < nTopRow <= nRow2 < nBotRow
536  if (nRow2 < nBotRow)
537  {
538  // Lower part will be split off.
539  pNewSharedRows->push_back(nRow2 + 1);
540  pNewSharedRows->push_back(nBotRow);
541  }
542  }
543  }
544 
545  aPos = maCells.position(it, nRow2+1);
547  }
548 
549  if (GetDoc().IsClipOrUndo())
550  return;
551 
552  DetachFormulaCellsHandler aFunc(GetDoc(), &rCxt);
553  sc::ProcessFormula(it, maCells, nRow1, nRow2, aFunc);
554 }
555 
556 static void lcl_AddFormulaGroupBoundaries(const sc::CellStoreType::position_type& rPos,
557  std::vector<SCROW>& rNewSharedRows )
558 {
559  sc::CellStoreType::iterator itRet = rPos.first;
560  if (itRet->type != sc::element_type_formula)
561  return;
562 
563  ScFormulaCell& rFC = *sc::formula_block::at(*itRet->data, rPos.second);
564  if ( rFC.IsShared() )
565  {
566  const SCROW nSharedTopRow = rFC.GetSharedTopRow();
567  const SCROW nSharedLength = rFC.GetSharedLength();
568  rNewSharedRows.push_back( nSharedTopRow);
569  rNewSharedRows.push_back( nSharedTopRow + nSharedLength - 1);
570  }
571  else
572  {
573  const SCROW nRow = rFC.aPos.Row();
574  rNewSharedRows.push_back( nRow);
575  rNewSharedRows.push_back( nRow);
576  }
577 }
578 
579 sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow,
580  std::vector<SCROW>& rNewSharedRows, bool bInsertFormula )
581 {
582  // See if we are overwriting an existing formula cell.
583  sc::CellStoreType::position_type aPos = maCells.position(it, nRow);
584  sc::CellStoreType::iterator itRet = aPos.first;
585 
586  if (itRet->type == sc::element_type_formula)
587  {
588  ScFormulaCell& rCell = *sc::formula_block::at(*itRet->data, aPos.second);
589  DetachFormulaCell(aPos, rCell, rNewSharedRows);
590  }
591  else if (bInsertFormula && !GetDoc().IsClipOrUndo())
592  {
593  if (nRow > 0)
594  {
595  sc::CellStoreType::position_type aPosBefore = maCells.position(maCells.begin(), nRow-1);
596  lcl_AddFormulaGroupBoundaries(aPosBefore, rNewSharedRows);
597  }
598  if (nRow < GetDoc().MaxRow())
599  {
600  sc::CellStoreType::position_type aPosAfter = maCells.position(maCells.begin(), nRow+1);
601  lcl_AddFormulaGroupBoundaries(aPosAfter, rNewSharedRows);
602  }
603  }
604 
605  return itRet;
606 }
607 
609  const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell,
610  const std::vector<SCROW>& rNewSharedRows,
611  bool bJoin, sc::StartListeningType eListenType )
612 {
613  AttachNewFormulaCell(maCells.position(itPos, nRow), rCell, rNewSharedRows, bJoin, eListenType);
614 }
615 
617  const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell,
618  const std::vector<SCROW>& rNewSharedRows,
619  bool bJoin, sc::StartListeningType eListenType )
620 {
621  if (bJoin)
622  // See if this new formula cell can join an existing shared formula group.
623  JoinNewFormulaCell(aPos, rCell);
624 
625  // When we insert from the Clipboard we still have wrong (old) References!
626  // First they are rewired in CopyBlockFromClip via UpdateReference and the
627  // we call StartListeningFromClip and BroadcastFromClip.
628  // If we insert into the Clipboard/andoDoc, we do not use a Broadcast.
629  // After Import we call CalcAfterLoad and in there Listening.
630  ScDocument& rDocument = GetDoc();
631  if (rDocument.IsClipOrUndo() || rDocument.IsInsertingFromOtherDoc())
632  return;
633 
634  switch (eListenType)
635  {
637  {
638  auto pPosSet = std::make_shared<sc::ColumnBlockPositionSet>(rDocument);
639  sc::StartListeningContext aStartCxt(rDocument, pPosSet);
640  sc::EndListeningContext aEndCxt(rDocument, pPosSet);
641  SCROW nStartRow, nEndRow;
642  nStartRow = nEndRow = aPos.first->position + aPos.second;
643  for (const SCROW nR : rNewSharedRows)
644  {
645  if (nStartRow > nR)
646  nStartRow = nR;
647  if (nEndRow < nR)
648  nEndRow = nR;
649  }
650  StartListeningFormulaCells(aStartCxt, aEndCxt, nStartRow, nEndRow);
651  }
652  break;
654  rCell.StartListeningTo(rDocument);
655  StartListeningUnshared( rNewSharedRows);
656  break;
657  case sc::NoListening:
658  default:
659  if (!rNewSharedRows.empty())
660  {
661  assert(rNewSharedRows.size() == 2 || rNewSharedRows.size() == 4);
662  // Calling SetNeedsListeningGroup() with a top row sets it to
663  // all affected formula cells of that group.
664  const ScFormulaCell* pFC = GetFormulaCell( rNewSharedRows[0]);
665  assert(pFC); // that *is* supposed to be a top row
666  if (pFC && !pFC->NeedsListening())
667  SetNeedsListeningGroup( rNewSharedRows[0]);
668  if (rNewSharedRows.size() > 2)
669  {
670  pFC = GetFormulaCell( rNewSharedRows[2]);
671  assert(pFC); // that *is* supposed to be a top row
672  if (pFC && !pFC->NeedsListening())
673  SetNeedsListeningGroup( rNewSharedRows[2]);
674  }
675  }
676  break;
677  }
678 
679  if (!rDocument.IsCalcingAfterLoad())
680  rCell.SetDirty();
681 }
682 
683 void ScColumn::AttachNewFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength,
684  std::vector<SCROW>& rNewSharedRows )
685 {
686  // Make sure the whole length consists of formula cells.
687  if (aPos.first->type != sc::element_type_formula)
688  return;
689 
690  if (aPos.first->size < aPos.second + nLength)
691  // Block is shorter than specified length.
692  return;
693 
694  // Join the top and bottom cells only.
695  ScFormulaCell* pCell1 = sc::formula_block::at(*aPos.first->data, aPos.second);
696  JoinNewFormulaCell(aPos, *pCell1);
697 
698  sc::CellStoreType::position_type aPosLast = aPos;
699  aPosLast.second += nLength - 1;
700  ScFormulaCell* pCell2 = sc::formula_block::at(*aPosLast.first->data, aPosLast.second);
701  JoinNewFormulaCell(aPosLast, *pCell2);
702 
703  ScDocument& rDocument = GetDoc();
704  if (rDocument.IsClipOrUndo() || rDocument.IsInsertingFromOtherDoc())
705  return;
706 
707  const bool bShared = pCell1->IsShared() || pCell2->IsShared();
708  if (bShared)
709  {
710  const SCROW nTopRow = (pCell1->IsShared() ? pCell1->GetSharedTopRow() : pCell1->aPos.Row());
711  const SCROW nBotRow = (pCell2->IsShared() ?
712  pCell2->GetSharedTopRow() + pCell2->GetSharedLength() - 1 : pCell2->aPos.Row());
713  if (rNewSharedRows.empty())
714  {
715  rNewSharedRows.push_back( nTopRow);
716  rNewSharedRows.push_back( nBotRow);
717  }
718  else if (rNewSharedRows.size() == 2)
719  {
720  // Combine into one span.
721  if (rNewSharedRows[0] > nTopRow)
722  rNewSharedRows[0] = nTopRow;
723  if (rNewSharedRows[1] < nBotRow)
724  rNewSharedRows[1] = nBotRow;
725  }
726  else if (rNewSharedRows.size() == 4)
727  {
728  // Merge into one span.
729  // The original two spans are ordered from top to bottom.
730  std::vector<SCROW> aRows { std::min( rNewSharedRows[0], nTopRow), std::max( rNewSharedRows[3], nBotRow) };
731  rNewSharedRows.swap( aRows);
732  }
733  else
734  {
735  assert(!"rNewSharedRows?");
736  }
737  }
738  StartListeningUnshared( rNewSharedRows);
739 
740  sc::StartListeningContext aCxt(rDocument);
741  ScFormulaCell** pp = &sc::formula_block::at(*aPos.first->data, aPos.second);
742  ScFormulaCell** ppEnd = pp + nLength;
743  for (; pp != ppEnd; ++pp)
744  {
745  if (!bShared)
746  (*pp)->StartListeningTo(aCxt);
747  if (!rDocument.IsCalcingAfterLoad())
748  (*pp)->SetDirty();
749  }
750 }
751 
753 {
754  // When we insert from the Clipboard we still have wrong (old) References!
755  // First they are rewired in CopyBlockFromClip via UpdateReference and the
756  // we call StartListeningFromClip and BroadcastFromClip.
757  // If we insert into the Clipboard/andoDoc, we do not use a Broadcast.
758  // After Import we call CalcAfterLoad and in there Listening.
759  if (GetDoc().IsClipOrUndo() || GetDoc().IsInsertingFromOtherDoc() || GetDoc().IsCalcingAfterLoad())
760  return;
761 
762  Broadcast(nRow);
763 }
764 
765 bool ScColumn::UpdateScriptType( sc::CellTextAttr& rAttr, SCROW nRow, sc::CellStoreType::iterator& itr )
766 {
767  if (rAttr.mnScriptType != SvtScriptType::UNKNOWN)
768  // Already updated. Nothing to do.
769  return false;
770 
771  // Script type not yet determined. Determine the real script
772  // type, and store it.
773  const ScPatternAttr* pPattern = GetPattern(nRow);
774  if (!pPattern)
775  return false;
776 
777  sc::CellStoreType::position_type pos = maCells.position(itr, nRow);
778  itr = pos.first;
779  size_t nOffset = pos.second;
780  ScRefCellValue aCell = GetCellValue( itr, nOffset );
781  ScAddress aPos(nCol, nRow, nTab);
782 
783  ScDocument& rDocument = GetDoc();
784  const SfxItemSet* pCondSet = nullptr;
785  ScConditionalFormatList* pCFList = rDocument.GetCondFormList(nTab);
786  if (pCFList)
787  {
788  const ScCondFormatItem& rItem =
789  pPattern->GetItem(ATTR_CONDITIONAL);
791  pCondSet = rDocument.GetCondResult(aCell, aPos, *pCFList, rData);
792  }
793 
794  SvNumberFormatter* pFormatter = rDocument.GetFormatTable();
795 
796  OUString aStr;
797  const Color* pColor;
798  sal_uInt32 nFormat = pPattern->GetNumberFormat(pFormatter, pCondSet);
799  ScCellFormat::GetString(aCell, nFormat, aStr, &pColor, *pFormatter, rDocument);
800 
801  // Store the real script type to the array.
802  rAttr.mnScriptType = rDocument.GetStringScriptType(aStr);
803  return true;
804 }
805 
806 namespace {
807 
808 class DeleteAreaHandler
809 {
810  ScDocument& mrDoc;
811  std::vector<ScFormulaCell*> maFormulaCells;
812  sc::SingleColumnSpanSet maDeleteRanges;
813 
814  bool mbNumeric:1;
815  bool mbString:1;
816  bool mbFormula:1;
817  bool mbDateTime:1;
818  ScColumn& mrCol;
819 
820 public:
821  DeleteAreaHandler(ScDocument& rDoc, InsertDeleteFlags nDelFlag, ScColumn& rCol) :
822  mrDoc(rDoc),
823  maDeleteRanges(rDoc.GetSheetLimits()),
824  mbNumeric(nDelFlag & InsertDeleteFlags::VALUE),
825  mbString(nDelFlag & InsertDeleteFlags::STRING),
826  mbFormula(nDelFlag & InsertDeleteFlags::FORMULA),
827  mbDateTime(nDelFlag & InsertDeleteFlags::DATETIME),
828  mrCol(rCol) {}
829 
830  void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
831  {
832  switch (node.type)
833  {
835  // Numeric type target datetime and number, thus we have a dedicated function
836  if (!mbNumeric && !mbDateTime)
837  return;
838 
839  // If numeric and datetime selected, delete full range
840  if (mbNumeric && mbDateTime)
841  break;
842 
843  deleteNumeric(node, nOffset, nDataSize);
844  return;
847  if (!mbString)
848  return;
849  break;
851  {
852  if (!mbFormula)
853  return;
854 
855  sc::formula_block::iterator it = sc::formula_block::begin(*node.data) + nOffset;
856  sc::formula_block::iterator itEnd = it + nDataSize;
857  maFormulaCells.insert(maFormulaCells.end(), it, itEnd);
858  }
859  break;
861  default:
862  return;
863  }
864 
865  // Tag these cells for deletion.
866  SCROW nRow1 = node.position + nOffset;
867  SCROW nRow2 = nRow1 + nDataSize - 1;
868  maDeleteRanges.set(nRow1, nRow2, true);
869  }
870 
871  void deleteNumeric(const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
872  {
873  size_t nStart = node.position + nOffset;
874  size_t nElements = 1;
875  bool bLastTypeDateTime = isDateTime(nStart); // true = datetime, false = numeric
876  size_t nCount = nStart + nDataSize;
877 
878  for (size_t i = nStart + 1; i < nCount; i++)
879  {
880  bool bIsDateTime = isDateTime(i);
881 
882  // same type as previous
883  if (bIsDateTime == bLastTypeDateTime)
884  {
885  nElements++;
886  }
887  // type switching
888  else
889  {
890  deleteNumberOrDateTime(nStart, nStart + nElements - 1, bLastTypeDateTime);
891  nStart += nElements;
892  nElements = 1;
893  }
894 
895  bLastTypeDateTime = bIsDateTime;
896  }
897 
898  // delete last cells
899  deleteNumberOrDateTime(nStart, nStart + nElements - 1, bLastTypeDateTime);
900  }
901 
902  void deleteNumberOrDateTime(SCROW nRow1, SCROW nRow2, bool dateTime)
903  {
904  if (!dateTime && !mbNumeric) // numeric flag must be selected
905  return;
906  if (dateTime && !mbDateTime) // datetime flag must be selected
907  return;
908  maDeleteRanges.set(nRow1, nRow2, true);
909  }
910 
911  bool isDateTime(size_t position)
912  {
914  mrCol.GetAttr(position, ATTR_VALUE_FORMAT).GetValue());
915 
916  return (nType == SvNumFormatType::DATE) || (nType == SvNumFormatType::TIME) ||
917  (nType == SvNumFormatType::DATETIME);
918  }
919 
920  void endFormulas()
921  {
922  mrDoc.EndListeningFormulaCells(maFormulaCells);
923  }
924 
925  sc::SingleColumnSpanSet& getSpans()
926  {
927  return maDeleteRanges;
928  }
929 };
930 
931 class EmptyCells
932 {
933  ScColumn& mrColumn;
935 
936  static void splitFormulaGrouping(const sc::CellStoreType::position_type& rPos)
937  {
938  if (rPos.first->type == sc::element_type_formula)
939  {
940  ScFormulaCell& rCell = *sc::formula_block::at(*rPos.first->data, rPos.second);
942  }
943  }
944 
945 public:
946  EmptyCells( sc::ColumnBlockPosition& rPos, ScColumn& rColumn ) :
947  mrColumn(rColumn), mrPos(rPos) {}
948 
949  void operator() (const sc::RowSpan& rSpan)
950  {
951  sc::CellStoreType& rCells = mrColumn.GetCellStore();
952 
953  // First, split formula grouping at the top and bottom boundaries
954  // before emptying the cells.
955  sc::CellStoreType::position_type aPos = rCells.position(mrPos.miCellPos, rSpan.mnRow1);
956  splitFormulaGrouping(aPos);
957  aPos = rCells.position(aPos.first, rSpan.mnRow2);
958  splitFormulaGrouping(aPos);
959 
960  mrPos.miCellPos = rCells.set_empty(mrPos.miCellPos, rSpan.mnRow1, rSpan.mnRow2);
961  mrPos.miCellTextAttrPos = mrColumn.GetCellAttrStore().set_empty(mrPos.miCellTextAttrPos, rSpan.mnRow1, rSpan.mnRow2);
962  }
963 };
964 
965 }
966 
968  sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2, InsertDeleteFlags nDelFlag,
969  sc::SingleColumnSpanSet& rDeleted )
970 {
971  // Determine which cells to delete based on the deletion flags.
972  DeleteAreaHandler aFunc(GetDoc(), nDelFlag, *this);
973  sc::CellStoreType::iterator itPos = maCells.position(rBlockPos.miCellPos, nRow1).first;
974  sc::ProcessBlock(itPos, maCells, aFunc, nRow1, nRow2);
975  aFunc.endFormulas(); // Have the formula cells stop listening.
976 
977  // Get the deletion spans.
979  aFunc.getSpans().getSpans(aSpans);
980 
981  // Delete the cells for real.
982  // tdf#139820: Deleting in reverse order is more efficient.
983  std::for_each(aSpans.rbegin(), aSpans.rend(), EmptyCells(rBlockPos, *this));
984  CellStorageModified();
985 
986  aFunc.getSpans().swap(rDeleted);
987 }
988 
990  SCROW nStartRow, SCROW nEndRow, InsertDeleteFlags nDelFlag, bool bBroadcast,
991  sc::ColumnSpanSet* pBroadcastSpans )
992 {
994  // InsertDeleteFlags::NOCAPTIONS needs to be passed too, if InsertDeleteFlags::NOTE is set
995  if( nDelFlag & InsertDeleteFlags::NOTE )
996  nContMask |= InsertDeleteFlags::NOCAPTIONS;
997  InsertDeleteFlags nContFlag = nDelFlag & nContMask;
998 
999  sc::SingleColumnSpanSet aDeletedRows(GetDoc().GetSheetLimits());
1000 
1001  sc::ColumnBlockPosition aBlockPos;
1002  InitBlockPosition(aBlockPos);
1003 
1004  if (!IsEmptyData() && nContFlag != InsertDeleteFlags::NONE)
1005  {
1006  DeleteCells(aBlockPos, nStartRow, nEndRow, nDelFlag, aDeletedRows);
1007  if (pBroadcastSpans)
1008  {
1010  aDeletedRows.getSpans(aSpans);
1011  for (const auto& rSpan : aSpans)
1012  pBroadcastSpans->set(GetDoc(), nTab, nCol, rSpan.mnRow1, rSpan.mnRow2, true);
1013  }
1014  }
1015 
1016  if (nDelFlag & InsertDeleteFlags::NOTE)
1017  {
1018  bool bForgetCaptionOwnership = ((nDelFlag & InsertDeleteFlags::FORGETCAPTIONS) != InsertDeleteFlags::NONE);
1019  DeleteCellNotes(aBlockPos, nStartRow, nEndRow, bForgetCaptionOwnership);
1020  }
1021 
1022  if ( nDelFlag & InsertDeleteFlags::EDITATTR )
1023  {
1024  OSL_ENSURE( nContFlag == InsertDeleteFlags::NONE, "DeleteArea: Wrong Flags" );
1025  RemoveEditAttribs( nStartRow, nEndRow );
1026  }
1027 
1028  // Delete attributes just now
1029  if ((nDelFlag & InsertDeleteFlags::ATTRIB) == InsertDeleteFlags::ATTRIB)
1030  pAttrArray->DeleteArea( nStartRow, nEndRow );
1031  else if ((nDelFlag & InsertDeleteFlags::HARDATTR) == InsertDeleteFlags::HARDATTR)
1032  pAttrArray->DeleteHardAttr( nStartRow, nEndRow );
1033 
1034  if (bBroadcast)
1035  {
1036  // Broadcast on only cells that were deleted; no point broadcasting on
1037  // cells that were already empty before the deletion.
1038  std::vector<SCROW> aRows;
1039  aDeletedRows.getRows(aRows);
1040  BroadcastCells(aRows, SfxHintId::ScDataChanged);
1041  }
1042 }
1043 
1045 {
1046  rBlockPos.miBroadcasterPos = maBroadcasters.begin();
1047  rBlockPos.miCellNotePos = maCellNotes.begin();
1048  rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
1049  rBlockPos.miCellPos = maCells.begin();
1050 }
1051 
1053 {
1054  rBlockPos.miCellNotePos = maCellNotes.begin();
1055  rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
1056  rBlockPos.miCellPos = maCells.begin();
1057 }
1058 
1059 namespace {
1060 
1061 class CopyAttrArrayByRange
1062 {
1063  ScAttrArray& mrDestAttrArray;
1064  ScAttrArray& mrSrcAttrArray;
1065  tools::Long mnRowOffset;
1066 public:
1067  CopyAttrArrayByRange(ScAttrArray& rDestAttrArray, ScAttrArray& rSrcAttrArray, tools::Long nRowOffset) :
1068  mrDestAttrArray(rDestAttrArray), mrSrcAttrArray(rSrcAttrArray), mnRowOffset(nRowOffset) {}
1069 
1070  void operator() (const sc::RowSpan& rSpan)
1071  {
1072  mrDestAttrArray.CopyAreaSafe(
1073  rSpan.mnRow1+mnRowOffset, rSpan.mnRow2+mnRowOffset, mnRowOffset, mrSrcAttrArray);
1074  }
1075 };
1076 
1077 class CopyCellsFromClipHandler
1078 {
1079  sc::CopyFromClipContext& mrCxt;
1080  ScColumn& mrSrcCol;
1081  ScColumn& mrDestCol;
1082  SCTAB mnTab;
1083  SCCOL mnCol;
1084  SCTAB mnSrcTab;
1085  SCCOL mnSrcCol;
1086  tools::Long mnRowOffset;
1087  sc::ColumnBlockPosition maDestBlockPos;
1088  sc::ColumnBlockPosition* mpDestBlockPos; // to save it for next iteration.
1089  svl::SharedStringPool* mpSharedStringPool;
1090 
1091  void insertRefCell(SCROW nSrcRow, SCROW nDestRow)
1092  {
1093  ScAddress aSrcPos(mnSrcCol, nSrcRow, mnSrcTab);
1094  ScAddress aDestPos(mnCol, nDestRow, mnTab);
1095  ScSingleRefData aRef;
1096  aRef.InitAddress(aSrcPos);
1097  aRef.SetFlag3D(true);
1098 
1099  ScTokenArray aArr(*mrCxt.getDestDoc());
1100  aArr.AddSingleReference(aRef);
1101 
1102  mrDestCol.SetFormulaCell(
1103  maDestBlockPos, nDestRow, new ScFormulaCell(mrDestCol.GetDoc(), aDestPos, aArr));
1104  }
1105 
1106  void duplicateNotes(SCROW nStartRow, size_t nDataSize, bool bCloneCaption )
1107  {
1108  mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestBlockPos, bCloneCaption, mnRowOffset);
1109  }
1110 
1111 public:
1112  CopyCellsFromClipHandler(sc::CopyFromClipContext& rCxt, ScColumn& rSrcCol, ScColumn& rDestCol, SCTAB nDestTab, SCCOL nDestCol, tools::Long nRowOffset, svl::SharedStringPool* pSharedStringPool) :
1113  mrCxt(rCxt),
1114  mrSrcCol(rSrcCol),
1115  mrDestCol(rDestCol),
1116  mnTab(nDestTab),
1117  mnCol(nDestCol),
1118  mnSrcTab(rSrcCol.GetTab()),
1119  mnSrcCol(rSrcCol.GetCol()),
1120  mnRowOffset(nRowOffset),
1121  mpDestBlockPos(mrCxt.getBlockPosition(nDestTab, nDestCol)),
1122  mpSharedStringPool(pSharedStringPool)
1123  {
1124  if (mpDestBlockPos)
1125  maDestBlockPos = *mpDestBlockPos;
1126  else
1127  mrDestCol.InitBlockPosition(maDestBlockPos);
1128  }
1129 
1130  ~CopyCellsFromClipHandler()
1131  {
1132  if (mpDestBlockPos)
1133  // Don't forget to save this to the context!
1134  *mpDestBlockPos = maDestBlockPos;
1135  }
1136 
1137  void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
1138  {
1139  SCROW nSrcRow1 = node.position + nOffset;
1140  bool bCopyCellNotes = mrCxt.isCloneNotes();
1141 
1142  InsertDeleteFlags nFlags = mrCxt.getInsertFlag();
1143 
1144  if (node.type == sc::element_type_empty)
1145  {
1146  if (bCopyCellNotes && !mrCxt.isSkipAttrForEmptyCells())
1147  {
1148  bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE;
1149  duplicateNotes(nSrcRow1, nDataSize, bCloneCaption );
1150  }
1151  return;
1152  }
1153 
1154  bool bNumeric = (nFlags & InsertDeleteFlags::VALUE) != InsertDeleteFlags::NONE;
1155  bool bDateTime = (nFlags & InsertDeleteFlags::DATETIME) != InsertDeleteFlags::NONE;
1156  bool bString = (nFlags & InsertDeleteFlags::STRING) != InsertDeleteFlags::NONE;
1157  bool bBoolean = (nFlags & InsertDeleteFlags::SPECIAL_BOOLEAN) != InsertDeleteFlags::NONE;
1158  bool bFormula = (nFlags & InsertDeleteFlags::FORMULA) != InsertDeleteFlags::NONE;
1159 
1160  bool bAsLink = mrCxt.isAsLink();
1161 
1162  switch (node.type)
1163  {
1165  {
1166  // We need to copy numeric cells individually because of date type check.
1167  sc::numeric_block::const_iterator it = sc::numeric_block::begin(*node.data);
1168  std::advance(it, nOffset);
1169  sc::numeric_block::const_iterator itEnd = it;
1170  std::advance(itEnd, nDataSize);
1171  for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
1172  {
1173  bool bCopy = mrCxt.isDateCell(mrSrcCol, nSrcRow) ? bDateTime : bNumeric;
1174  if (!bCopy)
1175  continue;
1176 
1177  if (bAsLink)
1178  insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
1179  else
1180  mrDestCol.SetValue(maDestBlockPos, nSrcRow + mnRowOffset, *it);
1181  }
1182  }
1183  break;
1185  {
1186  if (!bString)
1187  break;
1188 
1189  sc::string_block::const_iterator it = sc::string_block::begin(*node.data);
1190  std::advance(it, nOffset);
1191  sc::string_block::const_iterator itEnd = it;
1192  std::advance(itEnd, nDataSize);
1193  for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
1194  {
1195  if (bAsLink)
1196  insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
1197  else if (mpSharedStringPool)
1198  {
1199  // Re-intern the string if source is a different document.
1200  svl::SharedString aInterned = mpSharedStringPool->intern( (*it).getString());
1201  mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, aInterned);
1202  }
1203  else
1204  mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, *it);
1205  }
1206  }
1207  break;
1209  {
1210  if (!bString)
1211  break;
1212 
1213  sc::edittext_block::const_iterator it = sc::edittext_block::begin(*node.data);
1214  std::advance(it, nOffset);
1215  sc::edittext_block::const_iterator itEnd = it;
1216  std::advance(itEnd, nDataSize);
1217  for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
1218  {
1219 
1220  if (bAsLink)
1221  insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
1222  else
1223  mrDestCol.SetEditText(maDestBlockPos, nSrcRow + mnRowOffset, **it);
1224  }
1225  }
1226  break;
1228  {
1229  sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
1230  std::advance(it, nOffset);
1231  sc::formula_block::const_iterator itEnd = it;
1232  std::advance(itEnd, nDataSize);
1233  for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
1234  {
1235  ScFormulaCell& rSrcCell = **it;
1236  bool bForceFormula = false;
1237  if (bBoolean)
1238  {
1239  // See if the formula consists of =TRUE() or =FALSE().
1240  const ScTokenArray* pCode = rSrcCell.GetCode();
1241  if (pCode && pCode->GetLen() == 1)
1242  {
1243  const formula::FormulaToken* p = pCode->FirstToken();
1244  if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse)
1245  // This is a boolean formula.
1246  bForceFormula = true;
1247  }
1248  }
1249 
1250  ScAddress aDestPos(mnCol, nSrcRow + mnRowOffset, mnTab);
1251  if (bFormula || bForceFormula)
1252  {
1253  if (bAsLink)
1254  insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
1255  else
1256  {
1257  mrDestCol.SetFormulaCell(
1258  maDestBlockPos, nSrcRow + mnRowOffset,
1259  new ScFormulaCell(rSrcCell, mrDestCol.GetDoc(), aDestPos),
1261  rSrcCell.NeedsNumberFormat());
1262  }
1263  }
1264  else if (bNumeric || bDateTime || bString)
1265  {
1266  // Always just copy the original row to the Undo Document;
1267  // do not create Value/string cells from formulas
1268 
1269  FormulaError nErr = rSrcCell.GetErrCode();
1270  if (nErr != FormulaError::NONE)
1271  {
1272  // error codes are cloned with values
1273  if (bNumeric)
1274  {
1275  if (bAsLink)
1276  insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
1277  else
1278  {
1279  ScFormulaCell* pErrCell = new ScFormulaCell(mrDestCol.GetDoc(), aDestPos);
1280  pErrCell->SetErrCode(nErr);
1281  mrDestCol.SetFormulaCell(
1282  maDestBlockPos, nSrcRow + mnRowOffset, pErrCell);
1283  }
1284  }
1285  }
1286  else if (rSrcCell.IsEmptyDisplayedAsString())
1287  {
1288  // Empty stays empty and doesn't become 0.
1289  continue;
1290  }
1291  else if (rSrcCell.IsValue())
1292  {
1293  bool bCopy = mrCxt.isDateCell(mrSrcCol, nSrcRow) ? bDateTime : bNumeric;
1294  if (!bCopy)
1295  continue;
1296 
1297  if (bAsLink)
1298  insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
1299  else
1300  mrDestCol.SetValue(maDestBlockPos, nSrcRow + mnRowOffset, rSrcCell.GetValue());
1301  }
1302  else if (bString)
1303  {
1304  svl::SharedString aStr = rSrcCell.GetString();
1305  if (aStr.isEmpty())
1306  // do not clone empty string
1307  continue;
1308 
1309  if (bAsLink)
1310  insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
1311  else if (rSrcCell.IsMultilineResult())
1312  {
1313  // Clone as an edit text object.
1314  ScFieldEditEngine& rEngine = mrDestCol.GetDoc().GetEditEngine();
1315  rEngine.SetTextCurrentDefaults(aStr.getString());
1316  mrDestCol.SetEditText(maDestBlockPos, nSrcRow + mnRowOffset, rEngine.CreateTextObject());
1317  }
1318  else if (mpSharedStringPool)
1319  {
1320  // Re-intern the string if source is a different document.
1321  svl::SharedString aInterned = mpSharedStringPool->intern( aStr.getString());
1322  mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, aInterned);
1323  }
1324  else
1325  {
1326  mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, aStr);
1327  }
1328  }
1329  }
1330  }
1331  }
1332  break;
1333  default:
1334  ;
1335  }
1336  if (bCopyCellNotes)
1337  {
1338  bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE;
1339  duplicateNotes(nSrcRow1, nDataSize, bCloneCaption );
1340  }
1341  }
1342 };
1343 
1344 class CopyTextAttrsFromClipHandler
1345 {
1346  sc::CellTextAttrStoreType& mrAttrs;
1347  size_t mnDelta;
1348  sc::ColumnBlockPosition maDestBlockPos;
1349  sc::ColumnBlockPosition* mpDestBlockPos; // to save it for next iteration.
1350 
1351 public:
1352  CopyTextAttrsFromClipHandler( sc::CopyFromClipContext& rCxt, sc::CellTextAttrStoreType& rAttrs,
1353  ScColumn& rDestCol, SCTAB nDestTab, SCCOL nDestCol, size_t nDelta ) :
1354  mrAttrs(rAttrs),
1355  mnDelta(nDelta),
1356  mpDestBlockPos(rCxt.getBlockPosition(nDestTab, nDestCol))
1357  {
1358  if (mpDestBlockPos)
1359  maDestBlockPos = *mpDestBlockPos;
1360  else
1361  rDestCol.InitBlockPosition(maDestBlockPos);
1362  }
1363 
1364  ~CopyTextAttrsFromClipHandler()
1365  {
1366  if (mpDestBlockPos)
1367  // Don't forget to save this to the context!
1368  *mpDestBlockPos = maDestBlockPos;
1369  }
1370 
1371  void operator() ( const sc::CellTextAttrStoreType::value_type& aNode, size_t nOffset, size_t nDataSize )
1372  {
1373  if (aNode.type != sc::element_type_celltextattr)
1374  return;
1375 
1376  sc::celltextattr_block::const_iterator it = sc::celltextattr_block::begin(*aNode.data);
1377  std::advance(it, nOffset);
1378  sc::celltextattr_block::const_iterator itEnd = it;
1379  std::advance(itEnd, nDataSize);
1380 
1381  size_t nPos = aNode.position + nOffset + mnDelta;
1382  maDestBlockPos.miCellTextAttrPos = mrAttrs.set(maDestBlockPos.miCellTextAttrPos, nPos, it, itEnd);
1383  }
1384 };
1385 
1386 }
1387 
1388 // rColumn = source
1389 // nRow1, nRow2 = target position
1390 
1392  sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, tools::Long nDy, ScColumn& rColumn )
1393 {
1395  {
1396  if (rCxt.isSkipAttrForEmptyCells())
1397  {
1398  // copy only attributes for non-empty cells between nRow1-nDy and nRow2-nDy.
1399  sc::SingleColumnSpanSet aSpanSet(GetDoc().GetSheetLimits());
1400  aSpanSet.scan(rColumn, nRow1-nDy, nRow2-nDy);
1402  aSpanSet.getSpans(aSpans);
1403  std::for_each(
1404  aSpans.begin(), aSpans.end(), CopyAttrArrayByRange(*rColumn.pAttrArray, *pAttrArray, nDy));
1405  }
1406  else
1407  rColumn.pAttrArray->CopyAreaSafe( nRow1, nRow2, nDy, *pAttrArray );
1408  }
1410  return;
1411 
1412  ScDocument& rDocument = GetDoc();
1413  if (rCxt.isAsLink() && rCxt.getInsertFlag() == InsertDeleteFlags::ALL)
1414  {
1415  // We also reference empty cells for "ALL"
1416  // InsertDeleteFlags::ALL must always contain more flags when compared to "Insert contents" as
1417  // contents can be selected one by one!
1418 
1419  ScAddress aDestPos( nCol, 0, nTab ); // Adapt Row
1420 
1421  // Create reference (Source Position)
1422  ScSingleRefData aRef;
1423  aRef.InitFlags(); // -> All absolute
1424  aRef.SetAbsCol(rColumn.nCol);
1425  aRef.SetAbsTab(rColumn.nTab);
1426  aRef.SetFlag3D(true);
1427 
1428  for (SCROW nDestRow = nRow1; nDestRow <= nRow2; nDestRow++)
1429  {
1430  aRef.SetAbsRow(nDestRow - nDy); // Source row
1431  aDestPos.SetRow( nDestRow );
1432 
1433  ScTokenArray aArr(GetDoc());
1434  aArr.AddSingleReference( aRef );
1435  SetFormulaCell(nDestRow, new ScFormulaCell(rDocument, aDestPos, aArr));
1436  }
1437 
1438  // Don't forget to copy the cell text attributes.
1439  CopyTextAttrsFromClipHandler aFunc(rCxt, maCellTextAttrs, *this, nTab, nCol, nDy);
1440  sc::ParseBlock(rColumn.maCellTextAttrs.begin(), rColumn.maCellTextAttrs, aFunc, nRow1-nDy, nRow2-nDy);
1441 
1442  return;
1443  }
1444 
1445  // Compare the ScDocumentPool* to determine if we are copying within the
1446  // same document. If not, re-intern shared strings.
1447  svl::SharedStringPool* pSharedStringPool = (rColumn.GetDoc().GetPool() != rDocument.GetPool()) ?
1448  &rDocument.GetSharedStringPool() : nullptr;
1449 
1450  // nRow1 to nRow2 is for destination (this) column. Subtract nDy to get the source range.
1451  // Copy all cells in the source column (rColumn) from nRow1-nDy to nRow2-nDy to this column.
1452  {
1453  CopyCellsFromClipHandler aFunc(rCxt, rColumn, *this, nTab, nCol, nDy, pSharedStringPool);
1454  sc::ParseBlock(rColumn.maCells.begin(), rColumn.maCells, aFunc, nRow1-nDy, nRow2-nDy);
1455  }
1456 
1457  {
1458  // Don't forget to copy the cell text attributes.
1459  CopyTextAttrsFromClipHandler aFunc(rCxt, maCellTextAttrs, *this, nTab, nCol, nDy);
1460  sc::ParseBlock(rColumn.maCellTextAttrs.begin(), rColumn.maCellTextAttrs, aFunc, nRow1-nDy, nRow2-nDy);
1461  }
1462 }
1463 
1465  sc::MixDocContext& rCxt, const ScMarkData& rMark, ScPasteFunc nFunction,
1466  bool bSkipEmpty, const ScColumn& rSrcCol )
1467 {
1468  SCROW nRow1, nRow2;
1469 
1470  if (rMark.IsMultiMarked())
1471  {
1472  ScMultiSelIter aIter( rMark.GetMultiSelData(), nCol );
1473  while (aIter.Next( nRow1, nRow2 ))
1474  MixData(rCxt, nRow1, nRow2, nFunction, bSkipEmpty, rSrcCol);
1475  }
1476 }
1477 
1478 namespace {
1479 
1480 // Result in rVal1
1481 bool lcl_DoFunction( double& rVal1, double nVal2, ScPasteFunc nFunction )
1482 {
1483  bool bOk = false;
1484  switch (nFunction)
1485  {
1486  case ScPasteFunc::ADD:
1487  bOk = SubTotal::SafePlus( rVal1, nVal2 );
1488  break;
1489  case ScPasteFunc::SUB:
1490  nVal2 = -nVal2; // FIXME: Can we do this always without error?
1491  bOk = SubTotal::SafePlus( rVal1, nVal2 );
1492  break;
1493  case ScPasteFunc::MUL:
1494  bOk = SubTotal::SafeMult( rVal1, nVal2 );
1495  break;
1496  case ScPasteFunc::DIV:
1497  bOk = SubTotal::SafeDiv( rVal1, nVal2 );
1498  break;
1499  default: break;
1500  }
1501  return bOk;
1502 }
1503 
1504 void lcl_AddCode( ScTokenArray& rArr, const ScFormulaCell* pCell )
1505 {
1506  rArr.AddOpCode(ocOpen);
1507 
1508  const ScTokenArray* pCode = pCell->GetCode();
1509  if (pCode)
1510  {
1511  FormulaTokenArrayPlainIterator aIter(*pCode);
1512  const formula::FormulaToken* pToken = aIter.First();
1513  while (pToken)
1514  {
1515  rArr.AddToken( *pToken );
1516  pToken = aIter.Next();
1517  }
1518  }
1519 
1520  rArr.AddOpCode(ocClose);
1521 }
1522 
1523 class MixDataHandler
1524 {
1525  ScColumn& mrDestColumn;
1526  sc::ColumnBlockPosition& mrBlockPos;
1527 
1528  sc::CellStoreType maNewCells;
1529  sc::CellStoreType::iterator miNewCellsPos;
1530 
1531  size_t mnRowOffset;
1532  ScPasteFunc mnFunction;
1533 
1534  bool mbSkipEmpty;
1535 
1536  void doFunction( size_t nDestRow, double fVal1, double fVal2 )
1537  {
1538  bool bOk = lcl_DoFunction(fVal1, fVal2, mnFunction);
1539 
1540  if (bOk)
1541  miNewCellsPos = maNewCells.set(miNewCellsPos, nDestRow-mnRowOffset, fVal1);
1542  else
1543  {
1544  ScAddress aPos(mrDestColumn.GetCol(), nDestRow, mrDestColumn.GetTab());
1545 
1546  ScFormulaCell* pFC = new ScFormulaCell(mrDestColumn.GetDoc(), aPos);
1547  pFC->SetErrCode(FormulaError::NoValue);
1548 
1549  miNewCellsPos = maNewCells.set(miNewCellsPos, nDestRow-mnRowOffset, pFC);
1550  }
1551  }
1552 
1553 public:
1554  MixDataHandler(
1555  sc::ColumnBlockPosition& rBlockPos,
1556  ScColumn& rDestColumn,
1557  SCROW nRow1, SCROW nRow2,
1558  ScPasteFunc nFunction, bool bSkipEmpty) :
1559  mrDestColumn(rDestColumn),
1560  mrBlockPos(rBlockPos),
1561  maNewCells(nRow2 - nRow1 + 1),
1562  miNewCellsPos(maNewCells.begin()),
1563  mnRowOffset(nRow1),
1564  mnFunction(nFunction),
1565  mbSkipEmpty(bSkipEmpty)
1566  {
1567  }
1568 
1569  void operator() (size_t nRow, double f)
1570  {
1571  sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nRow);
1572  mrBlockPos.miCellPos = aPos.first;
1573  switch (aPos.first->type)
1574  {
1577  {
1578  double fSrcVal = 0.0;
1579  if (aPos.first->type == sc::element_type_numeric)
1580  fSrcVal = sc::numeric_block::at(*aPos.first->data, aPos.second);
1581 
1582  // Both src and dest are of numeric type.
1583  doFunction(nRow, f, fSrcVal);
1584  }
1585  break;
1587  {
1588  // Combination of value and at least one formula -> Create formula
1589  ScTokenArray aArr(mrDestColumn.GetDoc());
1590 
1591  // First row
1592  aArr.AddDouble(f);
1593 
1594  // Operator
1595  OpCode eOp = ocAdd;
1596  switch (mnFunction)
1597  {
1598  case ScPasteFunc::ADD: eOp = ocAdd; break;
1599  case ScPasteFunc::SUB: eOp = ocSub; break;
1600  case ScPasteFunc::MUL: eOp = ocMul; break;
1601  case ScPasteFunc::DIV: eOp = ocDiv; break;
1602  default: break;
1603  }
1604  aArr.AddOpCode(eOp); // Function
1605 
1606  // Second row
1607  ScFormulaCell* pDest = sc::formula_block::at(*aPos.first->data, aPos.second);
1608  lcl_AddCode(aArr, pDest);
1609 
1610  miNewCellsPos = maNewCells.set(
1611  miNewCellsPos, nRow-mnRowOffset,
1612  new ScFormulaCell(
1613  mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), aArr));
1614  }
1615  break;
1618  {
1619  // Destination cell is not a number. Just take the source cell.
1620  miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, f);
1621  }
1622  break;
1623  default:
1624  ;
1625  }
1626  }
1627 
1628  void operator() (size_t nRow, const svl::SharedString& rStr)
1629  {
1630  miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, rStr);
1631  }
1632 
1633  void operator() (size_t nRow, const EditTextObject* p)
1634  {
1635  miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, p->Clone().release());
1636  }
1637 
1638  void operator() (size_t nRow, const ScFormulaCell* p)
1639  {
1640  sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nRow);
1641  mrBlockPos.miCellPos = aPos.first;
1642  switch (aPos.first->type)
1643  {
1645  {
1646  // Source is formula, and dest is value.
1647  ScTokenArray aArr(mrDestColumn.GetDoc());
1648 
1649  // First row
1650  lcl_AddCode(aArr, p);
1651 
1652  // Operator
1653  OpCode eOp = ocAdd;
1654  switch (mnFunction)
1655  {
1656  case ScPasteFunc::ADD: eOp = ocAdd; break;
1657  case ScPasteFunc::SUB: eOp = ocSub; break;
1658  case ScPasteFunc::MUL: eOp = ocMul; break;
1659  case ScPasteFunc::DIV: eOp = ocDiv; break;
1660  default: break;
1661  }
1662  aArr.AddOpCode(eOp); // Function
1663 
1664  // Second row
1665  aArr.AddDouble(sc::numeric_block::at(*aPos.first->data, aPos.second));
1666 
1667  miNewCellsPos = maNewCells.set(
1668  miNewCellsPos, nRow-mnRowOffset,
1669  new ScFormulaCell(
1670  mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), aArr));
1671  }
1672  break;
1674  {
1675  // Both are formulas.
1676  ScTokenArray aArr(mrDestColumn.GetDoc());
1677 
1678  // First row
1679  lcl_AddCode(aArr, p);
1680 
1681  // Operator
1682  OpCode eOp = ocAdd;
1683  switch (mnFunction)
1684  {
1685  case ScPasteFunc::ADD: eOp = ocAdd; break;
1686  case ScPasteFunc::SUB: eOp = ocSub; break;
1687  case ScPasteFunc::MUL: eOp = ocMul; break;
1688  case ScPasteFunc::DIV: eOp = ocDiv; break;
1689  default: break;
1690  }
1691  aArr.AddOpCode(eOp); // Function
1692 
1693  // Second row
1694  ScFormulaCell* pDest = sc::formula_block::at(*aPos.first->data, aPos.second);
1695  lcl_AddCode(aArr, pDest);
1696 
1697  miNewCellsPos = maNewCells.set(
1698  miNewCellsPos, nRow-mnRowOffset,
1699  new ScFormulaCell(
1700  mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), aArr));
1701  }
1702  break;
1706  {
1707  // Destination cell is not a number. Just take the source cell.
1708  ScAddress aDestPos(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab());
1709  miNewCellsPos = maNewCells.set(
1710  miNewCellsPos, nRow-mnRowOffset, new ScFormulaCell(*p, mrDestColumn.GetDoc(), aDestPos));
1711  }
1712  break;
1713  default:
1714  ;
1715  }
1716  }
1717 
1721  void operator() (mdds::mtv::element_t, size_t nTopRow, size_t nDataSize)
1722  {
1723  if (mbSkipEmpty)
1724  return;
1725 
1726  // Source cells are empty. Treat them as if they have a value of 0.0.
1727  for (size_t i = 0; i < nDataSize; ++i)
1728  {
1729  size_t nDestRow = nTopRow + i;
1730  sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nDestRow);
1731  mrBlockPos.miCellPos = aPos.first;
1732  switch (aPos.first->type)
1733  {
1735  {
1736  double fVal2 = sc::numeric_block::at(*aPos.first->data, aPos.second);
1737  doFunction(nDestRow, 0.0, fVal2);
1738  }
1739  break;
1741  {
1742  const svl::SharedString& aVal = sc::string_block::at(*aPos.first->data, aPos.second);
1743  miNewCellsPos = maNewCells.set(
1744  miNewCellsPos, nDestRow-mnRowOffset, aVal);
1745  }
1746  break;
1748  {
1749  EditTextObject* pObj = sc::edittext_block::at(*aPos.first->data, aPos.second);
1750  miNewCellsPos = maNewCells.set(
1751  miNewCellsPos, nDestRow-mnRowOffset, pObj->Clone().release());
1752  }
1753  break;
1755  {
1756  ScTokenArray aArr(mrDestColumn.GetDoc());
1757 
1758  // First row
1759  ScFormulaCell* pSrc = sc::formula_block::at(*aPos.first->data, aPos.second);
1760  lcl_AddCode( aArr, pSrc);
1761 
1762  // Operator
1763  OpCode eOp = ocAdd;
1764  switch (mnFunction)
1765  {
1766  case ScPasteFunc::ADD: eOp = ocAdd; break;
1767  case ScPasteFunc::SUB: eOp = ocSub; break;
1768  case ScPasteFunc::MUL: eOp = ocMul; break;
1769  case ScPasteFunc::DIV: eOp = ocDiv; break;
1770  default: break;
1771  }
1772 
1773  aArr.AddOpCode(eOp); // Function
1774  aArr.AddDouble(0.0);
1775 
1776  miNewCellsPos = maNewCells.set(
1777  miNewCellsPos, nDestRow-mnRowOffset,
1778  new ScFormulaCell(
1779  mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nDestRow, mrDestColumn.GetTab()), aArr));
1780  }
1781  break;
1782  default:
1783  ;
1784  }
1785  }
1786  }
1787 
1791  void commit()
1792  {
1793  sc::CellStoreType& rDestCells = mrDestColumn.GetCellStore();
1794 
1795  // Stop all formula cells in the destination range first.
1796  sc::CellStoreType::position_type aPos = rDestCells.position(mrBlockPos.miCellPos, mnRowOffset);
1797  mrDestColumn.DetachFormulaCells(aPos, maNewCells.size(), nullptr);
1798 
1799  // Move the new cells to the destination range.
1800  sc::CellStoreType::iterator& itDestPos = mrBlockPos.miCellPos;
1801  sc::CellTextAttrStoreType::iterator& itDestAttrPos = mrBlockPos.miCellTextAttrPos;
1802 
1803  for (const auto& rNewCell : maNewCells)
1804  {
1805  bool bHasContent = true;
1806  size_t nDestRow = mnRowOffset + rNewCell.position;
1807 
1808  switch (rNewCell.type)
1809  {
1811  {
1812  sc::numeric_block::iterator itData = sc::numeric_block::begin(*rNewCell.data);
1813  sc::numeric_block::iterator itDataEnd = sc::numeric_block::end(*rNewCell.data);
1814  itDestPos = mrDestColumn.GetCellStore().set(itDestPos, nDestRow, itData, itDataEnd);
1815  }
1816  break;
1818  {
1819  sc::string_block::iterator itData = sc::string_block::begin(*rNewCell.data);
1820  sc::string_block::iterator itDataEnd = sc::string_block::end(*rNewCell.data);
1821  itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
1822  }
1823  break;
1825  {
1826  sc::edittext_block::iterator itData = sc::edittext_block::begin(*rNewCell.data);
1827  sc::edittext_block::iterator itDataEnd = sc::edittext_block::end(*rNewCell.data);
1828  itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
1829  }
1830  break;
1832  {
1833  sc::formula_block::iterator itData = sc::formula_block::begin(*rNewCell.data);
1834  sc::formula_block::iterator itDataEnd = sc::formula_block::end(*rNewCell.data);
1835 
1836  // Group new formula cells before inserting them.
1837  sc::SharedFormulaUtil::groupFormulaCells(itData, itDataEnd);
1838 
1839  // Insert the formula cells to the column.
1840  itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
1841 
1842  // Merge with the previous formula group (if any).
1843  aPos = rDestCells.position(itDestPos, nDestRow);
1845 
1846  // Merge with the next formula group (if any).
1847  size_t nNextRow = nDestRow + rNewCell.size;
1848  if (mrDestColumn.GetDoc().ValidRow(nNextRow))
1849  {
1850  aPos = rDestCells.position(aPos.first, nNextRow);
1852  }
1853 
1854  // Start listening on cells to get them updated by changes of referenced cells
1855  std::vector<SCROW> aNewSharedRows;
1856  aPos = rDestCells.position(itDestPos, nDestRow);
1857  size_t nFormulaCells = std::distance(itData, itDataEnd);
1858  mrDestColumn.AttachNewFormulaCells(aPos, nFormulaCells, aNewSharedRows);
1859  }
1860  break;
1862  {
1863  itDestPos = rDestCells.set_empty(itDestPos, nDestRow, nDestRow+rNewCell.size-1);
1864  bHasContent = false;
1865  }
1866  break;
1867  default:
1868  ;
1869  }
1870 
1871  sc::CellTextAttrStoreType& rDestAttrs = mrDestColumn.GetCellAttrStore();
1872  if (bHasContent)
1873  {
1874  std::vector<sc::CellTextAttr> aAttrs(rNewCell.size, sc::CellTextAttr());
1875  itDestAttrPos = rDestAttrs.set(itDestAttrPos, nDestRow, aAttrs.begin(), aAttrs.end());
1876  }
1877  else
1878  itDestAttrPos = rDestAttrs.set_empty(itDestAttrPos, nDestRow, nDestRow+rNewCell.size-1);
1879  }
1880 
1881  maNewCells.release();
1882  }
1883 };
1884 
1885 }
1886 
1888  sc::MixDocContext& rCxt, SCROW nRow1, SCROW nRow2, ScPasteFunc nFunction,
1889  bool bSkipEmpty, const ScColumn& rSrcCol )
1890 {
1891  // destination (this column) block position.
1892 
1893  sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
1894  if (!p)
1895  return;
1896 
1897  MixDataHandler aFunc(*p, *this, nRow1, nRow2, nFunction, bSkipEmpty);
1898  sc::ParseAll(rSrcCol.maCells.begin(), rSrcCol.maCells, nRow1, nRow2, aFunc, aFunc);
1899 
1900  aFunc.commit();
1901  CellStorageModified();
1902 }
1903 
1904 std::unique_ptr<ScAttrIterator> ScColumn::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const
1905 {
1906  return std::make_unique<ScAttrIterator>( pAttrArray.get(), nStartRow, nEndRow, GetDoc().GetDefPattern() );
1907 }
1908 
1909 namespace {
1910 
1911 class StartListenersHandler
1912 {
1914  bool mbAllListeners;
1915 
1916 public:
1917  StartListenersHandler( sc::StartListeningContext& rCxt, bool bAllListeners ) :
1918  mpCxt(&rCxt), mbAllListeners(bAllListeners) {}
1919 
1920  void operator() ( sc::CellStoreType::value_type& aBlk )
1921  {
1922  if (aBlk.type != sc::element_type_formula)
1923  return;
1924 
1925  ScFormulaCell** pp = &sc::formula_block::at(*aBlk.data, 0);
1926  ScFormulaCell** ppEnd = pp + aBlk.size;
1927 
1928  for (; pp != ppEnd; ++pp)
1929  {
1930  ScFormulaCell& rFC = **pp;
1931  if (!mbAllListeners && !rFC.NeedsListening())
1932  continue;
1933 
1934  if (rFC.IsSharedTop())
1935  {
1937  pp += rFC.GetSharedLength() - 1; // Move to the last cell in the group.
1938  }
1939  else
1940  rFC.StartListeningTo(*mpCxt);
1941  }
1942  }
1943 };
1944 
1945 }
1946 
1948 {
1949  std::for_each(maCells.begin(), maCells.end(), StartListenersHandler(rCxt, bAll));
1950 }
1951 
1952 namespace {
1953 
1954 void applyTextNumFormat( ScColumn& rCol, SCROW nRow, SvNumberFormatter* pFormatter )
1955 {
1956  sal_uInt32 nFormat = pFormatter->GetStandardFormat(SvNumFormatType::TEXT);
1957  ScPatternAttr aNewAttrs(rCol.GetDoc().GetPool());
1958  SfxItemSet& rSet = aNewAttrs.GetItemSet();
1959  rSet.Put(SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat));
1960  rCol.ApplyPattern(nRow, aNewAttrs);
1961 }
1962 
1963 }
1964 
1966  ScCellValue& rCell, SCROW nRow, SCTAB nTabP, const OUString& rString,
1968  const ScSetStringParam* pParam )
1969 {
1970  if (rString.isEmpty())
1971  return false;
1972 
1973  bool bNumFmtSet = false;
1974 
1975  ScSetStringParam aParam;
1976 
1977  if (pParam)
1978  aParam = *pParam;
1979 
1980  sal_uInt32 nIndex = 0;
1981  sal_uInt32 nOldIndex = 0;
1982  SvNumFormatType eNumFormatType = SvNumFormatType::ALL;
1983  if (!aParam.mpNumFormatter)
1984  aParam.mpNumFormatter = GetDoc().GetFormatTable();
1985 
1986  sal_Unicode cFirstChar = 0; // Text
1987  nIndex = nOldIndex = GetNumberFormat( GetDoc().GetNonThreadedContext(), nRow );
1988  if ( rString.getLength() > 1 )
1989  {
1990  eNumFormatType = aParam.mpNumFormatter->GetType(nIndex);
1991  if ( eNumFormatType != SvNumFormatType::TEXT )
1992  cFirstChar = rString[0];
1993  }
1994 
1995  svl::SharedStringPool& rPool = GetDoc().GetSharedStringPool();
1996 
1997  if ( cFirstChar == '=' )
1998  {
1999  if ( rString.getLength() == 1 ) // = Text
2000  {
2001  rCell.set(rPool.intern(rString));
2002  }
2003  else if (aParam.meSetTextNumFormat == ScSetStringParam::Always)
2004  {
2005  // Set the cell format type to Text.
2006  applyTextNumFormat(*this, nRow, aParam.mpNumFormatter);
2007  rCell.set(rPool.intern(rString));
2008  }
2009  else // = Formula
2010  {
2011  ScFormulaCell* pFormulaCell = new ScFormulaCell(
2012  GetDoc(), ScAddress(nCol, nRow, nTabP), rString,
2015  if (aParam.mbCheckLinkFormula)
2016  GetDoc().CheckLinkFormulaNeedingCheck( *pFormulaCell->GetCode());
2017  rCell.set( pFormulaCell);
2018  }
2019  }
2020  else if ( cFirstChar == '\'') // 'Text
2021  {
2022  bool bNumeric = false;
2023  if (aParam.mbHandleApostrophe)
2024  {
2025  // Cell format is not 'Text', and the first char
2026  // is an apostrophe. Check if the input is considered a number.
2027  OUString aTest = rString.copy(1);
2028  double fTest;
2029  bNumeric = aParam.mpNumFormatter->IsNumberFormat(aTest, nIndex, fTest);
2030  if (bNumeric)
2031  // This is a number. Strip out the first char.
2032  rCell.set(rPool.intern(aTest));
2033  }
2034  if (!bNumeric)
2035  // This is normal text. Take it as-is.
2036  rCell.set(rPool.intern(rString));
2037  }
2038  else
2039  {
2040  double nVal;
2041 
2042  do
2043  {
2044  if (aParam.mbDetectNumberFormat)
2045  {
2046  // Editing a date prefers the format's locale's edit date
2047  // format's date acceptance patterns and YMD order.
2048  /* TODO: this could be determined already far above when
2049  * starting to edit a date "cell" and passed down. A problem
2050  * could also be if a new date was typed over or written by a
2051  * macro assuming the current locale if that conflicts somehow.
2052  * You can't have everything. See tdf#116579 and tdf#125109. */
2053  if (eNumFormatType == SvNumFormatType::ALL)
2054  eNumFormatType = aParam.mpNumFormatter->GetType(nIndex);
2055  bool bForceFormatDate = (eNumFormatType == SvNumFormatType::DATE
2056  || eNumFormatType == SvNumFormatType::DATETIME);
2057  const SvNumberformat* pOldFormat = nullptr;
2059  if (bForceFormatDate)
2060  {
2061  ScRefCellValue aCell = GetCellValue(nRow);
2062  if (aCell.meType == CELLTYPE_VALUE)
2063  {
2064  // Only for an actual date (serial number), not an
2065  // arbitrary string or formula or empty cell.
2066  // Also ensure the edit date format's pattern is used,
2067  // not the display format's.
2068  pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex);
2069  if (!pOldFormat)
2070  bForceFormatDate = false;
2071  else
2072  {
2073  nIndex = aParam.mpNumFormatter->GetEditFormat( aCell.getValue(), nOldIndex, eNumFormatType,
2074  pOldFormat->GetLanguage(), pOldFormat);
2075  eEvalDateFormat = aParam.mpNumFormatter->GetEvalDateFormat();
2077  }
2078  }
2079  else
2080  {
2081  bForceFormatDate = false;
2082  }
2083  }
2084 
2085  const bool bIsNumberFormat = aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal);
2086 
2087  if (bForceFormatDate)
2088  aParam.mpNumFormatter->SetEvalDateFormat( eEvalDateFormat);
2089 
2090  if (!bIsNumberFormat)
2091  break;
2092 
2093  // If we have bForceFormatDate, the pOldFormat was/is of
2094  // nOldIndex date(+time) type already, if detected type is
2095  // compatible keep the original format.
2096  if (bForceFormatDate && SvNumberFormatter::IsCompatible(
2097  eNumFormatType, aParam.mpNumFormatter->GetType( nIndex)))
2098  {
2099  nIndex = nOldIndex;
2100  }
2101  else
2102  {
2103  // convert back to the original language if a built-in format was detected
2104  if (!pOldFormat)
2105  pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex );
2106  if (pOldFormat)
2108  nIndex, pOldFormat->GetLanguage());
2109  }
2110 
2111  rCell.set(nVal);
2112  if ( nIndex != nOldIndex)
2113  {
2114  // #i22345# New behavior: Apply the detected number format only if
2115  // the old one was the default number, date, time or boolean format.
2116  // Exception: If the new format is boolean, always apply it.
2117 
2118  bool bOverwrite = false;
2119  if ( pOldFormat )
2120  {
2121  SvNumFormatType nOldType = pOldFormat->GetMaskedType();
2122  if ( nOldType == SvNumFormatType::NUMBER || nOldType == SvNumFormatType::DATE ||
2123  nOldType == SvNumFormatType::TIME || nOldType == SvNumFormatType::LOGICAL )
2124  {
2125  if ( nOldIndex == aParam.mpNumFormatter->GetStandardFormat(
2126  nOldType, pOldFormat->GetLanguage() ) )
2127  {
2128  bOverwrite = true; // default of these types can be overwritten
2129  }
2130  }
2131  }
2132  if ( !bOverwrite && aParam.mpNumFormatter->GetType( nIndex ) == SvNumFormatType::LOGICAL )
2133  {
2134  bOverwrite = true; // overwrite anything if boolean was detected
2135  }
2136 
2137  if ( bOverwrite )
2138  {
2139  ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT,
2140  nIndex) );
2141  bNumFmtSet = true;
2142  }
2143  }
2144  }
2145  else if (aParam.meSetTextNumFormat == ScSetStringParam::Never ||
2147  {
2148  // Only check if the string is a regular number.
2150  if (!pLocale)
2151  break;
2152 
2153  const LocaleDataItem2& aLocaleItem = pLocale->getLocaleItem();
2154  const OUString& rDecSep = aLocaleItem.decimalSeparator;
2155  const OUString& rGroupSep = aLocaleItem.thousandSeparator;
2156  const OUString& rDecSepAlt = aLocaleItem.decimalSeparatorAlternative;
2157  if (rDecSep.getLength() != 1 || rGroupSep.getLength() != 1 || rDecSepAlt.getLength() > 1)
2158  break;
2159 
2160  sal_Unicode dsep = rDecSep[0];
2161  sal_Unicode gsep = rGroupSep[0];
2162  sal_Unicode dsepa = rDecSepAlt.toChar();
2163 
2164  if (!ScStringUtil::parseSimpleNumber(rString, dsep, gsep, dsepa, nVal))
2165  break;
2166 
2167  rCell.set(nVal);
2168  }
2169  }
2170  while (false);
2171 
2172  if (rCell.meType == CELLTYPE_NONE)
2173  {
2174  // If we reach here with ScSetStringParam::SpecialNumberOnly it
2175  // means a simple number was not detected above, so test for
2176  // special numbers. In any case ScSetStringParam::Always does not
2177  // mean always, but only always for content that could be any
2178  // numeric.
2181  aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal))
2182  {
2183  // Set the cell format type to Text.
2184  applyTextNumFormat(*this, nRow, aParam.mpNumFormatter);
2185  }
2186 
2187  rCell.set(rPool.intern(rString));
2188  }
2189  }
2190 
2191  return bNumFmtSet;
2192 }
2193 
2197 bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const OUString& rString,
2199  const ScSetStringParam* pParam )
2200 {
2201  if (!GetDoc().ValidRow(nRow))
2202  return false;
2203 
2204  ScCellValue aNewCell;
2205  bool bNumFmtSet = ParseString(aNewCell, nRow, nTabP, rString, eConv, pParam);
2206  if (pParam)
2207  aNewCell.release(*this, nRow, pParam->meStartListening);
2208  else
2209  aNewCell.release(*this, nRow);
2210 
2211  // Do not set Formats and Formulas here anymore!
2212  // These are queried during output
2213 
2214  return bNumFmtSet;
2215 }
2216 
2217 void ScColumn::SetEditText( SCROW nRow, std::unique_ptr<EditTextObject> pEditText )
2218 {
2219  pEditText->NormalizeString(GetDoc().GetSharedStringPool());
2220  std::vector<SCROW> aNewSharedRows;
2221  sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, false);
2222  maCells.set(it, nRow, pEditText.release());
2223  maCellTextAttrs.set(nRow, sc::CellTextAttr());
2224  CellStorageModified();
2225 
2226  StartListeningUnshared( aNewSharedRows);
2227 
2228  BroadcastNewCell(nRow);
2229 }
2230 
2231 void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, std::unique_ptr<EditTextObject> pEditText )
2232 {
2233  pEditText->NormalizeString(GetDoc().GetSharedStringPool());
2234  std::vector<SCROW> aNewSharedRows;
2235  rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows, false);
2236  rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pEditText.release());
2237  rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
2238  rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
2239 
2240  CellStorageModified();
2241 
2242  StartListeningUnshared( aNewSharedRows);
2243 
2244  BroadcastNewCell(nRow);
2245 }
2246 
2247 void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const EditTextObject& rEditText )
2248 {
2249  if (GetDoc().GetEditPool() == rEditText.GetPool())
2250  {
2251  SetEditText(rBlockPos, nRow, rEditText.Clone());
2252  return;
2253  }
2254 
2255  // rats, yet another "spool"
2256  // Sadly there is no other way to change the Pool than to
2257  // "spool" the Object through a corresponding Engine
2258  EditEngine& rEngine = GetDoc().GetEditEngine();
2259  rEngine.SetText(rEditText);
2260  SetEditText(rBlockPos, nRow, rEngine.CreateTextObject());
2261 }
2262 
2263 void ScColumn::SetEditText( SCROW nRow, const EditTextObject& rEditText, const SfxItemPool* pEditPool )
2264 {
2265  if (pEditPool && GetDoc().GetEditPool() == pEditPool)
2266  {
2267  SetEditText(nRow, rEditText.Clone());
2268  return;
2269  }
2270 
2271  // rats, yet another "spool"
2272  // Sadly there is no other way to change the Pool than to
2273  // "spool" the Object through a corresponding Engine
2274  EditEngine& rEngine = GetDoc().GetEditEngine();
2275  rEngine.SetText(rEditText);
2276  SetEditText(nRow, rEngine.CreateTextObject());
2277 }
2278 
2280 {
2281  ScAddress aPos(nCol, nRow, nTab);
2282 
2283  std::vector<SCROW> aNewSharedRows;
2284  sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, true);
2285  ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), aPos, rArray, eGram);
2286  sal_uInt32 nCellFormat = GetNumberFormat(GetDoc().GetNonThreadedContext(), nRow);
2287  if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
2288  pCell->SetNeedNumberFormat(true);
2289  it = maCells.set(it, nRow, pCell);
2290  maCellTextAttrs.set(nRow, sc::CellTextAttr());
2291 
2292  CellStorageModified();
2293 
2294  AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows);
2295 }
2296 
2297 void ScColumn::SetFormula( SCROW nRow, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram )
2298 {
2299  ScAddress aPos(nCol, nRow, nTab);
2300 
2301  std::vector<SCROW> aNewSharedRows;
2302  sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, true);
2303  ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), aPos, rFormula, eGram);
2304  sal_uInt32 nCellFormat = GetNumberFormat(GetDoc().GetNonThreadedContext(), nRow);
2305  if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
2306  pCell->SetNeedNumberFormat(true);
2307  it = maCells.set(it, nRow, pCell);
2308  maCellTextAttrs.set(nRow, sc::CellTextAttr());
2309 
2310  CellStorageModified();
2311 
2312  AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows);
2313 }
2314 
2316  SCROW nRow, ScFormulaCell* pCell, sc::StartListeningType eListenType,
2317  bool bInheritNumFormatIfNeeded )
2318 {
2319  std::vector<SCROW> aNewSharedRows;
2320  sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, true);
2321  sal_uInt32 nCellFormat = GetNumberFormat(GetDoc().GetNonThreadedContext(), nRow);
2322  if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && bInheritNumFormatIfNeeded )
2323  pCell->SetNeedNumberFormat(true);
2324  it = maCells.set(it, nRow, pCell);
2325  maCellTextAttrs.set(nRow, sc::CellTextAttr());
2326 
2327  CellStorageModified();
2328 
2329  AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows, true, eListenType);
2330 
2331  return pCell;
2332 }
2333 
2335  sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell,
2336  sc::StartListeningType eListenType,
2337  bool bInheritNumFormatIfNeeded )
2338 {
2339  std::vector<SCROW> aNewSharedRows;
2340  rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows, true);
2341  sal_uInt32 nCellFormat = GetNumberFormat(GetDoc().GetNonThreadedContext(), nRow);
2342  if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && bInheritNumFormatIfNeeded )
2343  pCell->SetNeedNumberFormat(true);
2344  rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pCell);
2345  rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
2346  rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
2347 
2348  CellStorageModified();
2349 
2350  AttachNewFormulaCell(rBlockPos.miCellPos, nRow, *pCell, aNewSharedRows, true, eListenType);
2351 }
2352 
2353 bool ScColumn::SetFormulaCells( SCROW nRow, std::vector<ScFormulaCell*>& rCells )
2354 {
2355  if (!GetDoc().ValidRow(nRow))
2356  return false;
2357 
2358  SCROW nEndRow = nRow + rCells.size() - 1;
2359  if (!GetDoc().ValidRow(nEndRow))
2360  return false;
2361 
2362  sc::CellStoreType::position_type aPos = maCells.position(nRow);
2363 
2364  // Detach all formula cells that will be overwritten.
2365  std::vector<SCROW> aNewSharedRows;
2366  DetachFormulaCells(aPos, rCells.size(), &aNewSharedRows);
2367 
2368  if (!GetDoc().IsClipOrUndo())
2369  {
2370  for (size_t i = 0, n = rCells.size(); i < n; ++i)
2371  {
2372  SCROW nThisRow = nRow + i;
2373  sal_uInt32 nFmt = GetNumberFormat(GetDoc().GetNonThreadedContext(), nThisRow);
2374  if ((nFmt % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
2375  rCells[i]->SetNeedNumberFormat(true);
2376  }
2377  }
2378 
2379  std::vector<sc::CellTextAttr> aDefaults(rCells.size(), sc::CellTextAttr());
2380  maCellTextAttrs.set(nRow, aDefaults.begin(), aDefaults.end());
2381 
2382  maCells.set(aPos.first, nRow, rCells.begin(), rCells.end());
2383 
2384  CellStorageModified();
2385 
2386  // Reget position_type as the type may have changed to formula, block and
2387  // block size changed, ...
2388  aPos = maCells.position(nRow);
2389  AttachNewFormulaCells(aPos, rCells.size(), aNewSharedRows);
2390 
2391  return true;
2392 }
2393 
2395 {
2396  sc::CellStoreType::const_position_type aPos = maCells.position(nRow);
2397  switch (aPos.first->type)
2398  {
2400  return sc::string_block::at(*aPos.first->data, aPos.second);
2402  {
2403  const EditTextObject* pObj = sc::edittext_block::at(*aPos.first->data, aPos.second);
2404  std::vector<svl::SharedString> aSSs = pObj->GetSharedStrings();
2405  if (aSSs.size() != 1)
2406  // We don't handle multiline content for now.
2407  return svl::SharedString();
2408 
2409  return aSSs[0];
2410  }
2411  break;
2412  default:
2413  ;
2414  }
2415  return svl::SharedString();
2416 }
2417 
2418 namespace {
2419 
2420 class FilterEntriesHandler
2421 {
2422  ScColumn& mrColumn;
2423  ScFilterEntries& mrFilterEntries;
2424 
2425  void processCell(const ScColumn& rColumn, SCROW nRow, ScRefCellValue& rCell)
2426  {
2427  SvNumberFormatter* pFormatter = mrColumn.GetDoc().GetFormatTable();
2428  OUString aStr;
2429  sal_uLong nFormat = mrColumn.GetNumberFormat(mrColumn.GetDoc().GetNonThreadedContext(), nRow);
2430  ScCellFormat::GetInputString(rCell, nFormat, aStr, *pFormatter, mrColumn.GetDoc(), mrColumn.HasFiltering());
2431 
2432  // Colors
2433  ScAddress aPos(rColumn.GetCol(), nRow, rColumn.GetTab());
2434 
2435  Color backgroundColor;
2436  bool bHasConditionalBackgroundColor = false;
2437 
2438  Color textColor;
2439  bool bHasConditionalTextColor = false;
2440  // Check text & background color from cond. formatting
2441  const ScPatternAttr* pPattern
2442  = mrColumn.GetDoc().GetPattern(aPos.Col(), aPos.Row(), aPos.Tab());
2443  if (pPattern)
2444  {
2445  if (!pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty())
2446  {
2447  const SfxItemSet* pCondSet
2448  = mrColumn.GetDoc().GetCondResult(aPos.Col(), aPos.Row(), aPos.Tab());
2449  const SvxColorItem* pColor = &pPattern->GetItem(ATTR_FONT_COLOR, pCondSet);
2450  textColor = pColor->GetValue();
2451  bHasConditionalTextColor = true;
2452 
2453  const SvxBrushItem* pBackgroundColor = &pPattern->GetItem(ATTR_BACKGROUND, pCondSet);
2454  backgroundColor = pBackgroundColor->GetColor();
2455  bHasConditionalBackgroundColor = true;
2456  }
2457  }
2458 
2459  if (!bHasConditionalTextColor)
2460  {
2461  const SvxColorItem* pColor = rColumn.GetDoc().GetAttr(aPos, ATTR_FONT_COLOR);
2462  textColor = pColor->GetValue();
2463  }
2464  mrFilterEntries.addTextColor(textColor);
2465 
2466  // Color scale needs a different handling
2467  ScConditionalFormat* pCondFormat
2468  = rColumn.GetDoc().GetCondFormat(aPos.Col(), aPos.Row(), aPos.Tab());
2469  if (pCondFormat)
2470  {
2471  for (size_t i = 0; i < pCondFormat->size(); i++)
2472  {
2473  auto aEntry = pCondFormat->GetEntry(i);
2474  if (aEntry->GetType() == ScFormatEntry::Type::Colorscale)
2475  {
2476  const ScColorScaleFormat* pColFormat
2477  = static_cast<const ScColorScaleFormat*>(aEntry);
2478  std::optional<Color> oColor = pColFormat->GetColor(aPos);
2479  if (oColor)
2480  {
2481  backgroundColor = *oColor;
2482  bHasConditionalBackgroundColor = true;
2483  }
2484  }
2485  }
2486  }
2487  if (!bHasConditionalBackgroundColor)
2488  {
2489  const SvxBrushItem* pBrush = rColumn.GetDoc().GetAttr(aPos, ATTR_BACKGROUND);
2490  backgroundColor = pBrush->GetColor();
2491  }
2492  mrFilterEntries.addBackgroundColor(backgroundColor);
2493 
2494  if (rCell.hasString())
2495  {
2496  mrFilterEntries.push_back(ScTypedStrData(aStr));
2497  return;
2498  }
2499 
2500  double fVal = 0.0;
2501 
2502  switch (rCell.meType)
2503  {
2504  case CELLTYPE_VALUE:
2505  fVal = rCell.mfValue;
2506  break;
2507 
2508  case CELLTYPE_FORMULA:
2509  {
2510  ScFormulaCell* pFC = rCell.mpFormula;
2511  FormulaError nErr = pFC->GetErrCode();
2512  if (nErr != FormulaError::NONE)
2513  {
2514  // Error cell is evaluated as string (for now).
2515  OUString aErr = ScGlobal::GetErrorString(nErr);
2516  if (!aErr.isEmpty())
2517  {
2518  mrFilterEntries.push_back(ScTypedStrData(aErr));
2519  return;
2520  }
2521  }
2522  else
2523  fVal = pFC->GetValue();
2524  }
2525  break;
2526  default:
2527  ;
2528  }
2529 
2530  SvNumFormatType nType = pFormatter->GetType(nFormat);
2531  bool bDate = false;
2532  if ((nType & SvNumFormatType::DATE) && !(nType & SvNumFormatType::TIME))
2533  {
2534  // special case for date values. Disregard the time
2535  // element if the number format is of date type.
2536  fVal = rtl::math::approxFloor(fVal);
2537  mrFilterEntries.mbHasDates = true;
2538  bDate = true;
2539  // Convert string representation to ISO 8601 date to eliminate
2540  // locale dependent behaviour later when filtering for dates.
2541  sal_uInt32 nIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_YYYYMMDD);
2542  pFormatter->GetInputLineString( fVal, nIndex, aStr);
2543  }
2544  else if (nType == SvNumFormatType::DATETIME)
2545  {
2546  // special case for datetime values.
2547  // Convert string representation to ISO 8601 (with blank instead of T) datetime
2548  // to eliminate locale dependent behaviour later when filtering for datetimes.
2549  sal_uInt32 nIndex = pFormatter->GetFormatIndex(NF_DATETIME_ISO_YYYYMMDD_HHMMSS);
2550  pFormatter->GetInputLineString(fVal, nIndex, aStr);
2551  }
2552  // store the formatted/rounded value for filtering
2553  if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0 && !bDate)
2554  mrFilterEntries.push_back(ScTypedStrData(aStr, fVal, rColumn.GetDoc().RoundValueAsShown(fVal, nFormat), ScTypedStrData::Value, bDate));
2555  else
2556  mrFilterEntries.push_back(ScTypedStrData(aStr, fVal, fVal, ScTypedStrData::Value, bDate));
2557  }
2558 
2559 public:
2560  FilterEntriesHandler(ScColumn& rColumn, ScFilterEntries& rFilterEntries) :
2561  mrColumn(rColumn), mrFilterEntries(rFilterEntries) {}
2562 
2563  void operator() (size_t nRow, double fVal)
2564  {
2565  ScRefCellValue aCell(fVal);
2566  processCell(mrColumn, nRow, aCell);
2567  }
2568 
2569  void operator() (size_t nRow, const svl::SharedString& rStr)
2570  {
2571  ScRefCellValue aCell(&rStr);
2572  processCell(mrColumn, nRow, aCell);
2573  }
2574 
2575  void operator() (size_t nRow, const EditTextObject* p)
2576  {
2577  ScRefCellValue aCell(p);
2578  processCell(mrColumn, nRow, aCell);
2579  }
2580 
2581  void operator() (size_t nRow, const ScFormulaCell* p)
2582  {
2583  ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
2584  processCell(mrColumn, nRow, aCell);
2585  }
2586 
2587  void operator() (const int nElemType, size_t nRow, size_t /* nDataSize */)
2588  {
2589  if ( nElemType == sc::element_type_empty )
2590  {
2591  if (!mrFilterEntries.mbHasEmpties)
2592  {
2593  mrFilterEntries.push_back(ScTypedStrData(OUString()));
2594  mrFilterEntries.mbHasEmpties = true;
2595  }
2596  return;
2597  }
2598  ScRefCellValue aCell = mrColumn.GetCellValue(nRow);
2599  processCell(mrColumn, nRow, aCell);
2600  }
2601 };
2602 
2603 }
2604 
2606  sc::ColumnBlockConstPosition& rBlockPos, SCROW nStartRow, SCROW nEndRow,
2607  ScFilterEntries& rFilterEntries, bool bFiltering )
2608 {
2609  mbFiltering = bFiltering;
2610  FilterEntriesHandler aFunc(*this, rFilterEntries);
2611  rBlockPos.miCellPos =
2612  sc::ParseAll(rBlockPos.miCellPos, maCells, nStartRow, nEndRow, aFunc, aFunc);
2613 }
2614 
2615 namespace {
2616 
2620 class StrCellIterator
2621 {
2622  typedef std::pair<sc::CellStoreType::const_iterator,size_t> PosType;
2623  PosType maPos;
2624  sc::CellStoreType::const_iterator miBeg;
2625  sc::CellStoreType::const_iterator miEnd;
2626  const ScDocument* mpDoc;
2627 public:
2628  StrCellIterator(const sc::CellStoreType& rCells, SCROW nStart, const ScDocument* pDoc) :
2629  miBeg(rCells.begin()), miEnd(rCells.end()), mpDoc(pDoc)
2630  {
2631  if (pDoc->ValidRow(nStart))
2632  maPos = rCells.position(nStart);
2633  else
2634  // Make this iterator invalid.
2635  maPos.first = miEnd;
2636  }
2637 
2638  bool valid() const { return (maPos.first != miEnd); }
2639 
2640  bool has() const
2641  {
2642  return (maPos.first->type == sc::element_type_string || maPos.first->type == sc::element_type_edittext);
2643  }
2644 
2645  bool prev()
2646  {
2647  if (!has())
2648  {
2649  // Not in a string block. Move back until we hit a string block.
2650  while (!has())
2651  {
2652  if (maPos.first == miBeg)
2653  return false;
2654 
2655  --maPos.first; // move to the preceding block.
2656  maPos.second = maPos.first->size - 1; // last cell in the block.
2657  }
2658  return true;
2659  }
2660 
2661  // We are in a string block.
2662  if (maPos.second > 0)
2663  {
2664  // Move back one cell in the same block.
2665  --maPos.second;
2666  }
2667  else
2668  {
2669  // Move back to the preceding string block.
2670  while (true)
2671  {
2672  if (maPos.first == miBeg)
2673  return false;
2674 
2675  // Move to the last cell of the previous block.
2676  --maPos.first;
2677  maPos.second = maPos.first->size - 1;
2678  if (has())
2679  break;
2680  }
2681  }
2682  return true;
2683  }
2684 
2685  bool next()
2686  {
2687  if (!has())
2688  {
2689  // Not in a string block. Move forward until we hit a string block.
2690  while (!has())
2691  {
2692  ++maPos.first;
2693  if (maPos.first == miEnd)
2694  return false;
2695 
2696  maPos.second = 0; // First cell in this block.
2697  }
2698  return true;
2699  }
2700 
2701  // We are in a string block.
2702  ++maPos.second;
2703  if (maPos.second >= maPos.first->size)
2704  {
2705  // Move to the next string block.
2706  while (true)
2707  {
2708  ++maPos.first;
2709  if (maPos.first == miEnd)
2710  return false;
2711 
2712  maPos.second = 0;
2713  if (has())
2714  break;
2715  }
2716  }
2717  return true;
2718  }
2719 
2720  OUString get() const
2721  {
2722  switch (maPos.first->type)
2723  {
2725  return sc::string_block::at(*maPos.first->data, maPos.second).getString();
2727  {
2728  const EditTextObject* p = sc::edittext_block::at(*maPos.first->data, maPos.second);
2729  return ScEditUtil::GetString(*p, mpDoc);
2730  }
2731  default:
2732  ;
2733  }
2734  return OUString();
2735  }
2736 };
2737 
2738 }
2739 
2740 // GetDataEntries - Strings from continuous Section around nRow
2742  SCROW nStartRow, std::set<ScTypedStrData>& rStrings) const
2743 {
2744  // Start at the specified row position, and collect all string values
2745  // going upward and downward directions in parallel. The start position
2746  // cell must be skipped.
2747 
2748  StrCellIterator aItrUp(maCells, nStartRow, &GetDoc());
2749  StrCellIterator aItrDown(maCells, nStartRow+1, &GetDoc());
2750 
2751  bool bMoveUp = aItrUp.valid();
2752  if (!bMoveUp)
2753  // Current cell is invalid.
2754  return false;
2755 
2756  // Skip the start position cell.
2757  bMoveUp = aItrUp.prev(); // Find the previous string cell position.
2758 
2759  bool bMoveDown = aItrDown.valid();
2760  if (bMoveDown && !aItrDown.has())
2761  bMoveDown = aItrDown.next(); // Find the next string cell position.
2762 
2763  bool bFound = false;
2764  while (bMoveUp)
2765  {
2766  // Get the current string and move up.
2767  OUString aStr = aItrUp.get();
2768  if (!aStr.isEmpty())
2769  {
2770  if (rStrings.insert(ScTypedStrData(aStr)).second)
2771  bFound = true;
2772  }
2773 
2774  bMoveUp = aItrUp.prev();
2775  }
2776 
2777  while (bMoveDown)
2778  {
2779  // Get the current string and move down.
2780  OUString aStr = aItrDown.get();
2781  if (!aStr.isEmpty())
2782  {
2783  if (rStrings.insert(ScTypedStrData(aStr)).second)
2784  bFound = true;
2785  }
2786 
2787  bMoveDown = aItrDown.next();
2788  }
2789 
2790  return bFound;
2791 }
2792 
2793 namespace {
2794 
2795 class FormulaToValueHandler
2796 {
2797  struct Entry
2798  {
2799  SCROW mnRow;
2801 
2802  Entry(SCROW nRow, double f) : mnRow(nRow), maValue(f) {}
2803  Entry(SCROW nRow, const svl::SharedString& rStr) : mnRow(nRow), maValue(rStr) {}
2804  };
2805 
2806  typedef std::vector<Entry> EntriesType;
2807  EntriesType maEntries;
2808 
2809 public:
2810 
2811  void operator() (size_t nRow, const ScFormulaCell* p)
2812  {
2813  ScFormulaCell* p2 = const_cast<ScFormulaCell*>(p);
2814  if (p2->IsValue())
2815  maEntries.emplace_back(nRow, p2->GetValue());
2816  else
2817  maEntries.emplace_back(nRow, p2->GetString());
2818  }
2819 
2820  void commitCells(ScColumn& rColumn)
2821  {
2822  sc::ColumnBlockPosition aBlockPos;
2823  rColumn.InitBlockPosition(aBlockPos);
2824 
2825  for (const Entry& r : maEntries)
2826  {
2827  switch (r.maValue.meType)
2828  {
2829  case CELLTYPE_VALUE:
2830  rColumn.SetValue(aBlockPos, r.mnRow, r.maValue.mfValue, false);
2831  break;
2832  case CELLTYPE_STRING:
2833  rColumn.SetRawString(aBlockPos, r.mnRow, *r.maValue.mpString, false);
2834  break;
2835  default:
2836  ;
2837  }
2838  }
2839  }
2840 };
2841 
2842 }
2843 
2844 void ScColumn::RemoveProtected( SCROW nStartRow, SCROW nEndRow )
2845 {
2846  FormulaToValueHandler aFunc;
2847  sc::CellStoreType::const_iterator itPos = maCells.begin();
2848 
2849  ScAttrIterator aAttrIter( pAttrArray.get(), nStartRow, nEndRow, GetDoc().GetDefPattern() );
2850  SCROW nTop = -1;
2851  SCROW nBottom = -1;
2852  const ScPatternAttr* pPattern = aAttrIter.Next( nTop, nBottom );
2853  while (pPattern)
2854  {
2855  const ScProtectionAttr* pAttr = &pPattern->GetItem(ATTR_PROTECTION);
2856  if ( pAttr->GetHideCell() )
2857  DeleteArea( nTop, nBottom, InsertDeleteFlags::CONTENTS );
2858  else if ( pAttr->GetHideFormula() )
2859  {
2860  // Replace all formula cells between nTop and nBottom with raw value cells.
2861  itPos = sc::ParseFormula(itPos, maCells, nTop, nBottom, aFunc);
2862  }
2863 
2864  pPattern = aAttrIter.Next( nTop, nBottom );
2865  }
2866 
2867  aFunc.commitCells(*this);
2868 }
2869 
2870 void ScColumn::SetError( SCROW nRow, const FormulaError nError)
2871 {
2872  if (!GetDoc().ValidRow(nRow))
2873  return;
2874 
2875  ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), ScAddress(nCol, nRow, nTab));
2876  pCell->SetErrCode(nError);
2877 
2878  std::vector<SCROW> aNewSharedRows;
2879  sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, true);
2880  it = maCells.set(it, nRow, pCell);
2881  maCellTextAttrs.set(nRow, sc::CellTextAttr());
2882 
2883  CellStorageModified();
2884 
2885  AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows);
2886 }
2887 
2888 void ScColumn::SetRawString( SCROW nRow, const OUString& rStr )
2889 {
2890  if (!GetDoc().ValidRow(nRow))
2891  return;
2892 
2893  svl::SharedString aSS = GetDoc().GetSharedStringPool().intern(rStr);
2894  if (!aSS.getData())
2895  return;
2896 
2897  SetRawString(nRow, aSS);
2898 }
2899 
2901 {
2902  if (!GetDoc().ValidRow(nRow))
2903  return;
2904 
2905  std::vector<SCROW> aNewSharedRows;
2906  sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, false);
2907  maCells.set(it, nRow, rStr);
2908  maCellTextAttrs.set(nRow, sc::CellTextAttr());
2909 
2910  CellStorageModified();
2911 
2912  StartListeningUnshared( aNewSharedRows);
2913 
2914  BroadcastNewCell(nRow);
2915 }
2916 
2918  sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const svl::SharedString& rStr, bool bBroadcast )
2919 {
2920  if (!GetDoc().ValidRow(nRow))
2921  return;
2922 
2923  std::vector<SCROW> aNewSharedRows;
2924  rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows, false);
2925  rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, rStr);
2926  rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
2927  rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
2928 
2929  CellStorageModified();
2930 
2931  StartListeningUnshared( aNewSharedRows);
2932 
2933  if (bBroadcast)
2934  BroadcastNewCell(nRow);
2935 }
2936 
2937 void ScColumn::SetValue( SCROW nRow, double fVal )
2938 {
2939  if (!GetDoc().ValidRow(nRow))
2940  return;
2941 
2942  std::vector<SCROW> aNewSharedRows;
2943  sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, false);
2944  maCells.set(it, nRow, fVal);
2945  maCellTextAttrs.set(nRow, sc::CellTextAttr());
2946 
2947  CellStorageModified();
2948 
2949  StartListeningUnshared( aNewSharedRows);
2950 
2951  BroadcastNewCell(nRow);
2952 }
2953 
2955  sc::ColumnBlockPosition& rBlockPos, SCROW nRow, double fVal, bool bBroadcast )
2956 {
2957  if (!GetDoc().ValidRow(nRow))
2958  return;
2959 
2960  std::vector<SCROW> aNewSharedRows;
2961  rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows, false);
2962  rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, fVal);
2963  rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
2964  rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
2965 
2966  CellStorageModified();
2967 
2968  StartListeningUnshared( aNewSharedRows);
2969 
2970  if (bBroadcast)
2971  BroadcastNewCell(nRow);
2972 }
2973 
2974 void ScColumn::GetString( const ScRefCellValue& aCell, SCROW nRow, OUString& rString, const ScInterpreterContext* pContext ) const
2975 {
2976  // ugly hack for ordering problem with GetNumberFormat and missing inherited formats
2977  if (aCell.meType == CELLTYPE_FORMULA)
2978  aCell.mpFormula->MaybeInterpret();
2979 
2980  sal_uInt32 nFormat = GetNumberFormat( pContext ? *pContext : GetDoc().GetNonThreadedContext(), nRow);
2981  const Color* pColor = nullptr;
2982  ScCellFormat::GetString(aCell, nFormat, rString, &pColor,
2983  pContext ? *(pContext->GetFormatTable()) : *(GetDoc().GetFormatTable()), GetDoc());
2984 }
2985 
2987 {
2988  std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
2989  sc::CellStoreType::iterator it = aPos.first;
2990  if (it == maCells.end())
2991  return nullptr;
2992 
2993  if (it->type != sc::element_type_numeric)
2994  return nullptr;
2995 
2996  return &sc::numeric_block::at(*it->data, aPos.second);
2997 }
2998 
2999 void ScColumn::GetInputString( const ScRefCellValue& aCell, SCROW nRow, OUString& rString ) const
3000 {
3001  sal_uLong nFormat = GetNumberFormat(GetDoc().GetNonThreadedContext(), nRow);
3002  ScCellFormat::GetInputString(aCell, nFormat, rString, *(GetDoc().GetFormatTable()), GetDoc());
3003 }
3004 
3005 double ScColumn::GetValue( SCROW nRow ) const
3006 {
3007  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3008  sc::CellStoreType::const_iterator it = aPos.first;
3009  switch (it->type)
3010  {
3012  return sc::numeric_block::at(*it->data, aPos.second);
3014  {
3015  const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
3016  ScFormulaCell* p2 = const_cast<ScFormulaCell*>(p);
3017  return p2->IsValue() ? p2->GetValue() : 0.0;
3018  }
3019  default:
3020  ;
3021  }
3022 
3023  return 0.0;
3024 }
3025 
3027 {
3028  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3029  sc::CellStoreType::const_iterator it = aPos.first;
3030  if (it == maCells.end())
3031  return nullptr;
3032 
3033  if (it->type != sc::element_type_edittext)
3034  return nullptr;
3035 
3036  return sc::edittext_block::at(*it->data, aPos.second);
3037 }
3038 
3040 {
3041  std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
3042  sc::CellStoreType::iterator it = aPos.first;
3043  if (it == maCells.end())
3044  return;
3045 
3046  if (it->type != sc::element_type_edittext)
3047  return;
3048 
3049  EditTextObject* p = sc::edittext_block::at(*it->data, aPos.second);
3050  ScEditUtil::RemoveCharAttribs(*p, rAttr);
3051 }
3052 
3053 void ScColumn::GetFormula( SCROW nRow, OUString& rFormula ) const
3054 {
3055  const ScFormulaCell* p = FetchFormulaCell(nRow);
3056  if (p)
3057  p->GetFormula(rFormula);
3058  else
3059  rFormula = EMPTY_OUSTRING;
3060 }
3061 
3063 {
3064  return FetchFormulaCell(nRow);
3065 }
3066 
3068 {
3069  return const_cast<ScFormulaCell*>(FetchFormulaCell(nRow));
3070 }
3071 
3073 {
3074  switch (maCells.get_type(nRow))
3075  {
3077  return CELLTYPE_VALUE;
3079  return CELLTYPE_STRING;
3081  return CELLTYPE_EDIT;
3083  return CELLTYPE_FORMULA;
3084  default:
3085  ;
3086  }
3087  return CELLTYPE_NONE;
3088 }
3089 
3090 namespace {
3091 
3095 class CellCounter
3096 {
3097  size_t mnCount;
3098 public:
3099  CellCounter() : mnCount(0) {}
3100 
3101  void operator() (const sc::CellStoreType::value_type& node)
3102  {
3103  if (node.type == sc::element_type_empty)
3104  return;
3105 
3106  mnCount += node.size;
3107  }
3108 
3109  size_t getCount() const { return mnCount; }
3110 };
3111 
3112 }
3113 
3115 {
3116  CellCounter aFunc;
3117  aFunc = std::for_each(maCells.begin(), maCells.end(), aFunc);
3118  return aFunc.getCount();
3119 }
3120 
3122 {
3123  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3124  sc::CellStoreType::const_iterator it = aPos.first;
3125  if (it == maCells.end())
3126  return FormulaError::NONE;
3127 
3128  if (it->type != sc::element_type_formula)
3129  return FormulaError::NONE;
3130 
3131  const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
3132  return const_cast<ScFormulaCell*>(p)->GetErrCode();
3133 }
3134 
3135 bool ScColumn::HasStringData( SCROW nRow ) const
3136 {
3137  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3138  switch (aPos.first->type)
3139  {
3142  return true;
3144  {
3145  const ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second);
3146  return !const_cast<ScFormulaCell*>(p)->IsValue();
3147  }
3148  default:
3149  ;
3150  }
3151 
3152  return false;
3153 }
3154 
3155 bool ScColumn::HasValueData( SCROW nRow ) const
3156 {
3157  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3158  switch (aPos.first->type)
3159  {
3161  return true;
3163  {
3164  const ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second);
3165  return const_cast<ScFormulaCell*>(p)->IsValue();
3166  }
3167  default:
3168  ;
3169  }
3170 
3171  return false;
3172 }
3173 
3177 bool ScColumn::HasStringCells( SCROW nStartRow, SCROW nEndRow ) const
3178 {
3179  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
3180  sc::CellStoreType::const_iterator it = aPos.first;
3181  size_t nOffset = aPos.second;
3182  SCROW nRow = nStartRow;
3183  for (; it != maCells.end() && nRow <= nEndRow; ++it)
3184  {
3185  if (it->type == sc::element_type_string || it->type == sc::element_type_edittext)
3186  return true;
3187 
3188  nRow += it->size - nOffset;
3189  nOffset = 0;
3190  }
3191 
3192  return false;
3193 }
3194 
3195 namespace {
3196 
3197 class MaxStringLenHandler
3198 {
3199  sal_Int32 mnMaxLen;
3200  const ScColumn& mrColumn;
3201  SvNumberFormatter* mpFormatter;
3202  rtl_TextEncoding meCharSet;
3203  bool mbOctetEncoding;
3204 
3205  void processCell(size_t nRow, const ScRefCellValue& rCell)
3206  {
3207  const Color* pColor;
3208  OUString aString;
3209  sal_uInt32 nFormat = mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT).GetValue();
3210  ScCellFormat::GetString(rCell, nFormat, aString, &pColor, *mpFormatter, mrColumn.GetDoc());
3211  sal_Int32 nLen = 0;
3212  if (mbOctetEncoding)
3213  {
3214  OString aOString;
3215  if (!aString.convertToString(&aOString, meCharSet,
3216  RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
3217  RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
3218  {
3219  // TODO: anything? this is used by the dBase export filter
3220  // that throws an error anyway, but in case of another
3221  // context we might want to indicate a conversion error
3222  // early.
3223  }
3224  nLen = aOString.getLength();
3225  }
3226  else
3227  nLen = aString.getLength() * sizeof(sal_Unicode);
3228 
3229  if (mnMaxLen < nLen)
3230  mnMaxLen = nLen;
3231  }
3232 
3233 public:
3234  MaxStringLenHandler(const ScColumn& rColumn, rtl_TextEncoding eCharSet) :
3235  mnMaxLen(0),
3236  mrColumn(rColumn),
3237  mpFormatter(rColumn.GetDoc().GetFormatTable()),
3238  meCharSet(eCharSet),
3239  mbOctetEncoding(rtl_isOctetTextEncoding(eCharSet))
3240  {
3241  }
3242 
3243  void operator() (size_t nRow, double fVal)
3244  {
3245  ScRefCellValue aCell(fVal);
3246  processCell(nRow, aCell);
3247  }
3248 
3249  void operator() (size_t nRow, const svl::SharedString& rStr)
3250  {
3251  ScRefCellValue aCell(&rStr);
3252  processCell(nRow, aCell);
3253  }
3254 
3255  void operator() (size_t nRow, const EditTextObject* p)
3256  {
3257  ScRefCellValue aCell(p);
3258  processCell(nRow, aCell);
3259  }
3260 
3261  void operator() (size_t nRow, const ScFormulaCell* p)
3262  {
3263  ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
3264  processCell(nRow, aCell);
3265  }
3266 
3267  sal_Int32 getMaxLen() const { return mnMaxLen; }
3268 };
3269 
3270 }
3271 
3272 sal_Int32 ScColumn::GetMaxStringLen( SCROW nRowStart, SCROW nRowEnd, rtl_TextEncoding eCharSet ) const
3273 {
3274  MaxStringLenHandler aFunc(*this, eCharSet);
3275  sc::ParseAllNonEmpty(maCells.begin(), maCells, nRowStart, nRowEnd, aFunc);
3276  return aFunc.getMaxLen();
3277 }
3278 
3279 namespace {
3280 
3281 class MaxNumStringLenHandler
3282 {
3283  const ScColumn& mrColumn;
3284  SvNumberFormatter* mpFormatter;
3285  sal_Int32 mnMaxLen;
3286  sal_uInt16 mnPrecision;
3287  sal_uInt16 mnMaxGeneralPrecision;
3288  bool mbHaveSigned;
3289 
3290  void processCell(size_t nRow, ScRefCellValue& rCell)
3291  {
3292  sal_uInt16 nCellPrecision = mnMaxGeneralPrecision;
3293  if (rCell.meType == CELLTYPE_FORMULA)
3294  {
3295  if (!rCell.mpFormula->IsValue())
3296  return;
3297 
3298  // Limit unformatted formula cell precision to precision
3299  // encountered so far, if any, otherwise we'd end up with 15 just
3300  // because of =1/3 ... If no precision yet then arbitrarily limit
3301  // to a maximum of 4 unless a maximum general precision is set.
3302  if (mnPrecision)
3303  nCellPrecision = mnPrecision;
3304  else
3305  nCellPrecision = (mnMaxGeneralPrecision >= 15) ? 4 : mnMaxGeneralPrecision;
3306  }
3307 
3308  double fVal = rCell.getValue();
3309  if (!mbHaveSigned && fVal < 0.0)
3310  mbHaveSigned = true;
3311 
3312  OUString aString;
3313  OUString aSep;
3314  sal_uInt16 nPrec;
3315  sal_uInt32 nFormat =
3316  mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT).GetValue();
3317  if (nFormat % SV_COUNTRY_LANGUAGE_OFFSET)
3318  {
3319  aSep = mpFormatter->GetFormatDecimalSep(nFormat);
3320  ScCellFormat::GetInputString(rCell, nFormat, aString, *mpFormatter, mrColumn.GetDoc());
3321  const SvNumberformat* pEntry = mpFormatter->GetEntry(nFormat);
3322  if (pEntry)
3323  {
3324  bool bThousand, bNegRed;
3325  sal_uInt16 nLeading;
3326  pEntry->GetFormatSpecialInfo(bThousand, bNegRed, nPrec, nLeading);
3327  }
3328  else
3329  nPrec = mpFormatter->GetFormatPrecision(nFormat);
3330  }
3331  else
3332  {
3333  if (mnPrecision >= mnMaxGeneralPrecision)
3334  return; // early bail out for nothing changes here
3335 
3336  if (!fVal)
3337  {
3338  // 0 doesn't change precision, but set a maximum length if none yet.
3339  if (!mnMaxLen)
3340  mnMaxLen = 1;
3341  return;
3342  }
3343 
3344  // Simple number string with at most 15 decimals and trailing
3345  // decimal zeros eliminated.
3346  aSep = ".";
3347  aString = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_F, nCellPrecision, '.', true);
3349  }
3350 
3351  sal_Int32 nLen = aString.getLength();
3352  if (nLen <= 0)
3353  // Ignore empty string.
3354  return;
3355 
3356  if (nPrec == SvNumberFormatter::UNLIMITED_PRECISION && mnPrecision < mnMaxGeneralPrecision)
3357  {
3358  if (nFormat % SV_COUNTRY_LANGUAGE_OFFSET)
3359  {
3360  // For some reason we couldn't obtain a precision from the
3361  // format, retry with simple number string.
3362  aSep = ".";
3363  aString = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_F, nCellPrecision, '.', true);
3364  nLen = aString.getLength();
3365  }
3366  sal_Int32 nSep = aString.indexOf( aSep);
3367  if (nSep != -1)
3368  nPrec = aString.getLength() - nSep - 1;
3369 
3370  }
3371 
3372  if (nPrec != SvNumberFormatter::UNLIMITED_PRECISION && nPrec > mnPrecision)
3373  mnPrecision = nPrec;
3374 
3375  if (mnPrecision)
3376  { // less than mnPrecision in string => widen it
3377  // more => shorten it
3378  sal_Int32 nTmp = aString.indexOf(aSep);
3379  if ( nTmp == -1 )
3380  nLen += mnPrecision + aSep.getLength();
3381  else
3382  {
3383  nTmp = aString.getLength() - (nTmp + aSep.getLength());
3384  if (nTmp != mnPrecision)
3385  nLen += mnPrecision - nTmp;
3386  // nPrecision > nTmp : nLen + Diff
3387  // nPrecision < nTmp : nLen - Diff
3388  }
3389  }
3390 
3391  // Enlarge for sign if necessary. Bear in mind that
3392  // GetMaxNumberStringLen() is for determining dBase decimal field width
3393  // and precision where the overall field width must include the sign.
3394  // Fitting -1 into "#.##" (width 4, 2 decimals) does not work.
3395  if (mbHaveSigned && fVal >= 0.0)
3396  ++nLen;
3397 
3398  if (mnMaxLen < nLen)
3399  mnMaxLen = nLen;
3400  }
3401 
3402 public:
3403  MaxNumStringLenHandler(const ScColumn& rColumn, sal_uInt16 nMaxGeneralPrecision) :
3404  mrColumn(rColumn), mpFormatter(rColumn.GetDoc().GetFormatTable()),
3405  mnMaxLen(0), mnPrecision(0), mnMaxGeneralPrecision(nMaxGeneralPrecision),
3406  mbHaveSigned(false)
3407  {
3408  // Limit the decimals passed to doubleToUString().
3409  // Also, the dBaseIII maximum precision is 15.
3410  if (mnMaxGeneralPrecision > 15)
3411  mnMaxGeneralPrecision = 15;
3412  }
3413 
3414  void operator() (size_t nRow, double fVal)
3415  {
3416  ScRefCellValue aCell(fVal);
3417  processCell(nRow, aCell);
3418  }
3419 
3420  void operator() (size_t nRow, const ScFormulaCell* p)
3421  {
3422  ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
3423  processCell(nRow, aCell);
3424  }
3425 
3426  sal_Int32 getMaxLen() const { return mnMaxLen; }
3427 
3428  sal_uInt16 getPrecision() const { return mnPrecision; }
3429 };
3430 
3431 }
3432 
3434  sal_uInt16& nPrecision, SCROW nRowStart, SCROW nRowEnd ) const
3435 {
3436  sal_uInt16 nMaxGeneralPrecision = GetDoc().GetDocOptions().GetStdPrecision();
3437  MaxNumStringLenHandler aFunc(*this, nMaxGeneralPrecision);
3438  sc::ParseFormulaNumeric(maCells.begin(), maCells, nRowStart, nRowEnd, aFunc);
3439  nPrecision = aFunc.getPrecision();
3440  return aFunc.getMaxLen();
3441 }
3442 
3443 namespace {
3444 
3445 class GroupFormulaCells
3446 {
3447  std::vector<ScAddress>* mpGroupPos;
3448 
3449 public:
3450  explicit GroupFormulaCells(std::vector<ScAddress>* pGroupPos)
3451  : mpGroupPos(pGroupPos) {}
3452 
3453  void operator() (sc::CellStoreType::value_type& node)
3454  {
3455  if (node.type != sc::element_type_formula)
3456  // We are only interested in formula cells.
3457  return;
3458 
3459  size_t nRow = node.position; // start row position.
3460 
3461  sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
3462  sc::formula_block::iterator itEnd = sc::formula_block::end(*node.data);
3463 
3464  // This block should never be empty.
3465 
3466  ScFormulaCell* pPrev = *it;
3467  ScFormulaCellGroupRef xPrevGrp = pPrev->GetCellGroup();
3468  if (xPrevGrp)
3469  {
3470  // Move to the cell after the last cell of the current group.
3471  std::advance(it, xPrevGrp->mnLength);
3472  nRow += xPrevGrp->mnLength;
3473  }
3474  else
3475  {
3476  ++it;
3477  ++nRow;
3478  }
3479 
3480  ScFormulaCell* pCur = nullptr;
3481  ScFormulaCellGroupRef xCurGrp;
3482  for (; it != itEnd; pPrev = pCur, xPrevGrp = xCurGrp)
3483  {
3484  pCur = *it;
3485  xCurGrp = pCur->GetCellGroup();
3486 
3487  ScFormulaCell::CompareState eCompState = pPrev->CompareByTokenArray(*pCur);
3488  if (eCompState == ScFormulaCell::NotEqual)
3489  {
3490  // different formula tokens.
3491  if (xCurGrp)
3492  {
3493  // Move to the cell after the last cell of the current group.
3494  if (xCurGrp->mnLength > std::distance(it, itEnd))
3495  throw css::lang::IllegalArgumentException();
3496  std::advance(it, xCurGrp->mnLength);
3497  nRow += xCurGrp->mnLength;
3498  }
3499  else
3500  {
3501  ++it;
3502  ++nRow;
3503  }
3504 
3505  continue;
3506  }
3507 
3508  // Formula tokens equal those of the previous formula cell or cell group.
3509  if (xPrevGrp)
3510  {
3511  // Previous cell is a group.
3512  if (xCurGrp)
3513  {
3514  // The current cell is a group. Merge these two groups.
3515  xPrevGrp->mnLength += xCurGrp->mnLength;
3516  pCur->SetCellGroup(xPrevGrp);
3517  sc::formula_block::iterator itGrpEnd = it;
3518  if (xCurGrp->mnLength > std::distance(itGrpEnd, itEnd))
3519  throw css::lang::IllegalArgumentException();
3520  std::advance(itGrpEnd, xCurGrp->mnLength);
3521  for (++it; it != itGrpEnd; ++it)
3522  {
3523  ScFormulaCell* pCell = *it;
3524  pCell->SetCellGroup(xPrevGrp);
3525  }
3526  nRow += xCurGrp->mnLength;
3527  }
3528  else
3529  {
3530  // Add this cell to the previous group.
3531  pCur->SetCellGroup(xPrevGrp);
3532  ++xPrevGrp->mnLength;
3533  ++nRow;
3534  ++it;
3535  }
3536 
3537  }
3538  else if (xCurGrp)
3539  {
3540  // Previous cell is a regular cell and current cell is a group.
3541  nRow += xCurGrp->mnLength;
3542  if (xCurGrp->mnLength > std::distance(it, itEnd))
3543  throw css::lang::IllegalArgumentException();
3544  std::advance(it, xCurGrp->mnLength);
3545  pPrev->SetCellGroup(xCurGrp);
3546  xCurGrp->mpTopCell = pPrev;
3547  ++xCurGrp->mnLength;
3548  xPrevGrp = xCurGrp;
3549  }
3550  else
3551  {
3552  // Both previous and current cells are regular cells.
3553  assert(pPrev->aPos.Row() == static_cast<SCROW>(nRow - 1));
3554  xPrevGrp = pPrev->CreateCellGroup(2, eCompState == ScFormulaCell::EqualInvariant);
3555  pCur->SetCellGroup(xPrevGrp);
3556  ++nRow;
3557  ++it;
3558  }
3559 
3560  if (mpGroupPos)
3561  mpGroupPos->push_back(pCur->aPos);
3562 
3563  pCur = pPrev;
3564  xCurGrp = xPrevGrp;
3565  }
3566  }
3567 };
3568 
3569 }
3570 
3571 void ScColumn::RegroupFormulaCells( std::vector<ScAddress>* pGroupPos )
3572 {
3573  // re-build formula groups.
3574  std::for_each(maCells.begin(), maCells.end(), GroupFormulaCells(pGroupPos));
3575 }
3576 
3577 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static bool parseSimpleNumber(const OUString &rStr, sal_Unicode dsep, sal_Unicode gsep, sal_Unicode dsepa, double &rVal)
Check if a given string is a simple decimal number (e.g.
Definition: stringutil.cxx:52
Numeric values (and numeric results if InsertDeleteFlags::FORMULA is not set).
void set(double fValue)
Definition: cellvalue.cxx:295
sal_uInt32 GetFormatForLanguageIfBuiltIn(sal_uInt32 nFormat, LanguageType eLnge=LANGUAGE_DONTKNOW)
void FreeAll()
Definition: column3.cxx:157
void InterpretDirtyCells(SCROW nRow1, SCROW nRow2)
Definition: column3.cxx:116
STRING
Temporarily switch on/off auto calculation mode.
Definition: scopetools.hxx:26
CellTextAttrStoreType::const_iterator miCellTextAttrPos
void MixMarked(sc::MixDocContext &rCxt, const ScMarkData &rMark, ScPasteFunc nFunction, bool bSkipEmpty, const ScColumn &rSrcCol)
Definition: column3.cxx:1464
SfxHintId
::boost::intrusive_ptr< ScFormulaCellGroup > ScFormulaCellGroupRef
Definition: types.hxx:43
void DeleteRow(SCROW nStartRow, SCSIZE nSize, std::vector< ScAddress > *pGroupPos)
Definition: column3.cxx:190
sal_Int32 nIndex
CellType meType
Definition: cellvalue.hxx:37
OUString getString() const
CellStoreType::const_iterator miCellPos
void CopyFromClip(sc::CopyFromClipContext &rCxt, SCROW nRow1, SCROW nRow2, tools::Long nDy, ScColumn &rColumn)
Definition: column3.cxx:1391
SharedString intern(const OUString &rStr)
SC_DLLPUBLIC svl::SharedStringPool & GetSharedStringPool()
Definition: documen2.cxx:566
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:42
void DeleteArea(SCROW nStartRow, SCROW nEndRow, InsertDeleteFlags nDelFlag, bool bBroadcast=true, sc::ColumnSpanSet *pBroadcastSpans=nullptr)
Definition: column3.cxx:989
Store parameters used in the ScDocument::SetString() method.
Definition: stringutil.hxx:34
static void GetInputString(const ScRefCellValue &rCell, sal_uInt32 nFormat, OUString &rString, SvNumberFormatter &rFormatter, const ScDocument &rDoc, bool bFiltering=false)
Definition: cellform.cxx:119
std::unique_ptr< ScAttrArray > pAttrArray
Definition: column.hxx:131
bool mbHandleApostrophe
When true, treat input with a leading apostrophe as an escape character for a numeric value content...
Definition: stringutil.hxx:91
ScDocument & GetDoc() const
Definition: column.hxx:184
#define EMPTY_OUSTRING
Definition: global.hxx:214
void SetError(SCROW nRow, const FormulaError nError)
Definition: column3.cxx:2870
const char * pLocale
const SfxPoolItem & GetAttr(SCROW nRow, sal_uInt16 nWhich) const
Definition: column.cxx:376
Sheet / outlining (grouping) information.
SCROW Row() const
Definition: address.hxx:261
SvNumberFormatter * mpNumFormatter
Stores the pointer to the number formatter instance to be used during number format detection...
Definition: stringutil.hxx:70
Single reference (one address) into the sheet.
Definition: refdata.hxx:29
bool NeedsListening() const
CellTextAttrStoreType::iterator miCellTextAttrPos
sal_uInt32 GetFormatIndex(NfIndexTableOffset, LanguageType eLnge=LANGUAGE_DONTKNOW)
void GetFilterEntries(sc::ColumnBlockConstPosition &rBlockPos, SCROW nStartRow, SCROW nEndRow, ScFilterEntries &rFilterEntries, bool bFiltering)
Definition: column3.cxx:2605
static void lcl_AddFormulaGroupBoundaries(const sc::CellStoreType::position_type &rPos, std::vector< SCROW > &rNewSharedRows)
Definition: column3.cxx:556
const mdds::mtv::element_t element_type_celltextattr
Definition: mtvelements.hxx:45
SCROW GetSharedTopRow() const
FormulaError GetErrCode(SCROW nRow) const
Definition: column3.cxx:3121
bool mbCheckLinkFormula
When true and the string results in a compiled formula, check the formula tokens for presence of func...
Definition: stringutil.hxx:100
void GetFormula(OUString &rFormula, const formula::FormulaGrammar::Grammar=formula::FormulaGrammar::GRAM_DEFAULT, const ScInterpreterContext *pContext=nullptr) const
SCTAB nTab
Definition: column.hxx:136
ScTokenArray * GetCode()
bool GetDirty() const
sal_uIntPtr sal_uLong
long Long
void DuplicateNotes(SCROW nStartRow, size_t nDataSize, ScColumn &rDestCol, sc::ColumnBlockPosition &maDestBlockPos, bool bCloneCaption, SCROW nRowOffsetDest=0) const
Definition: column2.cxx:1956
StoreT::const_iterator ParseBlock(const typename StoreT::const_iterator &itPos, const StoreT &rStore, Func &rFunc, typename StoreT::size_type nStart, typename StoreT::size_type nEnd)
Generic algorithm to parse blocks of multi_type_vector either partially or fully. ...
sal_Int64 n
void SetEditText(SCROW nRow, std::unique_ptr< EditTextObject > pEditText)
Definition: column3.cxx:2217
CellStoreType::const_iterator ParseFormulaNumeric(const CellStoreType::const_iterator &itPos, const CellStoreType &rCells, SCROW nRow1, SCROW nRow2, Func &rFunc)
void BroadcastNewCell(SCROW nRow)
Definition: column3.cxx:752
sal_Int32 mnCol
SvNumFormatType GetType(sal_uInt32 nFIndex) const
formula::FormulaToken * AddSingleReference(const ScSingleRefData &rRef)
ScSingleRefToken with ocPush.
Definition: token.cxx:2271
void Broadcast(SCROW nRow)
Definition: column3.cxx:73
Store position data for column array storage.
const ContentProperties & rData
InsertDeleteFlags getInsertFlag() const
bool IsClipOrUndo() const
Definition: document.hxx:1532
bool isSkipAttrForEmptyCells() const
CellType GetCellType(SCROW nRow) const
Definition: column3.cxx:3072
void SetAbsRow(SCROW nVal)
Definition: refdata.cxx:76
CellStoreType::const_iterator ParseAllNonEmpty(const typename CellStoreType::const_iterator &itPos, const CellStoreType &rCells, SCROW nRow1, SCROW nRow2, Func &rFunc)
Definition: mtvcellfunc.hxx:95
static void startListeningAsGroup(StartListeningContext &rCxt, ScFormulaCell **ppSharedTop)
Have all formula cells belonging to a group start listening to their references.
void BroadcastRows(SCROW nStartRow, SCROW nEndRow, SfxHintId nHint)
Definition: column3.cxx:94
OpCode GetOpCode() const
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:103
constexpr TypedWhichId< ScProtectionAttr > ATTR_PROTECTION(149)
static const ScFormulaCell * getSharedTopFormulaCell(const CellStoreType::position_type &aPos)
Get shared formula top cell from position, if any, else nullptr.
mdds::multi_type_vector< CellFunc, CellStoreEvent > CellStoreType
void RemoveEditTextCharAttribs(SCROW nRow, const ScPatternAttr &rAttr)
Definition: column3.cxx:3039
sal_uInt16 GetFormatPrecision(sal_uInt32 nFormat) const
StoreT::iterator ProcessBlock(const typename StoreT::iterator &itPos, StoreT &rStore, Func &rFunc, typename StoreT::size_type nStart, typename StoreT::size_type nEnd)
Non-const variant of the above function.
SC_DLLPUBLIC SvtScriptType GetStringScriptType(const OUString &rString)
Definition: documen6.cxx:76
bool IsMultilineResult()
Determines whether or not the result string contains more than one paragraph.
const ScAddress & GetAddress() const
Definition: brdcst.hxx:30
ScAddress & mrPos
void StartListeners(sc::StartListeningContext &rCxt, bool bAll)
Definition: column3.cxx:1947
void GetFormula(SCROW nRow, OUString &rFormula) const
Definition: column3.cxx:3053
Internal use only (d&d undo): do not delete caption objects of cell notes.
TextFormatPolicy meSetTextNumFormat
Determine when to set the 'Text' number format to the cell where the input string is being set...
Definition: stringutil.hxx:83
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6087
virtual const SfxItemPool * GetPool() const =0
static bool IsCompatible(SvNumFormatType eOldType, SvNumFormatType eNewType)
void ParseFormula(const CellStoreType &rStore, Func &rFunc)
Definition: mtvcellfunc.hxx:63
BroadcasterStoreType::iterator miBroadcasterPos
Store arbitrary cell value of any kind.
Definition: cellvalue.hxx:35
sal_Int32 GetMaxStringLen(SCROW nRowStart, SCROW nRowEnd, rtl_TextEncoding eCharSet) const
Definition: column3.cxx:3272
const ScFormulaCellGroupRef & GetCellGroup() const
ScFormulaCell * SetFormulaCell(SCROW nRow, ScFormulaCell *pCell, sc::StartListeningType eListenType=sc::SingleCellListening, bool bInheritNumFormatIfNeeded=true)
Takes ownership of pCell.
Definition: column3.cxx:2315
sal_uInt16 sal_Unicode
SC_DLLPUBLIC ScConditionalFormatList * GetCondFormList(SCTAB nTab) const
Definition: documen4.cxx:868
const LocaleDataWrapper * GetLocaleData() const
const mdds::mtv::element_t element_type_formula
Definition: mtvelements.hxx:49
sc::CellStoreType::iterator GetPositionToInsert(SCROW nRow, std::vector< SCROW > &rNewSharedRows, bool bInsertFormula)
Definition: column3.cxx:271
Keep track of spans in a single column only.
void SetText(const OUString &rStr)
ScRefCellValue GetCellValue(SCROW nRow) const
Definition: column.cxx:734
enumrange< T >::Iterator begin(enumrange< T >)
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
std::optional< Color > GetColor(const ScAddress &rAddr) const
Definition: colorscale.cxx:588
size_t pos
const css::i18n::LocaleDataItem2 & getLocaleItem() const
void StartListeningTo(ScDocument &rDoc)
double GetValue()
bool IsMultiMarked() const
Definition: markdata.hxx:82
bool hasString() const
Definition: cellvalue.cxx:617
FormulaError GetErrCode()
OpCode
int nCount
void Delete(SCROW nRow)
Definition: column3.cxx:147
sc::CellStoreType maCells
Definition: column.hxx:129
ScDocument * getDestDoc()
Definition: clipcontext.hxx:97
static bool splitFormulaCellGroup(const CellStoreType::position_type &aPos, sc::EndListeningContext *pCxt)
Split existing shared formula range at specified position.
static bool SafeMult(double &fVal1, double fVal2)
Definition: subtotal.cxx:40
static Grammar mergeToGrammar(const Grammar eGrammar, const AddressConvention eConv)
void push_back(const ScTypedStrData &r)
void set(const ScDocument &rDoc, SCTAB nTab, SCCOL nCol, SCROW nRow, bool bVal)
void CopyAreaSafe(SCROW nStartRow, SCROW nEndRow, tools::Long nDy, ScAttrArray &rAttrArray)
Leave flags summarized with CopyArea.
Definition: attarray.cxx:2461
ScFormulaCell * mpFormula
Definition: cellvalue.hxx:110
void SetRow(SCROW nRowP)
Definition: address.hxx:274
void release(ScDocument &rDoc, const ScAddress &rPos)
Set cell value at specified position in specified document.
Definition: cellvalue.cxx:432
bool SetFormulaCells(SCROW nRow, std::vector< ScFormulaCell * > &rCells)
Definition: column3.cxx:2353
sal_uInt32 GetNumberFormat(const ScInterpreterContext &rContext, SCROW nRow) const
Definition: column.cxx:422
void EndListeningFormulaCells(std::vector< ScFormulaCell * > &rCells)
Definition: documen7.cxx:246
void DeleteContent(SCROW nRow, bool bBroadcast=true)
Definition: column3.cxx:125
ScAddress aPos
void SetNeedNumberFormat(bool bVal)
sal_Int32 nElements
SC_DLLPUBLIC const ScPatternAttr * GetPattern(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:4766
size_t size() const
Definition: conditio.cxx:1772
void AttachNewFormulaCells(const sc::CellStoreType::position_type &aPos, size_t nLength, std::vector< SCROW > &rNewSharedRows)
Definition: column3.cxx:683
void SetDirty(bool bDirtyFlag=true)
SC_DLLPUBLIC const SfxPoolItem * GetAttr(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich) const
Definition: document.cxx:4745
sal_uInt16 GetLen() const
Internal use only (copy from clip): do not delete existing cell contents when pasting notes...
const SfxPoolItem & GetItem(sal_uInt16 nWhichP) const
Definition: patattr.hxx:70
NfEvalDateFormat GetEvalDateFormat() const
bool SetString(SCROW nRow, SCTAB nTab, const OUString &rString, formula::FormulaGrammar::AddressConvention eConv, const ScSetStringParam *pParam=nullptr)
Returns true if the cell format was set as well.
Definition: column3.cxx:2197
double GetValue(SCROW nRow) const
Definition: column3.cxx:3005
bool GetHideCell() const
Definition: attrib.hxx:147
const Color & GetColor() const
SCROW GetSharedLength() const
svl::SharedString GetSharedString(SCROW nRow) const
Definition: column3.cxx:2394
const ScFormatEntry * GetEntry(sal_uInt16 nPos) const
Definition: conditio.cxx:1786
ScPasteFunc
Definition: global.hxx:189
bool IsShared() const
FormulaToken * AddToken(const FormulaToken &)
static bool joinFormulaCellAbove(const CellStoreType::position_type &aPos)
Merge with an existing formula group (if any) located immediately above if the cell at specified posi...
sal_uInt32 GetEditFormat(double fNumber, sal_uInt32 nFIndex, SvNumFormatType eType, LanguageType eLnge, SvNumberformat const *pFormat)
SCCOL nCol
Definition: column.hxx:135
void getSpans(SpansType &rSpans) const
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:441
bool IsInsertingFromOtherDoc() const
Definition: document.hxx:2147
void InitBlockPosition(sc::ColumnBlockPosition &rBlockPos)
Definition: column3.cxx:1044
void AttachNewFormulaCell(const sc::CellStoreType::iterator &itPos, SCROW nRow, ScFormulaCell &rCell, const std::vector< SCROW > &rNewSharedRows, bool bJoin=true, sc::StartListeningType eListenType=sc::SingleCellListening)
Definition: column3.cxx:608
void SetTextCurrentDefaults(const EditTextObject &rTextObject)
SetText and apply defaults already set.
Definition: editutil.cxx:596
int i
void SetRawString(SCROW nRow, const OUString &rStr)
Definition: column3.cxx:2888
bool NeedsNumberFormat() const
bool isEmpty() const
void SetFlag3D(bool bVal)
Definition: refdata.hxx:89
ocMul
void InitAddress(const ScAddress &rAdr)
InitAddress: InitFlags and set address.
Definition: refdata.cxx:27
sal_Int16 SCCOL
Definition: types.hxx:21
InsertDeleteFlags
Definition: global.hxx:158
void RegroupFormulaCells(std::vector< ScAddress > *pGroupPos=nullptr)
Regroup formula cells for the entire column.
Definition: column3.cxx:3571
SvtScriptType mnScriptType
Set Text number format only when the input string is considered a special number but we only want to ...
Definition: stringutil.hxx:51
void SetAbsCol(SCCOL nVal)
Definition: refdata.cxx:59
bool GetHideFormula() const
Definition: attrib.hxx:145
sc::CellTextAttrStoreType maCellTextAttrs
Definition: column.hxx:118
ocSub
SvNumberFormatter * GetFormatTable() const
const SvxPageUsage aArr[]
void getRows(std::vector< SCROW > &rRows) const
StartListeningType
Definition: types.hxx:123
bool Interpret(SCROW nStartOffset=-1, SCROW nEndOffset=-1)
static void JoinNewFormulaCell(const sc::CellStoreType::position_type &aPos, ScFormulaCell &rCell)
Definition: column3.cxx:277
std::unique_ptr< EditTextObject > CreateTextObject()
void SetCellGroup(const ScFormulaCellGroupRef &xRef)
const mdds::mtv::element_t element_type_empty
Definition: mtvelements.hxx:55
void set(SCROW nRow1, SCROW nRow2, bool bVal)
Structure that stores segments of boolean flags per column, and perform custom action on those segmen...
bool HasValueData(SCROW nRow) const
Definition: column3.cxx:3155
bool IsNumberFormat(const OUString &sString, sal_uInt32 &F_Index, double &fOutNumber, SvNumInputOptions eInputOptions=SvNumInputOptions::NONE)
void SetEvalDateFormat(NfEvalDateFormat eEDF)
void GetInputLineString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &rOutString, bool bFiltering=false)
CellStoreType::const_iterator ParseAll(const typename CellStoreType::const_iterator &itPos, const CellStoreType &rCells, SCROW nRow1, SCROW nRow2, FuncElem &rFuncElem, FuncElse &rFuncElse)
Definition: mtvcellfunc.hxx:83
constexpr TypedWhichId< SfxUInt32Item > ATTR_VALUE_FORMAT(146)
SvNumFormatType
const mdds::mtv::element_t element_type_numeric
Mapped standard element types (for convenience).
Definition: mtvelements.hxx:54
bool IsSharedTop() const
sal_uInt32 GetNumberFormat(SvNumberFormatter *) const
Definition: patattr.cxx:1256
bool HasStringData(SCROW nRow) const
Definition: column3.cxx:3135
FormulaToken * FirstToken() const
double * GetValueCell(SCROW nRow)
Definition: column3.cxx:2986
CellStoreType::iterator ProcessFormula(const CellStoreType::iterator &it, CellStoreType &rStore, SCROW nRow1, SCROW nRow2, std::function< void(size_t, ScFormulaCell *)> aFuncElem)
Process formula cells found within specified row range.
Definition: mtvcellfunc.cxx:12
#define SV_COUNTRY_LANGUAGE_OFFSET
std::size_t mnCount
void SetAbsTab(SCTAB nVal)
Definition: refdata.cxx:93
void DetachFormulaCells(const sc::CellStoreType::position_type &aPos, size_t nLength, std::vector< SCROW > *pNewSharedRows)
Definition: column3.cxx:408
SC_DLLPUBLIC const SfxItemSet * GetCondResult(SCCOL nCol, SCROW nRow, SCTAB nTab, ScRefCellValue *pCell=nullptr) const
Definition: documen4.cxx:799
bool IsEmptyDisplayedAsString()
void Broadcast(const ScHint &rHint)
Broadcast wrapper, calls rHint.GetCell()->Broadcast() and AreaBroadcast() and TrackFormulas() Preferr...
Definition: documen7.cxx:117
void addTextColor(const Color &aTextColor)
rtl_uString * getData()
void FreeNotes()
Definition: column3.cxx:170
enumrange< T >::Iterator end(enumrange< T >)
const svl::SharedString & GetString()
FormulaError
OUString GetFormatDecimalSep(sal_uInt32 nFormat) const
CellStoreType::iterator miCellPos
ocFalse
bool GetDataEntries(SCROW nRow, std::set< ScTypedStrData > &rStrings) const
Definition: column3.cxx:2741
void MixData(sc::MixDocContext &rCxt, SCROW nRow1, SCROW nRow2, ScPasteFunc nFunction, bool bSkipEmpty, const ScColumn &rSrcCol)
Definition: column3.cxx:1887
static bool SafePlus(double &fVal1, double fVal2)
Definition: subtotal.cxx:24
static const sal_uInt16 UNLIMITED_PRECISION
constexpr TypedWhichId< SvxBrushItem > ATTR_BACKGROUND(148)
SC_DLLPUBLIC double RoundValueAsShown(double fVal, sal_uInt32 nFormat, const ScInterpreterContext *pContext=nullptr) const
Definition: documen4.cxx:635
virtual formula::FormulaToken * AddOpCode(OpCode eCode) override
Definition: token.cxx:2264
CellType meType
Definition: cellvalue.hxx:105
static bool SafeDiv(double &fVal1, double fVal2)
Definition: subtotal.cxx:53
static void unshareFormulaCell(const CellStoreType::position_type &aPos, ScFormulaCell &rCell)
Turn a shared formula cell into a non-shared one, and split it off from the adjacent formula cell gro...
ocTrue
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
NF_EVALDATEFORMAT_INTL_FORMAT
sal_Int32 SCROW
Definition: types.hxx:17
bool ParseString(ScCellValue &rCell, SCROW nRow, SCTAB nTab, const OUString &rString, formula::FormulaGrammar::AddressConvention eConv, const ScSetStringParam *pParam)
Definition: column3.cxx:1965
bool HasFiltering() const
Definition: column.hxx:187
const EditTextObject * GetEditText(SCROW nRow) const
Definition: column3.cxx:3026
bool ValidRow(SCROW nRow) const
Definition: document.hxx:875
NfEvalDateFormat
void SetFormula(SCROW nRow, const ScTokenArray &rArray, formula::FormulaGrammar::Grammar eGram)
Definition: column3.cxx:2279
bool mbDetectNumberFormat
When true, we try to detect special number format (dates etc) from the input string, when false, we only try to detect a basic decimal number format.
Definition: stringutil.hxx:77
ocAdd
void RemoveProtected(SCROW nStartRow, SCROW nEndRow)
Definition: column3.cxx:2844
void AttachFormulaCells(sc::StartListeningContext &rCxt, SCROW nRow1, SCROW nRow2)
Definition: column3.cxx:473
std::unique_ptr< ScAttrIterator > CreateAttrIterator(SCROW nStartRow, SCROW nEndRow) const
Definition: column3.cxx:1904
SCCOL GetCol() const
Definition: column.hxx:186
const SvNumberformat * GetEntry(sal_uInt32 nKey) const
static void groupFormulaCells(const Iter &itBeg, const Iter &itEnd)
Group formula cells stored in the passed container.
CellType
Definition: global.hxx:281
sc::CellTextAttrStoreType & GetCellAttrStore()
Definition: column.hxx:190
const mdds::mtv::element_t element_type_edittext
Definition: mtvelements.hxx:48
void InitFlags()
No default ctor, because used in ScRawToken union, set InitFlags!
Definition: refdata.hxx:54
sal_uInt32 GetStandardFormat(SvNumFormatType eType, LanguageType eLnge=LANGUAGE_DONTKNOW)
Dates, times, datetime values.
void GetString(SCROW nRow, OUString &rString, const ScInterpreterContext *pContext=nullptr) const
Definition: column.hxx:367
virtual std::unique_ptr< EditTextObject > Clone() const =0
CellNoteStoreType::iterator miCellNotePos
void ApplyPattern(SCROW nRow, const ScPatternAttr &rPatAttr)
Definition: column.cxx:502
const ScFormulaCell * GetFormulaCell(SCROW nRow) const
Definition: column3.cxx:3062
bool isDateCell(const ScColumn &rCol, SCROW nRow) const
SvNumFormatType GetMaskedType() const
constexpr TypedWhichId< ScCondFormatItem > ATTR_CONDITIONAL(154)
void * p
CompareState CompareByTokenArray(const ScFormulaCell &rOther) const
QPRO_FUNC_TYPE nType
Definition: qproform.cxx:398
std::vector< RowSpan > SpansType
ScFormulaCellGroupRef CreateCellGroup(SCROW nLen, bool bInvariant)
Turn a non-grouped cell into the top of a grouped cell.
double getValue()
Definition: cellvalue.cxx:632
virtual std::vector< svl::SharedString > GetSharedStrings() const =0
const ScCondFormatIndexes & GetCondFormatData() const
Definition: attrib.hxx:279
Set Text number format if the input string can be parsed as a number or formula text.
Definition: stringutil.hxx:45
static void RemoveCharAttribs(EditTextObject &rEditText, const ScPatternAttr &rAttr)
Definition: editutil.cxx:149
sal_Int32 GetMaxNumberStringLen(sal_uInt16 &nPrecision, SCROW nRowStart, SCROW nRowEnd) const
Definition: column3.cxx:3433
SCSIZE GetCellCount() const
Definition: column3.cxx:3114
ocDiv
void scan(const ScColumn &rColumn)
Scan an entire column and tag all non-empty cell positions.
void BroadcastCells(const std::vector< SCROW > &rRows, SfxHintId nHint)
Definition: column3.cxx:79
sc::StartListeningType meStartListening
Definition: stringutil.hxx:93
static SC_DLLPUBLIC OUString GetString(const EditTextObject &rEditText, const ScDocument *pDoc)
Retrieves string with paragraphs delimited by new lines (' ').
Definition: editutil.cxx:113
ScInterpreterContext & GetNonThreadedContext() const
Definition: document.hxx:604
void GetInputString(SCROW nRow, OUString &rString) const
Definition: column.hxx:373
bool ValidRow(SCROW nRow, SCROW nMaxRow)
Definition: address.hxx:98
SCTAB GetTab() const
Definition: column.hxx:185
void MaybeInterpret()
const ScMultiSel & GetMultiSelData() const
Definition: markdata.hxx:106
void SetValue(SCROW nRow, double fVal)
Definition: column3.cxx:2937
SC_DLLPUBLIC ScConditionalFormat * GetCondFormat(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: documen4.cxx:845
static void GetString(const ScRefCellValue &rCell, sal_uInt32 nFormat, OUString &rString, const Color **ppColor, SvNumberFormatter &rFormatter, const ScDocument &rDoc, bool bNullVals=true, bool bFormula=false, bool bUseStarFormat=false)
Definition: cellform.cxx:32
sal_Int32 mnRow
Never set Text number format.
Definition: stringutil.hxx:62
void addBackgroundColor(const Color &aBackgroundColor)
void DeleteCells(sc::ColumnBlockPosition &rBlockPos, SCROW nRow1, SCROW nRow2, InsertDeleteFlags nDelFlag, sc::SingleColumnSpanSet &rDeleted)
Definition: column3.cxx:967
bool IsCalcingAfterLoad() const
Definition: document.hxx:2151
bool HasStringCells(SCROW nStartRow, SCROW nEndRow) const
Return true if there is a string or editcell in the range.
Definition: column3.cxx:3177
CellNoteStoreType::const_iterator miCellNotePos
NF_EVALDATEFORMAT_FORMAT_INTL
constexpr TypedWhichId< SvxColorItem > ATTR_FONT_COLOR(109)
void SetErrCode(FormulaError n)
const mdds::mtv::element_t element_type_string
Definition: mtvelements.hxx:47
mdds::multi_type_vector< CTAttrFunc > CellTextAttrStoreType
sc::CellStoreType & GetCellStore()
Definition: column.hxx:188
void EndListeningTo(ScDocument &rDoc, ScTokenArray *pArr=nullptr, ScAddress aPos=ScAddress())
aStr
static OUString GetErrorString(FormulaError nErrNumber)
Definition: global.cxx:303
Strings (and string results if InsertDeleteFlags::FORMULA is not set).
SC_DLLPUBLIC ScFieldEditEngine & GetEditEngine()
Definition: documen2.cxx:457
double maValue
static bool joinFormulaCells(const CellStoreType::position_type &rPos, ScFormulaCell &rCell1, ScFormulaCell &rCell2)
See if two specified adjacent formula cells can be merged, and if they can, merge them into the same ...
LanguageType GetLanguage() const
void StartListeningUnshared(const std::vector< SCROW > &rNewSharedRows)
Re-establish listeners on unshared formula groups.
Definition: column3.cxx:350
const Color & GetValue() const
sal_uInt16 nPos
ColumnBlockPosition * getBlockPosition(SCTAB nTab, SCCOL nCol)
Definition: clipcontext.cxx:32
sal_Int16 SCTAB
Definition: types.hxx:22
void DetachFormulaCell(const sc::CellStoreType::position_type &aPos, ScFormulaCell &rCell, std::vector< SCROW > &rNewSharedRows)
Detach a formula cell that's about to be deleted, or removed from document storage (if that ever happ...
Definition: column3.cxx:297
void GetFormatSpecialInfo(bool &bThousand, bool &IsRed, sal_uInt16 &nPrecision, sal_uInt16 &nLeadingCnt) const
bool UpdateScriptType(sc::CellTextAttr &rAttr, SCROW nRow, sc::CellStoreType::iterator &itr)
Definition: column3.cxx:765
bool isCloneNotes() const