LibreOffice Module sc (master)  1
column4.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 
10 #include <column.hxx>
11 #include <clipparam.hxx>
12 #include <cellvalue.hxx>
13 #include <attarray.hxx>
14 #include <document.hxx>
15 #include <cellvalues.hxx>
16 #include <columnspanset.hxx>
17 #include <columniterator.hxx>
18 #include <mtvcellfunc.hxx>
19 #include <clipcontext.hxx>
20 #include <attrib.hxx>
21 #include <patattr.hxx>
22 #include <docpool.hxx>
23 #include <conditio.hxx>
24 #include <formulagroup.hxx>
25 #include <tokenarray.hxx>
26 #include <scitems.hxx>
27 #include <cellform.hxx>
28 #include <sharedformula.hxx>
29 #include <drwlayer.hxx>
30 #include <compiler.hxx>
31 #include <recursionhelper.hxx>
32 
33 #include <o3tl/safeint.hxx>
34 #include <svl/sharedstringpool.hxx>
35 #include <sal/log.hxx>
36 #include <tools/stream.hxx>
37 
38 #include <numeric>
39 #include <vector>
40 #include <cassert>
41 
42 bool ScColumn::IsMerged( SCROW nRow ) const
43 {
44  return pAttrArray->IsMerged(nRow);
45 }
46 
48  SCROW nRow1, SCROW nRow2, SCROW* pRow1 ) const
49 {
50  sc::CellStoreType::const_position_type aPos = maCells.position(nRow1);
51  sc::CellStoreType::const_iterator it = aPos.first;
52  size_t nOffset = aPos.second;
53  SCROW nRow = nRow1;
54  bool bHasOne = false; // whether or not we have found a non-empty block of size one.
55 
56  for (; it != maCells.end() && nRow <= nRow2; ++it)
57  {
58  if (it->type != sc::element_type_empty)
59  {
60  // non-empty block found.
61  assert(it->size > 0); // mtv should never contain a block of zero length.
62  size_t nSize = it->size - nOffset;
63 
64  SCROW nLastRow = nRow + nSize - 1;
65  if (nLastRow > nRow2)
66  // shrink the size to avoid exceeding the specified last row position.
67  nSize -= nLastRow - nRow2;
68 
69  if (nSize == 1)
70  {
71  // this block is of size one.
72  if (bHasOne)
74 
75  bHasOne = true;
76  if (pRow1)
77  *pRow1 = nRow;
78  }
79  else
80  {
81  // size of this block is greater than one.
82  if (pRow1)
83  *pRow1 = nRow;
85  }
86  }
87 
88  nRow += it->size - nOffset;
89  nOffset = 0;
90  }
91 
93 }
94 
96  sc::CopyFromClipContext& rCxt, const ScColumn& rClipCol, sc::ColumnSpanSet& rBroadcastSpans )
97 {
98  ScDocument& rDocument = GetDoc();
100  if (!rDocument.ValidRow(aRange.mnRow1) || !rDocument.ValidRow(aRange.mnRow2))
101  return;
102 
103  ScRange aClipRange = rCxt.getClipDoc()->GetClipParam().getWholeRange();
104  SCROW nClipRow1 = aClipRange.aStart.Row();
105  SCROW nClipRow2 = aClipRange.aEnd.Row();
106  SCROW nClipRowLen = nClipRow2 - nClipRow1 + 1;
107 
108  // Check for non-empty cell ranges in the clip column.
109  sc::SingleColumnSpanSet aSpanSet(GetDoc().GetSheetLimits());
110  aSpanSet.scan(rClipCol, nClipRow1, nClipRow2);
112  aSpanSet.getSpans(aSpans);
113 
114  if (aSpans.empty())
115  // All cells in the range in the clip are empty. Nothing to delete.
116  return;
117 
118  // Translate the clip column spans into the destination column, and repeat as needed.
119  std::vector<sc::RowSpan> aDestSpans;
120  SCROW nDestOffset = aRange.mnRow1 - nClipRow1;
121  bool bContinue = true;
122  while (bContinue)
123  {
124  for (const sc::RowSpan& r : aSpans)
125  {
126  SCROW nDestRow1 = r.mnRow1 + nDestOffset;
127  SCROW nDestRow2 = r.mnRow2 + nDestOffset;
128 
129  if (nDestRow1 > aRange.mnRow2)
130  {
131  // We're done.
132  bContinue = false;
133  break;
134  }
135 
136  if (nDestRow2 > aRange.mnRow2)
137  {
138  // Truncate this range, and set it as the last span.
139  nDestRow2 = aRange.mnRow2;
140  bContinue = false;
141  }
142 
143  aDestSpans.emplace_back(nDestRow1, nDestRow2);
144 
145  if (!bContinue)
146  break;
147  }
148 
149  nDestOffset += nClipRowLen;
150  }
151 
152  InsertDeleteFlags nDelFlag = rCxt.getDeleteFlag();
153  sc::ColumnBlockPosition aBlockPos;
154  InitBlockPosition(aBlockPos);
155 
156  for (const auto& rDestSpan : aDestSpans)
157  {
158  SCROW nRow1 = rDestSpan.mnRow1;
159  SCROW nRow2 = rDestSpan.mnRow2;
160 
161  if (nDelFlag & InsertDeleteFlags::CONTENTS)
162  {
163  sc::SingleColumnSpanSet aDeletedRows(GetDoc().GetSheetLimits());
164  DeleteCells(aBlockPos, nRow1, nRow2, nDelFlag, aDeletedRows);
165  rBroadcastSpans.set(GetDoc(), nTab, nCol, aDeletedRows, true);
166  }
167 
168  if (nDelFlag & InsertDeleteFlags::NOTE)
169  DeleteCellNotes(aBlockPos, nRow1, nRow2, false);
170 
171  if (nDelFlag & InsertDeleteFlags::EDITATTR)
172  RemoveEditAttribs(nRow1, nRow2);
173 
174  // Delete attributes just now
175  if (nDelFlag & InsertDeleteFlags::ATTRIB)
176  {
177  pAttrArray->DeleteArea(nRow1, nRow2);
178 
179  if (rCxt.isTableProtected())
180  {
181  ScPatternAttr aPattern(rDocument.GetPool());
182  aPattern.GetItemSet().Put(ScProtectionAttr(false));
183  ApplyPatternArea(nRow1, nRow2, aPattern);
184  }
185 
186  ScConditionalFormatList* pCondList = rCxt.getCondFormatList();
187  if (pCondList)
188  pCondList->DeleteArea(nCol, nRow1, nCol, nRow2);
189  }
190  else if ((nDelFlag & InsertDeleteFlags::HARDATTR) == InsertDeleteFlags::HARDATTR)
191  pAttrArray->DeleteHardAttr(nRow1, nRow2);
192  }
193 }
194 
195 void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, size_t nColOffset )
196 {
197  assert(nRow1 <= nRow2);
198 
199  size_t nDestSize = nRow2 - nRow1 + 1;
201  if (!pBlockPos)
202  return;
203 
204  ScDocument& rDocument = GetDoc();
205  bool bSameDocPool = (rCxt.getClipDoc()->GetPool() == rDocument.GetPool());
206 
207  ScCellValue& rSrcCell = rCxt.getSingleCell(nColOffset);
208  sc::CellTextAttr& rSrcAttr = rCxt.getSingleCellAttr(nColOffset);
209 
210  InsertDeleteFlags nFlags = rCxt.getInsertFlag();
211 
213  {
214  if (!rCxt.isSkipAttrForEmptyCells() || rSrcCell.meType != CELLTYPE_NONE)
215  {
216  const ScPatternAttr* pAttr = (bSameDocPool ? rCxt.getSingleCellPattern(nColOffset) :
217  rCxt.getSingleCellPattern(nColOffset)->PutInPool( &rDocument, rCxt.getClipDoc()));
218 
219  auto pNewPattern = std::make_unique<ScPatternAttr>(*pAttr);
220  sal_uInt16 pItems[2];
221  pItems[0] = ATTR_CONDITIONAL;
222  pItems[1] = 0;
223  pNewPattern->ClearItems(pItems);
224  pAttrArray->SetPatternArea(nRow1, nRow2, std::move(pNewPattern), true);
225  }
226  }
227 
229  {
230  std::vector<sc::CellTextAttr> aTextAttrs(nDestSize, rSrcAttr);
231 
232  switch (rSrcCell.meType)
233  {
234  case CELLTYPE_VALUE:
235  {
236  std::vector<double> aVals(nDestSize, rSrcCell.mfValue);
237  pBlockPos->miCellPos =
238  maCells.set(pBlockPos->miCellPos, nRow1, aVals.begin(), aVals.end());
239  pBlockPos->miCellTextAttrPos =
240  maCellTextAttrs.set(pBlockPos->miCellTextAttrPos, nRow1, aTextAttrs.begin(), aTextAttrs.end());
242  }
243  break;
244  case CELLTYPE_STRING:
245  {
246  // Compare the ScDocumentPool* to determine if we are copying within the
247  // same document. If not, re-intern shared strings.
248  svl::SharedStringPool* pSharedStringPool = (bSameDocPool ? nullptr : &rDocument.GetSharedStringPool());
249  svl::SharedString aStr = (pSharedStringPool ?
250  pSharedStringPool->intern( rSrcCell.mpString->getString()) :
251  *rSrcCell.mpString);
252 
253  std::vector<svl::SharedString> aStrs(nDestSize, aStr);
254  pBlockPos->miCellPos =
255  maCells.set(pBlockPos->miCellPos, nRow1, aStrs.begin(), aStrs.end());
256  pBlockPos->miCellTextAttrPos =
257  maCellTextAttrs.set(pBlockPos->miCellTextAttrPos, nRow1, aTextAttrs.begin(), aTextAttrs.end());
259  }
260  break;
261  case CELLTYPE_EDIT:
262  {
263  std::vector<EditTextObject*> aStrs;
264  aStrs.reserve(nDestSize);
265  for (size_t i = 0; i < nDestSize; ++i)
266  aStrs.push_back(rSrcCell.mpEditText->Clone().release());
267 
268  pBlockPos->miCellPos =
269  maCells.set(pBlockPos->miCellPos, nRow1, aStrs.begin(), aStrs.end());
270  pBlockPos->miCellTextAttrPos =
271  maCellTextAttrs.set(pBlockPos->miCellTextAttrPos, nRow1, aTextAttrs.begin(), aTextAttrs.end());
273  }
274  break;
275  case CELLTYPE_FORMULA:
276  {
277  std::vector<sc::RowSpan> aRanges;
278  aRanges.reserve(1);
279  aRanges.emplace_back(nRow1, nRow2);
280  CloneFormulaCell(*rSrcCell.mpFormula, rSrcAttr, aRanges);
281  }
282  break;
283  default:
284  ;
285  }
286  }
287 
288  const ScPostIt* pNote = rCxt.getSingleCellNote(nColOffset);
290  return;
291 
292  // Duplicate the cell note over the whole pasted range.
293 
294  ScDocument* pClipDoc = rCxt.getClipDoc();
295  const ScAddress aSrcPos = pClipDoc->GetClipParam().getWholeRange().aStart;
296  std::vector<ScPostIt*> aNotes;
297  ScAddress aDestPos(nCol, nRow1, nTab);
298  aNotes.reserve(nDestSize);
299  for (size_t i = 0; i < nDestSize; ++i)
300  {
301  bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE;
302  aNotes.push_back(pNote->Clone(aSrcPos, rDocument, aDestPos, bCloneCaption).release());
303  aDestPos.IncRow();
304  }
305 
306  pBlockPos->miCellNotePos =
307  maCellNotes.set(
308  pBlockPos->miCellNotePos, nRow1, aNotes.begin(), aNotes.end());
309 }
310 
311 void ScColumn::SetValues( const SCROW nRow, const std::vector<double>& rVals )
312 {
313  if (!GetDoc().ValidRow(nRow))
314  return;
315 
316  SCROW nLastRow = nRow + rVals.size() - 1;
317  if (nLastRow > GetDoc().MaxRow())
318  // Out of bound. Do nothing.
319  return;
320 
321  sc::CellStoreType::position_type aPos = maCells.position(nRow);
322  std::vector<SCROW> aNewSharedRows;
323  DetachFormulaCells(aPos, rVals.size(), &aNewSharedRows);
324 
325  maCells.set(nRow, rVals.begin(), rVals.end());
326  std::vector<sc::CellTextAttr> aDefaults(rVals.size());
327  maCellTextAttrs.set(nRow, aDefaults.begin(), aDefaults.end());
328 
330 
331  StartListeningUnshared( aNewSharedRows);
332 
333  std::vector<SCROW> aRows;
334  aRows.reserve(rVals.size());
335  for (SCROW i = nRow; i <= nLastRow; ++i)
336  aRows.push_back(i);
337 
338  BroadcastCells(aRows, SfxHintId::ScDataChanged);
339 }
340 
341 void ScColumn::TransferCellValuesTo( SCROW nRow, size_t nLen, sc::CellValues& rDest )
342 {
343  if (!GetDoc().ValidRow(nRow))
344  return;
345 
346  SCROW nLastRow = nRow + nLen - 1;
347  if (nLastRow > GetDoc().MaxRow())
348  // Out of bound. Do nothing.
349  return;
350 
351  sc::CellStoreType::position_type aPos = maCells.position(nRow);
352  DetachFormulaCells(aPos, nLen, nullptr);
353 
354  rDest.transferFrom(*this, nRow, nLen);
355 
357 
358  std::vector<SCROW> aRows;
359  aRows.reserve(nLen);
360  for (SCROW i = nRow; i <= nLastRow; ++i)
361  aRows.push_back(i);
362 
363  BroadcastCells(aRows, SfxHintId::ScDataChanged);
364 }
365 
367 {
368  if (!GetDoc().ValidRow(nRow))
369  return;
370 
371  SCROW nLastRow = nRow + rSrc.size() - 1;
372  if (nLastRow > GetDoc().MaxRow())
373  // Out of bound. Do nothing
374  return;
375 
376  sc::CellStoreType::position_type aPos = maCells.position(nRow);
377  DetachFormulaCells(aPos, rSrc.size(), nullptr);
378 
379  rSrc.copyTo(*this, nRow);
380 
382 
383  std::vector<SCROW> aRows;
384  aRows.reserve(rSrc.size());
385  for (SCROW i = nRow; i <= nLastRow; ++i)
386  aRows.push_back(i);
387 
388  BroadcastCells(aRows, SfxHintId::ScDataChanged);
389 }
390 
391 namespace {
392 
393 class ConvertFormulaToValueHandler
394 {
395  sc::CellValues maResValues;
396  bool mbModified;
397 
398 public:
399  ConvertFormulaToValueHandler(ScSheetLimits const & rSheetLimits) :
400  mbModified(false)
401  {
402  maResValues.reset(rSheetLimits.GetMaxRowCount());
403  }
404 
405  void operator() ( size_t nRow, const ScFormulaCell* pCell )
406  {
407  sc::FormulaResultValue aRes = pCell->GetResult();
408  switch (aRes.meType)
409  {
411  maResValues.setValue(nRow, aRes.mfValue);
412  break;
414  maResValues.setValue(nRow, aRes.maString);
415  break;
418  default:
419  maResValues.setValue(nRow, svl::SharedString::getEmptyString());
420  }
421 
422  mbModified = true;
423  }
424 
425  bool isModified() const { return mbModified; }
426 
427  sc::CellValues& getResValues() { return maResValues; }
428 };
429 
430 }
431 
433  sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2, sc::TableValues* pUndo )
434 {
435  if (!GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2) || nRow1 > nRow2)
436  return;
437 
438  std::vector<SCROW> aBounds;
439  aBounds.push_back(nRow1);
440  if (nRow2 < GetDoc().MaxRow()-1)
441  aBounds.push_back(nRow2+1);
442 
443  // Split formula cell groups at top and bottom boundaries (if applicable).
445 
446  // Parse all formulas within the range and store their results into temporary storage.
447  ConvertFormulaToValueHandler aFunc(GetDoc().GetSheetLimits());
448  sc::ParseFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
449  if (!aFunc.isModified())
450  // No formula cells encountered.
451  return;
452 
453  DetachFormulaCells(rCxt, nRow1, nRow2, nullptr);
454 
455  // Undo storage to hold static values which will get swapped to the cell storage later.
456  sc::CellValues aUndoCells;
457  aFunc.getResValues().swap(aUndoCells);
458  aUndoCells.swapNonEmpty(*this);
459  if (pUndo)
460  pUndo->swap(nTab, nCol, aUndoCells);
461 }
462 
463 namespace {
464 
465 class StartListeningHandler
466 {
468 
469 public:
470  explicit StartListeningHandler( sc::StartListeningContext& rCxt ) :
471  mrCxt(rCxt) {}
472 
473  void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
474  {
475  pCell->StartListeningTo(mrCxt);
476  }
477 };
478 
479 class EndListeningHandler
480 {
482 
483 public:
484  explicit EndListeningHandler( sc::EndListeningContext& rCxt ) :
485  mrCxt(rCxt) {}
486 
487  void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
488  {
489  pCell->EndListeningTo(mrCxt);
490  }
491 };
492 
493 }
494 
496  sc::TableValues& rValues, sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt )
497 {
498  const ScRange& rRange = rValues.getRange();
499  std::vector<SCROW> aBounds;
500  aBounds.push_back(rRange.aStart.Row());
501  if (rRange.aEnd.Row() < GetDoc().MaxRow()-1)
502  aBounds.push_back(rRange.aEnd.Row()+1);
503 
504  // Split formula cell groups at top and bottom boundaries (if applicable).
506  std::vector<sc::CellValueSpan> aSpans = rValues.getNonEmptySpans(nTab, nCol);
507 
508  // Detach formula cells within the spans (if any).
509  EndListeningHandler aEndLisFunc(rEndCxt);
510  sc::CellStoreType::iterator itPos = maCells.begin();
511  for (const auto& rSpan : aSpans)
512  {
513  SCROW nRow1 = rSpan.mnRow1;
514  SCROW nRow2 = rSpan.mnRow2;
515  itPos = sc::ProcessFormula(itPos, maCells, nRow1, nRow2, aEndLisFunc);
516  }
517 
518  rValues.swapNonEmpty(nTab, nCol, *this);
520 
521  // Attach formula cells within the spans (if any).
522  StartListeningHandler aStartLisFunc(rStartCxt);
523  itPos = maCells.begin();
524  for (const auto& rSpan : aSpans)
525  {
526  SCROW nRow1 = rSpan.mnRow1;
527  SCROW nRow2 = rSpan.mnRow2;
528  itPos = sc::ProcessFormula(itPos, maCells, nRow1, nRow2, aStartLisFunc);
529  }
530 
532 }
533 
534 void ScColumn::DeleteRanges( const std::vector<sc::RowSpan>& rRanges, InsertDeleteFlags nDelFlag )
535 {
536  for (const auto& rSpan : rRanges)
537  DeleteArea(rSpan.mnRow1, rSpan.mnRow2, nDelFlag, false/*bBroadcast*/);
538 }
539 
541  const ScFormulaCell& rSrc, const sc::CellTextAttr& rAttr,
542  const std::vector<sc::RowSpan>& rRanges )
543 {
544  sc::CellStoreType::iterator itPos = maCells.begin();
545  sc::CellTextAttrStoreType::iterator itAttrPos = maCellTextAttrs.begin();
546 
547  SCCOL nMatrixCols = 0;
548  SCROW nMatrixRows = 0;
549  ScMatrixMode nMatrixFlag = rSrc.GetMatrixFlag();
550  if (nMatrixFlag == ScMatrixMode::Formula)
551  {
552  rSrc.GetMatColsRows( nMatrixCols, nMatrixRows);
553  SAL_WARN_IF( nMatrixCols != 1 || nMatrixRows != 1, "sc.core",
554  "ScColumn::CloneFormulaCell - cloning array/matrix with not exactly one column or row as single cell");
555  }
556 
557  ScDocument& rDocument = GetDoc();
558  std::vector<ScFormulaCell*> aFormulas;
559  for (const auto& rSpan : rRanges)
560  {
561  SCROW nRow1 = rSpan.mnRow1, nRow2 = rSpan.mnRow2;
562  size_t nLen = nRow2 - nRow1 + 1;
563  assert(nLen > 0);
564  aFormulas.clear();
565  aFormulas.reserve(nLen);
566 
567  ScAddress aPos(nCol, nRow1, nTab);
568 
569  if (nLen == 1)
570  {
571  // Single, ungrouped formula cell.
572  ScFormulaCell* pCell = new ScFormulaCell(rSrc, rDocument, aPos);
573  aFormulas.push_back(pCell);
574  }
575  else
576  {
577  // Create a group of formula cells.
579  xGroup->setCode(*rSrc.GetCode());
580  xGroup->compileCode(rDocument, aPos, rDocument.GetGrammar());
581  for (size_t i = 0; i < nLen; ++i, aPos.IncRow())
582  {
583  ScFormulaCell* pCell = new ScFormulaCell(rDocument, aPos, xGroup, rDocument.GetGrammar(), nMatrixFlag);
584  if (nMatrixFlag == ScMatrixMode::Formula)
585  pCell->SetMatColsRows( nMatrixCols, nMatrixRows);
586  if (i == 0)
587  {
588  xGroup->mpTopCell = pCell;
589  xGroup->mnLength = nLen;
590  }
591  aFormulas.push_back(pCell);
592  }
593  }
594 
595  itPos = maCells.set(itPos, nRow1, aFormulas.begin(), aFormulas.end());
596 
597  // Join the top and bottom of the pasted formula cells as needed.
598  sc::CellStoreType::position_type aPosObj = maCells.position(itPos, nRow1);
599 
600  assert(aPosObj.first->type == sc::element_type_formula);
601  ScFormulaCell* pCell = sc::formula_block::at(*aPosObj.first->data, aPosObj.second);
602  JoinNewFormulaCell(aPosObj, *pCell);
603 
604  aPosObj = maCells.position(aPosObj.first, nRow2);
605  assert(aPosObj.first->type == sc::element_type_formula);
606  pCell = sc::formula_block::at(*aPosObj.first->data, aPosObj.second);
607  JoinNewFormulaCell(aPosObj, *pCell);
608 
609  std::vector<sc::CellTextAttr> aTextAttrs(nLen, rAttr);
610  itAttrPos = maCellTextAttrs.set(itAttrPos, nRow1, aTextAttrs.begin(), aTextAttrs.end());
611  }
612 
614 }
615 
616 std::unique_ptr<ScPostIt> ScColumn::ReleaseNote( SCROW nRow )
617 {
618  if (!GetDoc().ValidRow(nRow))
619  return nullptr;
620 
621  ScPostIt* p = nullptr;
622  maCellNotes.release(nRow, p);
623  return std::unique_ptr<ScPostIt>(p);
624 }
625 
627 {
628  return std::accumulate(maCellNotes.begin(), maCellNotes.end(), size_t(0),
629  [](const size_t& rCount, const auto& rCellNote) {
630  if (rCellNote.type != sc::element_type_cellnote)
631  return rCount;
632  return rCount + rCellNote.size;
633  });
634 }
635 
636 namespace {
637 
638 class NoteCaptionCreator
639 {
640  ScAddress maPos;
641 public:
642  NoteCaptionCreator( SCTAB nTab, SCCOL nCol ) : maPos(nCol,0,nTab) {}
643 
644  void operator() ( size_t nRow, const ScPostIt* p )
645  {
646  maPos.SetRow(nRow);
647  p->GetOrCreateCaption(maPos);
648  }
649 };
650 
651 class NoteCaptionCleaner
652 {
653  bool mbPreserveData;
654 public:
655  explicit NoteCaptionCleaner( bool bPreserveData ) : mbPreserveData(bPreserveData) {}
656 
657  void operator() ( size_t /*nRow*/, ScPostIt* p )
658  {
659  p->ForgetCaption(mbPreserveData);
660  }
661 };
662 
663 }
664 
666 {
667  NoteCaptionCreator aFunc(nTab, nCol);
669 }
670 
671 void ScColumn::ForgetNoteCaptions( SCROW nRow1, SCROW nRow2, bool bPreserveData )
672 {
673  if (maCellNotes.empty())
674  return;
675 
676  if (!GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2))
677  return;
678 
679  NoteCaptionCleaner aFunc(bPreserveData);
680  sc::CellNoteStoreType::iterator it = maCellNotes.begin();
681  sc::ProcessNote(it, maCellNotes, nRow1, nRow2, aFunc);
682 }
683 
684 SCROW ScColumn::GetNotePosition( size_t nIndex ) const
685 {
686  // Return the row position of the nth note in the column.
687 
688  size_t nCount = 0; // Number of notes encountered so far.
689  for (const auto& rCellNote : maCellNotes)
690  {
691  if (rCellNote.type != sc::element_type_cellnote)
692  // Skip the empty blocks.
693  continue;
694 
695  if (nIndex < nCount + rCellNote.size)
696  {
697  // Index falls within this block.
698  size_t nOffset = nIndex - nCount;
699  return rCellNote.position + nOffset;
700  }
701 
702  nCount += rCellNote.size;
703  }
704 
705  return -1;
706 }
707 
708 namespace {
709 
710 class NoteEntryCollector
711 {
712  std::vector<sc::NoteEntry>& mrNotes;
713  SCTAB mnTab;
714  SCCOL mnCol;
715  SCROW mnStartRow;
716  SCROW mnEndRow;
717 public:
718  NoteEntryCollector( std::vector<sc::NoteEntry>& rNotes, SCTAB nTab, SCCOL nCol,
719  SCROW nStartRow, SCROW nEndRow) :
720  mrNotes(rNotes), mnTab(nTab), mnCol(nCol),
721  mnStartRow(nStartRow), mnEndRow(nEndRow) {}
722 
723  void operator() (const sc::CellNoteStoreType::value_type& node) const
724  {
725  if (node.type != sc::element_type_cellnote)
726  return;
727 
728  size_t nTopRow = node.position;
729  sc::cellnote_block::const_iterator it = sc::cellnote_block::begin(*node.data);
730  sc::cellnote_block::const_iterator itEnd = sc::cellnote_block::end(*node.data);
731  size_t nOffset = 0;
732  if(nTopRow < o3tl::make_unsigned(mnStartRow))
733  {
734  std::advance(it, mnStartRow - nTopRow);
735  nOffset = mnStartRow - nTopRow;
736  }
737 
738  for (; it != itEnd && nTopRow + nOffset <= o3tl::make_unsigned(mnEndRow);
739  ++it, ++nOffset)
740  {
741  ScAddress aPos(mnCol, nTopRow + nOffset, mnTab);
742  mrNotes.emplace_back(aPos, *it);
743  }
744  }
745 };
746 
747 }
748 
749 void ScColumn::GetAllNoteEntries( std::vector<sc::NoteEntry>& rNotes ) const
750 {
751  std::for_each(maCellNotes.begin(), maCellNotes.end(), NoteEntryCollector(rNotes, nTab, nCol, 0, GetDoc().MaxRow()));
752 }
753 
754 void ScColumn::GetNotesInRange(SCROW nStartRow, SCROW nEndRow,
755  std::vector<sc::NoteEntry>& rNotes ) const
756 {
757  std::pair<sc::CellNoteStoreType::const_iterator,size_t> aPos = maCellNotes.position(nStartRow);
758  sc::CellNoteStoreType::const_iterator it = aPos.first;
759  if (it == maCellNotes.end())
760  // Invalid row number.
761  return;
762 
763  std::pair<sc::CellNoteStoreType::const_iterator,size_t> aEndPos =
764  maCellNotes.position(nEndRow);
765  sc::CellNoteStoreType::const_iterator itEnd = aEndPos.first;
766 
767  std::for_each(it, ++itEnd, NoteEntryCollector(rNotes, nTab, nCol, nStartRow, nEndRow));
768 }
769 
770 bool ScColumn::HasCellNote(SCROW nStartRow, SCROW nEndRow) const
771 {
772  std::pair<sc::CellNoteStoreType::const_iterator,size_t> aStartPos =
773  maCellNotes.position(nStartRow);
774  if (aStartPos.first == maCellNotes.end())
775  // Invalid row number.
776  return false;
777 
778  std::pair<sc::CellNoteStoreType::const_iterator,size_t> aEndPos =
779  maCellNotes.position(nEndRow);
780 
781  for (sc::CellNoteStoreType::const_iterator it = aStartPos.first; it != aEndPos.first; ++it)
782  {
783  if (it->type != sc::element_type_cellnote)
784  continue;
785  size_t nTopRow = it->position;
786  sc::cellnote_block::const_iterator blockIt = sc::cellnote_block::begin(*(it->data));
787  sc::cellnote_block::const_iterator blockItEnd = sc::cellnote_block::end(*(it->data));
788  size_t nOffset = 0;
789  if(nTopRow < o3tl::make_unsigned(nStartRow))
790  {
791  std::advance(blockIt, nStartRow - nTopRow);
792  nOffset = nStartRow - nTopRow;
793  }
794 
795  if (blockIt != blockItEnd && nTopRow + nOffset <= o3tl::make_unsigned(nEndRow))
796  return true;
797  }
798 
799  return false;
800 }
801 
802 void ScColumn::GetUnprotectedCells( SCROW nStartRow, SCROW nEndRow, ScRangeList& rRangeList ) const
803 {
804  SCROW nTmpStartRow = nStartRow, nTmpEndRow = nEndRow;
805  const ScPatternAttr* pPattern = pAttrArray->GetPatternRange(nTmpStartRow, nTmpEndRow, nStartRow);
806  bool bProtection = pPattern->GetItem(ATTR_PROTECTION).GetProtection();
807  if (!bProtection)
808  {
809  // Limit the span to the range in question.
810  if (nTmpStartRow < nStartRow)
811  nTmpStartRow = nStartRow;
812  if (nTmpEndRow > nEndRow)
813  nTmpEndRow = nEndRow;
814  rRangeList.Join( ScRange( nCol, nTmpStartRow, nTab, nCol, nTmpEndRow, nTab));
815  }
816  while (nEndRow > nTmpEndRow)
817  {
818  nStartRow = nTmpEndRow + 1;
819  pPattern = pAttrArray->GetPatternRange(nTmpStartRow, nTmpEndRow, nStartRow);
820  bool bTmpProtection = pPattern->GetItem(ATTR_PROTECTION).GetProtection();
821  if (!bTmpProtection)
822  {
823  // Limit the span to the range in question.
824  // Only end row needs to be checked as we enter here only for spans
825  // below the original nStartRow.
826  if (nTmpEndRow > nEndRow)
827  nTmpEndRow = nEndRow;
828  rRangeList.Join( ScRange( nCol, nTmpStartRow, nTab, nCol, nTmpEndRow, nTab));
829  }
830  }
831 }
832 
833 namespace {
834 
835 class RecompileByOpcodeHandler
836 {
837  ScDocument* mpDoc;
838  const formula::unordered_opcode_set& mrOps;
839  sc::EndListeningContext& mrEndListenCxt;
840  sc::CompileFormulaContext& mrCompileFormulaCxt;
841 
842 public:
843  RecompileByOpcodeHandler(
844  ScDocument* pDoc, const formula::unordered_opcode_set& rOps,
845  sc::EndListeningContext& rEndListenCxt, sc::CompileFormulaContext& rCompileCxt ) :
846  mpDoc(pDoc),
847  mrOps(rOps),
848  mrEndListenCxt(rEndListenCxt),
849  mrCompileFormulaCxt(rCompileCxt) {}
850 
851  void operator() ( sc::FormulaGroupEntry& rEntry )
852  {
853  // Perform end listening, remove from formula tree, and set them up
854  // for re-compilation.
855 
856  ScFormulaCell* pTop = nullptr;
857 
858  if (rEntry.mbShared)
859  {
860  // Only inspect the code from the top cell.
861  pTop = *rEntry.mpCells;
862  }
863  else
864  pTop = rEntry.mpCell;
865 
866  ScTokenArray* pCode = pTop->GetCode();
867  bool bRecompile = pCode->HasOpCodes(mrOps);
868 
869  if (!bRecompile)
870  return;
871 
872  // Get the formula string.
873  OUString aFormula = pTop->GetFormula(mrCompileFormulaCxt);
874  sal_Int32 n = aFormula.getLength();
875  if (pTop->GetMatrixFlag() != ScMatrixMode::NONE && n > 0)
876  {
877  if (aFormula[0] == '{' && aFormula[n-1] == '}')
878  aFormula = aFormula.copy(1, n-2);
879  }
880 
881  if (rEntry.mbShared)
882  {
883  ScFormulaCell** pp = rEntry.mpCells;
884  ScFormulaCell** ppEnd = pp + rEntry.mnLength;
885  for (; pp != ppEnd; ++pp)
886  {
887  ScFormulaCell* p = *pp;
888  p->EndListeningTo(mrEndListenCxt);
889  mpDoc->RemoveFromFormulaTree(p);
890  }
891  }
892  else
893  {
894  rEntry.mpCell->EndListeningTo(mrEndListenCxt);
895  mpDoc->RemoveFromFormulaTree(rEntry.mpCell);
896  }
897 
898  pCode->Clear();
899  pTop->SetHybridFormula(aFormula, mpDoc->GetGrammar());
900  }
901 };
902 
903 class CompileHybridFormulaHandler
904 {
905  ScDocument& mrDoc;
906  sc::StartListeningContext& mrStartListenCxt;
907  sc::CompileFormulaContext& mrCompileFormulaCxt;
908 
909 public:
910  CompileHybridFormulaHandler(ScDocument& rDoc, sc::StartListeningContext& rStartListenCxt, sc::CompileFormulaContext& rCompileCxt ) :
911  mrDoc(rDoc),
912  mrStartListenCxt(rStartListenCxt),
913  mrCompileFormulaCxt(rCompileCxt) {}
914 
915  void operator() ( sc::FormulaGroupEntry& rEntry )
916  {
917  if (rEntry.mbShared)
918  {
919  ScFormulaCell* pTop = *rEntry.mpCells;
920  OUString aFormula = pTop->GetHybridFormula();
921 
922  if (!aFormula.isEmpty())
923  {
924  // Create a new token array from the hybrid formula string, and
925  // set it to the group.
926  ScCompiler aComp(mrCompileFormulaCxt, pTop->aPos);
927  std::unique_ptr<ScTokenArray> pNewCode = aComp.CompileString(aFormula);
928  ScFormulaCellGroupRef xGroup = pTop->GetCellGroup();
929  assert(xGroup);
930  xGroup->setCode(std::move(pNewCode));
931  xGroup->compileCode(mrDoc, pTop->aPos, mrDoc.GetGrammar());
932 
933  // Propagate the new token array to all formula cells in the group.
934  ScFormulaCell** pp = rEntry.mpCells;
935  ScFormulaCell** ppEnd = pp + rEntry.mnLength;
936  for (; pp != ppEnd; ++pp)
937  {
938  ScFormulaCell* p = *pp;
939  p->SyncSharedCode();
940  p->StartListeningTo(mrStartListenCxt);
941  p->SetDirty();
942  }
943  }
944  }
945  else
946  {
947  ScFormulaCell* pCell = rEntry.mpCell;
948  OUString aFormula = pCell->GetHybridFormula();
949 
950  if (!aFormula.isEmpty())
951  {
952  // Create token array from formula string.
953  ScCompiler aComp(mrCompileFormulaCxt, pCell->aPos);
954  std::unique_ptr<ScTokenArray> pNewCode = aComp.CompileString(aFormula);
955 
956  // Generate RPN tokens.
957  ScCompiler aComp2(mrDoc, pCell->aPos, *pNewCode, formula::FormulaGrammar::GRAM_UNSPECIFIED,
958  true, pCell->GetMatrixFlag() != ScMatrixMode::NONE);
959  aComp2.CompileTokenArray();
960 
961  pCell->SetCode(std::move(pNewCode));
962  pCell->StartListeningTo(mrStartListenCxt);
963  pCell->SetDirty();
964  }
965  }
966  }
967 };
968 
969 }
970 
972  sc::EndListeningContext& rEndListenCxt, sc::CompileFormulaContext& rCompileCxt )
973 {
974  // Collect all formula groups.
975  std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries();
976 
978  aOps.insert(ocBad);
979  aOps.insert(ocColRowName);
980  aOps.insert(ocName);
981  RecompileByOpcodeHandler aFunc(&GetDoc(), aOps, rEndListenCxt, rCompileCxt);
982  std::for_each(aGroups.begin(), aGroups.end(), aFunc);
983 }
984 
986  sc::EndListeningContext& rEndListenCxt, sc::CompileFormulaContext& rCompileCxt )
987 {
988  // Collect all formula groups.
989  std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries();
990 
992  aOps.insert(ocBad);
993  aOps.insert(ocColRowName);
994  aOps.insert(ocDBArea);
995  aOps.insert(ocTableRef);
996  RecompileByOpcodeHandler aFunc(&GetDoc(), aOps, rEndListenCxt, rCompileCxt);
997  std::for_each(aGroups.begin(), aGroups.end(), aFunc);
998 }
999 
1001  sc::StartListeningContext& rStartListenCxt, sc::CompileFormulaContext& rCompileCxt )
1002 {
1003  // Collect all formula groups.
1004  std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries();
1005 
1006  CompileHybridFormulaHandler aFunc(GetDoc(), rStartListenCxt, rCompileCxt);
1007  std::for_each(aGroups.begin(), aGroups.end(), aFunc);
1008 }
1009 
1010 namespace {
1011 
1012 class ScriptTypeUpdater
1013 {
1014  ScColumn& mrCol;
1015  sc::CellTextAttrStoreType& mrTextAttrs;
1016  sc::CellTextAttrStoreType::iterator miPosAttr;
1017  ScConditionalFormatList* mpCFList;
1018  SvNumberFormatter* mpFormatter;
1019  ScAddress maPos;
1020  bool mbUpdated;
1021 
1022 private:
1023  void updateScriptType( size_t nRow, ScRefCellValue& rCell )
1024  {
1025  sc::CellTextAttrStoreType::position_type aAttrPos = mrTextAttrs.position(miPosAttr, nRow);
1026  miPosAttr = aAttrPos.first;
1027 
1028  if (aAttrPos.first->type != sc::element_type_celltextattr)
1029  return;
1030 
1031  sc::CellTextAttr& rAttr = sc::celltextattr_block::at(*aAttrPos.first->data, aAttrPos.second);
1032  if (rAttr.mnScriptType != SvtScriptType::UNKNOWN)
1033  // Script type already determined. Skip it.
1034  return;
1035 
1036  const ScPatternAttr* pPat = mrCol.GetPattern(nRow);
1037  if (!pPat)
1038  // In theory this should never return NULL. But let's be safe.
1039  return;
1040 
1041  const SfxItemSet* pCondSet = nullptr;
1042  if (mpCFList)
1043  {
1044  maPos.SetRow(nRow);
1045  const ScCondFormatItem& rItem = pPat->GetItem(ATTR_CONDITIONAL);
1046  const ScCondFormatIndexes& rData = rItem.GetCondFormatData();
1047  pCondSet = mrCol.GetDoc().GetCondResult(rCell, maPos, *mpCFList, rData);
1048  }
1049 
1050  OUString aStr;
1051  const Color* pColor;
1052  sal_uInt32 nFormat = pPat->GetNumberFormat(mpFormatter, pCondSet);
1053  ScCellFormat::GetString(rCell, nFormat, aStr, &pColor, *mpFormatter, mrCol.GetDoc());
1054 
1055  rAttr.mnScriptType = mrCol.GetDoc().GetStringScriptType(aStr);
1056  mbUpdated = true;
1057  }
1058 
1059 public:
1060  explicit ScriptTypeUpdater( ScColumn& rCol ) :
1061  mrCol(rCol),
1062  mrTextAttrs(rCol.GetCellAttrStore()),
1063  miPosAttr(mrTextAttrs.begin()),
1064  mpCFList(rCol.GetDoc().GetCondFormList(rCol.GetTab())),
1065  mpFormatter(rCol.GetDoc().GetFormatTable()),
1066  maPos(rCol.GetCol(), 0, rCol.GetTab()),
1067  mbUpdated(false)
1068  {}
1069 
1070  void operator() ( size_t nRow, double fVal )
1071  {
1072  ScRefCellValue aCell(fVal);
1073  updateScriptType(nRow, aCell);
1074  }
1075 
1076  void operator() ( size_t nRow, const svl::SharedString& rStr )
1077  {
1078  ScRefCellValue aCell(&rStr);
1079  updateScriptType(nRow, aCell);
1080  }
1081 
1082  void operator() ( size_t nRow, const EditTextObject* pText )
1083  {
1084  ScRefCellValue aCell(pText);
1085  updateScriptType(nRow, aCell);
1086  }
1087 
1088  void operator() ( size_t nRow, const ScFormulaCell* pCell )
1089  {
1090  ScRefCellValue aCell(const_cast<ScFormulaCell*>(pCell));
1091  updateScriptType(nRow, aCell);
1092  }
1093 
1094  bool isUpdated() const { return mbUpdated; }
1095 };
1096 
1097 }
1098 
1100 {
1101  if (!GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2) || nRow1 > nRow2)
1102  return;
1103 
1104  ScriptTypeUpdater aFunc(*this);
1105  sc::ParseAllNonEmpty(maCells.begin(), maCells, nRow1, nRow2, aFunc);
1106  if (aFunc.isUpdated())
1108 }
1109 
1110 void ScColumn::Swap( ScColumn& rOther, SCROW nRow1, SCROW nRow2, bool bPattern )
1111 {
1112  maCells.swap(nRow1, nRow2, rOther.maCells, nRow1);
1113  maCellTextAttrs.swap(nRow1, nRow2, rOther.maCellTextAttrs, nRow1);
1114  maCellNotes.swap(nRow1, nRow2, rOther.maCellNotes, nRow1);
1115  maBroadcasters.swap(nRow1, nRow2, rOther.maBroadcasters, nRow1);
1116 
1117  // Update draw object anchors
1118  ScDrawLayer* pDrawLayer = GetDoc().GetDrawLayer();
1119  if (pDrawLayer)
1120  {
1121  std::map<SCROW, std::vector<SdrObject*>> aThisColRowDrawObjects
1122  = pDrawLayer->GetObjectsAnchoredToRange(GetTab(), GetCol(), nRow1, nRow2);
1123  std::map<SCROW, std::vector<SdrObject*>> aOtherColRowDrawObjects
1124  = pDrawLayer->GetObjectsAnchoredToRange(GetTab(), rOther.GetCol(), nRow1, nRow2);
1125  for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
1126  {
1127  std::vector<SdrObject*>& rThisCellDrawObjects = aThisColRowDrawObjects[nRow];
1128  if (!rThisCellDrawObjects.empty())
1129  UpdateDrawObjectsForRow(rThisCellDrawObjects, rOther.GetCol(), nRow);
1130  std::vector<SdrObject*>& rOtherCellDrawObjects = aOtherColRowDrawObjects[nRow];
1131  if (!rOtherCellDrawObjects.empty())
1132  rOther.UpdateDrawObjectsForRow(rOtherCellDrawObjects, GetCol(), nRow);
1133  }
1134  }
1135 
1136  if (bPattern)
1137  {
1138  for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
1139  {
1140  const ScPatternAttr* pPat1 = GetPattern(nRow);
1141  const ScPatternAttr* pPat2 = rOther.GetPattern(nRow);
1142  if (pPat1 != pPat2)
1143  {
1144  if (pPat1->GetRefCount() == 1)
1145  pPat1 = &rOther.GetDoc().GetPool()->Put(*pPat1);
1146  SetPattern(nRow, *pPat2);
1147  rOther.SetPattern(nRow, *pPat1);
1148  }
1149  }
1150  }
1151 
1153  rOther.CellStorageModified();
1154 }
1155 
1156 namespace {
1157 
1158 class FormulaColPosSetter
1159 {
1160  SCCOL mnCol;
1161  bool mbUpdateRefs;
1162 public:
1163  FormulaColPosSetter( SCCOL nCol, bool bUpdateRefs ) : mnCol(nCol), mbUpdateRefs(bUpdateRefs) {}
1164 
1165  void operator() ( size_t nRow, ScFormulaCell* pCell )
1166  {
1167  if (!pCell->IsShared() || pCell->IsSharedTop())
1168  {
1169  // Ensure that the references still point to the same locations
1170  // after the position change.
1171  ScAddress aOldPos = pCell->aPos;
1172  pCell->aPos.SetCol(mnCol);
1173  pCell->aPos.SetRow(nRow);
1174  if (mbUpdateRefs)
1175  pCell->GetCode()->AdjustReferenceOnMovedOrigin(aOldPos, pCell->aPos);
1176  else
1177  pCell->GetCode()->AdjustReferenceOnMovedOriginIfOtherSheet(aOldPos, pCell->aPos);
1178  }
1179  else
1180  {
1181  pCell->aPos.SetCol(mnCol);
1182  pCell->aPos.SetRow(nRow);
1183  }
1184  }
1185 };
1186 
1187 }
1188 
1189 void ScColumn::ResetFormulaCellPositions( SCROW nRow1, SCROW nRow2, bool bUpdateRefs )
1190 {
1191  FormulaColPosSetter aFunc(nCol, bUpdateRefs);
1192  sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
1193 }
1194 
1195 namespace {
1196 
1197 class RelativeRefBoundChecker
1198 {
1199  std::vector<SCROW> maBounds;
1200  ScRange maBoundRange;
1201 
1202 public:
1203  explicit RelativeRefBoundChecker( const ScRange& rBoundRange ) :
1204  maBoundRange(rBoundRange) {}
1205 
1206  void operator() ( size_t /*nRow*/, ScFormulaCell* pCell )
1207  {
1208  if (!pCell->IsSharedTop())
1209  return;
1210 
1212  pCell->aPos, pCell->GetSharedLength(), maBoundRange, maBounds);
1213  }
1214 
1215  void swapBounds( std::vector<SCROW>& rBounds )
1216  {
1217  rBounds.swap(maBounds);
1218  }
1219 };
1220 
1221 }
1222 
1224 {
1225  if (rBoundRange.aStart.Row() >= GetDoc().MaxRow())
1226  // Nothing to split.
1227  return;
1228 
1229  std::vector<SCROW> aBounds;
1230 
1231  // Cut at row boundaries first.
1232  aBounds.push_back(rBoundRange.aStart.Row());
1233  if (rBoundRange.aEnd.Row() < GetDoc().MaxRow())
1234  aBounds.push_back(rBoundRange.aEnd.Row()+1);
1236 
1237  RelativeRefBoundChecker aFunc(rBoundRange);
1239  maCells.begin(), maCells, rBoundRange.aStart.Row(), rBoundRange.aEnd.Row(), aFunc);
1240  aFunc.swapBounds(aBounds);
1242 }
1243 
1244 namespace {
1245 
1246 class ListenerCollector
1247 {
1248  std::vector<SvtListener*>& mrListeners;
1249 public:
1250  explicit ListenerCollector( std::vector<SvtListener*>& rListener ) :
1251  mrListeners(rListener) {}
1252 
1253  void operator() ( size_t /*nRow*/, SvtBroadcaster* p )
1254  {
1256  mrListeners.insert(mrListeners.end(), rLis.begin(), rLis.end());
1257  }
1258 };
1259 
1260 class FormulaCellCollector
1261 {
1262  std::vector<ScFormulaCell*>& mrCells;
1263 public:
1264  explicit FormulaCellCollector( std::vector<ScFormulaCell*>& rCells ) : mrCells(rCells) {}
1265 
1266  void operator() ( size_t /*nRow*/, ScFormulaCell* p )
1267  {
1268  mrCells.push_back(p);
1269  }
1270 };
1271 
1272 }
1273 
1274 void ScColumn::CollectListeners( std::vector<SvtListener*>& rListeners, SCROW nRow1, SCROW nRow2 )
1275 {
1276  if (nRow2 < nRow1 || !GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2))
1277  return;
1278 
1279  ListenerCollector aFunc(rListeners);
1280  sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFunc);
1281 }
1282 
1283 void ScColumn::CollectFormulaCells( std::vector<ScFormulaCell*>& rCells, SCROW nRow1, SCROW nRow2 )
1284 {
1285  if (nRow2 < nRow1 || !GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2))
1286  return;
1287 
1288  FormulaCellCollector aFunc(rCells);
1289  sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
1290 }
1291 
1293 {
1294  return mnBlkCountFormula != 0;
1295 }
1296 
1297 namespace {
1298 
1299 struct FindAnyFormula
1300 {
1301  bool operator() ( size_t /*nRow*/, const ScFormulaCell* /*pCell*/ ) const
1302  {
1303  return true;
1304  }
1305 };
1306 
1307 }
1308 
1309 bool ScColumn::HasFormulaCell( SCROW nRow1, SCROW nRow2 ) const
1310 {
1311  if (!mnBlkCountFormula)
1312  return false;
1313 
1314  if (nRow2 < nRow1 || !GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2))
1315  return false;
1316 
1317  if (nRow1 == 0 && nRow2 == GetDoc().MaxRow())
1318  return HasFormulaCell();
1319 
1320  FindAnyFormula aFunc;
1321  std::pair<sc::CellStoreType::const_iterator, size_t> aRet =
1322  sc::FindFormula(maCells, nRow1, nRow2, aFunc);
1323 
1324  return aRet.first != maCells.end();
1325 }
1326 
1327 namespace {
1328 
1329 void endListening( sc::EndListeningContext& rCxt, ScFormulaCell** pp, ScFormulaCell** ppEnd )
1330 {
1331  for (; pp != ppEnd; ++pp)
1332  {
1333  ScFormulaCell& rFC = **pp;
1334  rFC.EndListeningTo(rCxt);
1335  }
1336 }
1337 
1338 class StartListeningFormulaCellsHandler
1339 {
1340  sc::StartListeningContext& mrStartCxt;
1341  sc::EndListeningContext& mrEndCxt;
1342  SCROW mnStartRow;
1343 
1344 public:
1345  StartListeningFormulaCellsHandler( sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt ) :
1346  mrStartCxt(rStartCxt), mrEndCxt(rEndCxt), mnStartRow(-1) {}
1347 
1348  void operator() ( const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize )
1349  {
1350  if (node.type != sc::element_type_formula)
1351  // We are only interested in formulas.
1352  return;
1353 
1354  mnStartRow = node.position + nOffset;
1355 
1356  ScFormulaCell** ppBeg = &sc::formula_block::at(*node.data, nOffset);
1357  ScFormulaCell** ppEnd = ppBeg + nDataSize;
1358 
1359  ScFormulaCell** pp = ppBeg;
1360 
1361  // If the first formula cell belongs to a group and it's not the top
1362  // cell, move up to the top cell of the group, and have all the extra
1363  // formula cells stop listening.
1364 
1365  ScFormulaCell* pFC = *pp;
1366  if (pFC->IsShared() && !pFC->IsSharedTop())
1367  {
1368  SCROW nBackTrackSize = pFC->aPos.Row() - pFC->GetSharedTopRow();
1369  if (nBackTrackSize > 0)
1370  {
1371  assert(o3tl::make_unsigned(nBackTrackSize) <= nOffset);
1372  for (SCROW i = 0; i < nBackTrackSize; ++i)
1373  --pp;
1374  endListening(mrEndCxt, pp, ppBeg);
1375  mnStartRow -= nBackTrackSize;
1376  }
1377  }
1378 
1379  for (; pp != ppEnd; ++pp)
1380  {
1381  pFC = *pp;
1382 
1383  if (!pFC->IsSharedTop())
1384  {
1385  assert(!pFC->IsShared());
1386  pFC->StartListeningTo(mrStartCxt);
1387  continue;
1388  }
1389 
1390  // If This is the last group in the range, see if the group
1391  // extends beyond the range, in which case have the excess
1392  // formula cells stop listening.
1393  size_t nEndGroupPos = (pp - ppBeg) + pFC->GetSharedLength();
1394  if (nEndGroupPos > nDataSize)
1395  {
1396  size_t nExcessSize = nEndGroupPos - nDataSize;
1397  ScFormulaCell** ppGrpEnd = pp + pFC->GetSharedLength();
1398  ScFormulaCell** ppGrp = ppGrpEnd - nExcessSize;
1399  endListening(mrEndCxt, ppGrp, ppGrpEnd);
1400 
1401  // Register formula cells as a group.
1403  pp = ppEnd - 1; // Move to the one before the end position.
1404  }
1405  else
1406  {
1407  // Register formula cells as a group.
1409  pp += pFC->GetSharedLength() - 1; // Move to the last one in the group.
1410  }
1411  }
1412  }
1413 
1414 };
1415 
1416 class EndListeningFormulaCellsHandler
1417 {
1418  sc::EndListeningContext& mrEndCxt;
1419  SCROW mnStartRow;
1420  SCROW mnEndRow;
1421 
1422 public:
1423  explicit EndListeningFormulaCellsHandler( sc::EndListeningContext& rEndCxt ) :
1424  mrEndCxt(rEndCxt), mnStartRow(-1), mnEndRow(-1) {}
1425 
1426  void operator() ( const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize )
1427  {
1428  if (node.type != sc::element_type_formula)
1429  // We are only interested in formulas.
1430  return;
1431 
1432  mnStartRow = node.position + nOffset;
1433 
1434  ScFormulaCell** ppBeg = &sc::formula_block::at(*node.data, nOffset);
1435  ScFormulaCell** ppEnd = ppBeg + nDataSize;
1436 
1437  ScFormulaCell** pp = ppBeg;
1438 
1439  // If the first formula cell belongs to a group and it's not the top
1440  // cell, move up to the top cell of the group.
1441 
1442  ScFormulaCell* pFC = *pp;
1443  if (pFC->IsShared() && !pFC->IsSharedTop())
1444  {
1445  SCROW nBackTrackSize = pFC->aPos.Row() - pFC->GetSharedTopRow();
1446  if (nBackTrackSize > 0)
1447  {
1448  assert(o3tl::make_unsigned(nBackTrackSize) <= nOffset);
1449  for (SCROW i = 0; i < nBackTrackSize; ++i)
1450  --pp;
1451  mnStartRow -= nBackTrackSize;
1452  }
1453  }
1454 
1455  for (; pp != ppEnd; ++pp)
1456  {
1457  pFC = *pp;
1458 
1459  if (!pFC->IsSharedTop())
1460  {
1461  assert(!pFC->IsShared());
1462  pFC->EndListeningTo(mrEndCxt);
1463  continue;
1464  }
1465 
1466  size_t nEndGroupPos = (pp - ppBeg) + pFC->GetSharedLength();
1467  mnEndRow = node.position + nOffset + nEndGroupPos - 1; // absolute row position of the last one in the group.
1468 
1469  ScFormulaCell** ppGrpEnd = pp + pFC->GetSharedLength();
1470  endListening(mrEndCxt, pp, ppGrpEnd);
1471 
1472  if (nEndGroupPos > nDataSize)
1473  {
1474  // The group goes beyond the specified end row. Move to the
1475  // one before the end position to finish the loop.
1476  pp = ppEnd - 1;
1477  }
1478  else
1479  {
1480  // Move to the last one in the group.
1481  pp += pFC->GetSharedLength() - 1;
1482  }
1483  }
1484  }
1485 
1486  SCROW getStartRow() const
1487  {
1488  return mnStartRow;
1489  }
1490 
1491  SCROW getEndRow() const
1492  {
1493  return mnEndRow;
1494  }
1495 };
1496 
1497 }
1498 
1501  SCROW nRow1, SCROW nRow2 )
1502 {
1503  if (!HasFormulaCell())
1504  return;
1505 
1506  StartListeningFormulaCellsHandler aFunc(rStartCxt, rEndCxt);
1507  sc::ProcessBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
1508 }
1509 
1511  sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2,
1512  SCROW* pStartRow, SCROW* pEndRow )
1513 {
1514  if (!HasFormulaCell())
1515  return;
1516 
1517  EndListeningFormulaCellsHandler aFunc(rCxt);
1518  sc::ProcessBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
1519 
1520  if (pStartRow)
1521  *pStartRow = aFunc.getStartRow();
1522 
1523  if (pEndRow)
1524  *pEndRow = aFunc.getEndRow();
1525 }
1526 
1528  sc::EndListeningContext& rCxt, SCROW nRow, std::vector<ScAddress>* pGroupPos )
1529 {
1530  if (!GetDoc().ValidRow(nRow))
1531  return;
1532 
1533  sc::CellStoreType::position_type aPos = maCells.position(nRow);
1534  sc::CellStoreType::iterator it = aPos.first;
1535  if (it->type != sc::element_type_formula)
1536  // Only interested in a formula block.
1537  return;
1538 
1539  ScFormulaCell* pFC = sc::formula_block::at(*it->data, aPos.second);
1540  ScFormulaCellGroupRef xGroup = pFC->GetCellGroup();
1541  if (!xGroup)
1542  // Not a formula group.
1543  return;
1544 
1545  // End listening.
1546  pFC->EndListeningTo(rCxt);
1547 
1548  if (pGroupPos)
1549  {
1550  if (!pFC->IsSharedTop())
1551  // Record the position of the top cell of the group.
1552  pGroupPos->push_back(xGroup->mpTopCell->aPos);
1553 
1554  SCROW nGrpLastRow = pFC->GetSharedTopRow() + pFC->GetSharedLength() - 1;
1555  if (nRow < nGrpLastRow)
1556  // Record the last position of the group.
1557  pGroupPos->push_back(ScAddress(nCol, nGrpLastRow, nTab));
1558  }
1559 }
1560 
1562  sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2, std::vector<ScAddress>* pGroupPos )
1563 {
1564  // Only end the intersected group.
1565  sc::CellStoreType::position_type aPos = maCells.position(nRow1);
1566  sc::CellStoreType::iterator it = aPos.first;
1567  if (it->type == sc::element_type_formula)
1568  {
1569  ScFormulaCell* pFC = sc::formula_block::at(*it->data, aPos.second);
1570  ScFormulaCellGroupRef xGroup = pFC->GetCellGroup();
1571  if (xGroup)
1572  {
1573  if (!pFC->IsSharedTop())
1574  // End listening.
1575  pFC->EndListeningTo(rCxt);
1576 
1577  if (pGroupPos)
1578  // Record the position of the top cell of the group.
1579  pGroupPos->push_back(xGroup->mpTopCell->aPos);
1580  }
1581  }
1582 
1583  aPos = maCells.position(it, nRow2);
1584  it = aPos.first;
1585  if (it->type != sc::element_type_formula)
1586  return;
1587 
1588  ScFormulaCell* pFC = sc::formula_block::at(*it->data, aPos.second);
1589  ScFormulaCellGroupRef xGroup = pFC->GetCellGroup();
1590  if (!xGroup)
1591  return;
1592 
1593  if (!pFC->IsSharedTop())
1594  // End listening.
1595  pFC->EndListeningTo(rCxt);
1596 
1597  if (pGroupPos)
1598  {
1599  // Record the position of the bottom cell of the group.
1600  ScAddress aPosLast = xGroup->mpTopCell->aPos;
1601  aPosLast.IncRow(xGroup->mnLength-1);
1602  pGroupPos->push_back(aPosLast);
1603  }
1604 }
1605 
1607 {
1608  sc::CellStoreType::position_type aPos = maCells.position(nRow);
1609  if (aPos.first->type != sc::element_type_formula)
1610  // not a formula cell.
1611  return;
1612 
1613  ScFormulaCell** pp = &sc::formula_block::at(*aPos.first->data, aPos.second);
1614 
1615  ScFormulaCellGroupRef xGroup = (*pp)->GetCellGroup();
1616  if (!xGroup)
1617  {
1618  // not a formula group.
1619  (*pp)->EndListeningTo(rCxt);
1620  return;
1621  }
1622 
1623  // Move back to the top cell.
1624  SCROW nTopDelta = (*pp)->aPos.Row() - xGroup->mpTopCell->aPos.Row();
1625  assert(nTopDelta >= 0);
1626  if (nTopDelta > 0)
1627  pp -= nTopDelta;
1628 
1629  // Set the needs listening flag to all cells in the group.
1630  assert(*pp == xGroup->mpTopCell);
1631  ScFormulaCell** ppEnd = pp + xGroup->mnLength;
1632  for (; pp != ppEnd; ++pp)
1633  (*pp)->EndListeningTo(rCxt);
1634 }
1635 
1637 {
1638  sc::CellStoreType::position_type aPos = maCells.position(nRow);
1639  if (aPos.first->type != sc::element_type_formula)
1640  // not a formula cell.
1641  return;
1642 
1643  ScFormulaCell** pp = &sc::formula_block::at(*aPos.first->data, aPos.second);
1644 
1645  ScFormulaCellGroupRef xGroup = (*pp)->GetCellGroup();
1646  if (!xGroup)
1647  {
1648  // not a formula group.
1649  (*pp)->SetNeedsListening(true);
1650  return;
1651  }
1652 
1653  // Move back to the top cell.
1654  SCROW nTopDelta = (*pp)->aPos.Row() - xGroup->mpTopCell->aPos.Row();
1655  assert(nTopDelta >= 0);
1656  if (nTopDelta > 0)
1657  pp -= nTopDelta;
1658 
1659  // Set the needs listening flag to all cells in the group.
1660  assert(*pp == xGroup->mpTopCell);
1661  ScFormulaCell** ppEnd = pp + xGroup->mnLength;
1662  for (; pp != ppEnd; ++pp)
1663  (*pp)->SetNeedsListening(true);
1664 }
1665 
1666 std::optional<sc::ColumnIterator> ScColumn::GetColumnIterator( SCROW nRow1, SCROW nRow2 ) const
1667 {
1668  if (!GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2) || nRow1 > nRow2)
1669  return {};
1670 
1671  return sc::ColumnIterator(maCells, nRow1, nRow2);
1672 }
1673 
1674 static bool lcl_InterpretSpan(sc::formula_block::const_iterator& rSpanIter, SCROW nStartOffset, SCROW nEndOffset,
1675  const ScFormulaCellGroupRef& mxParentGroup, bool& bAllowThreading, ScDocument& rDoc)
1676 {
1677  bAllowThreading = true;
1678  ScFormulaCell* pCellStart = nullptr;
1679  SCROW nSpanStart = -1;
1680  SCROW nSpanEnd = -1;
1681  sc::formula_block::const_iterator itSpanStart;
1682  bool bAnyDirty = false;
1683  for (SCROW nFGOffset = nStartOffset; nFGOffset <= nEndOffset; ++rSpanIter, ++nFGOffset)
1684  {
1685  bool bThisDirty = (*rSpanIter)->NeedsInterpret();
1686  if (!pCellStart && bThisDirty)
1687  {
1688  pCellStart = *rSpanIter;
1689  itSpanStart = rSpanIter;
1690  nSpanStart = nFGOffset;
1691  bAnyDirty = true;
1692  }
1693 
1694  if (pCellStart && (!bThisDirty || nFGOffset == nEndOffset))
1695  {
1696  nSpanEnd = bThisDirty ? nFGOffset : nFGOffset - 1;
1697  assert(nSpanStart >= nStartOffset && nSpanStart <= nSpanEnd && nSpanEnd <= nEndOffset);
1698 
1699  // Found a completely dirty sub span [nSpanStart, nSpanEnd] inside the required span [nStartOffset, nEndOffset]
1700  bool bGroupInterpreted = pCellStart->Interpret(nSpanStart, nSpanEnd);
1701 
1702  if (bGroupInterpreted)
1703  for (SCROW nIdx = nSpanStart; nIdx <= nSpanEnd; ++nIdx, ++itSpanStart)
1704  assert(!(*itSpanStart)->NeedsInterpret());
1705 
1706  ScRecursionHelper& rRecursionHelper = rDoc.GetRecursionHelper();
1707  // child cell's Interpret could result in calling dependency calc
1708  // and that could detect a cycle involving mxGroup
1709  // and do early exit in that case.
1710  // OR
1711  // this call resulted from a dependency calculation for a multi-formula-group-threading and
1712  // if intergroup dependency is found, return early.
1713  if ((mxParentGroup && mxParentGroup->mbPartOfCycle) || !rRecursionHelper.AreGroupsIndependent())
1714  {
1715  bAllowThreading = false;
1716  return bAnyDirty;
1717  }
1718 
1719  if (!bGroupInterpreted)
1720  {
1721  // Evaluate from second cell in non-grouped style (no point in trying group-interpret again).
1722  ++itSpanStart;
1723  for (SCROW nIdx = nSpanStart+1; nIdx <= nSpanEnd; ++nIdx, ++itSpanStart)
1724  {
1725  (*itSpanStart)->Interpret(); // We know for sure that this cell is dirty so directly call Interpret().
1726  if ((*itSpanStart)->NeedsInterpret())
1727  {
1728  SAL_WARN("sc.core.formulagroup", "Internal error, cell " << (*itSpanStart)->aPos
1729  << " failed running Interpret(), not allowing threading");
1730  bAllowThreading = false;
1731  return bAnyDirty;
1732  }
1733 
1734  // Allow early exit like above.
1735  if ((mxParentGroup && mxParentGroup->mbPartOfCycle) || !rRecursionHelper.AreGroupsIndependent())
1736  {
1737  // Set this cell as dirty as this may be interpreted in InterpretTail()
1738  pCellStart->SetDirtyVar();
1739  bAllowThreading = false;
1740  return bAnyDirty;
1741  }
1742  }
1743  }
1744 
1745  pCellStart = nullptr; // For next sub span start detection.
1746  }
1747  }
1748 
1749  return bAnyDirty;
1750 }
1751 
1752 static void lcl_EvalDirty(sc::CellStoreType& rCells, SCROW nRow1, SCROW nRow2, ScDocument& rDoc,
1753  const ScFormulaCellGroupRef& mxGroup, bool bThreadingDepEval, bool bSkipRunning,
1754  bool& bIsDirty, bool& bAllowThreading)
1755 {
1756  ScRecursionHelper& rRecursionHelper = rDoc.GetRecursionHelper();
1757  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = rCells.position(nRow1);
1758  sc::CellStoreType::const_iterator it = aPos.first;
1759  size_t nOffset = aPos.second;
1760  SCROW nRow = nRow1;
1761 
1762  bIsDirty = false;
1763 
1764  for (;it != rCells.end() && nRow <= nRow2; ++it, nOffset = 0)
1765  {
1766  switch( it->type )
1767  {
1769  // These require EditEngine (in ScEditUtils::GetString()), which is probably
1770  // too complex for use in threads.
1771  if (bThreadingDepEval)
1772  {
1773  bAllowThreading = false;
1774  return;
1775  }
1776  break;
1778  {
1779  size_t nRowsToRead = nRow2 - nRow + 1;
1780  const size_t nEnd = std::min(it->size, nOffset+nRowsToRead); // last row + 1
1781  sc::formula_block::const_iterator itCell = sc::formula_block::begin(*it->data);
1782  std::advance(itCell, nOffset);
1783 
1784  // Loop inside the formula block.
1785  size_t nCellIdx = nOffset;
1786  while (nCellIdx < nEnd)
1787  {
1788  const ScFormulaCellGroupRef& mxGroupChild = (*itCell)->GetCellGroup();
1789  ScFormulaCell* pChildTopCell = mxGroupChild ? mxGroupChild->mpTopCell : *itCell;
1790 
1791  // Check if itCell is already in path.
1792  // If yes use a cycle guard to mark all elements of the cycle
1793  // and return false
1794  if (bThreadingDepEval && pChildTopCell->GetSeenInPath())
1795  {
1796  ScFormulaGroupCycleCheckGuard aCycleCheckGuard(rRecursionHelper, pChildTopCell);
1797  bAllowThreading = false;
1798  return;
1799  }
1800 
1801  if (bSkipRunning && (*itCell)->IsRunning())
1802  {
1803  ++itCell;
1804  nCellIdx += 1;
1805  nRow += 1;
1806  nRowsToRead -= 1;
1807  continue;
1808  }
1809 
1810  if (mxGroupChild)
1811  {
1812  // It is a Formula-group, evaluate the necessary parts of it (spans).
1813  const SCROW nFGStartOffset = (*itCell)->aPos.Row() - pChildTopCell->aPos.Row();
1814  const SCROW nFGEndOffset = std::min(nFGStartOffset + static_cast<SCROW>(nRowsToRead) - 1, mxGroupChild->mnLength - 1);
1815  assert(nFGEndOffset >= nFGStartOffset);
1816  const SCROW nSpanLen = nFGEndOffset - nFGStartOffset + 1;
1817  // The (main) span required to be evaluated is [nFGStartOffset, nFGEndOffset], but this span may contain
1818  // non-dirty cells, so split this into sets of completely-dirty spans and try evaluate each of them in grouped-style.
1819 
1820  bool bAnyDirtyInSpan = lcl_InterpretSpan(itCell, nFGStartOffset, nFGEndOffset, mxGroup, bAllowThreading, rDoc);
1821  if (!bAllowThreading)
1822  return;
1823  // itCell will now point to cell just after the end of span [nFGStartOffset, nFGEndOffset].
1824  bIsDirty = bIsDirty || bAnyDirtyInSpan;
1825 
1826  // update the counters by nSpanLen.
1827  // itCell already got updated.
1828  nCellIdx += nSpanLen;
1829  nRow += nSpanLen;
1830  nRowsToRead -= nSpanLen;
1831  }
1832  else
1833  {
1834  // No formula-group here.
1835  bool bDirtyFlag = false;
1836  if( (*itCell)->NeedsInterpret())
1837  {
1838  bDirtyFlag = true;
1839  (*itCell)->Interpret();
1840  if ((*itCell)->NeedsInterpret())
1841  {
1842  SAL_WARN("sc.core.formulagroup", "Internal error, cell " << (*itCell)->aPos
1843  << " failed running Interpret(), not allowing threading");
1844  bAllowThreading = false;
1845  return;
1846  }
1847  }
1848  bIsDirty = bIsDirty || bDirtyFlag;
1849 
1850  // child cell's Interpret could result in calling dependency calc
1851  // and that could detect a cycle involving mxGroup
1852  // and do early exit in that case.
1853  // OR
1854  // we are trying multi-formula-group-threading, but found intergroup dependency.
1855  if (bThreadingDepEval && mxGroup &&
1856  (mxGroup->mbPartOfCycle || !rRecursionHelper.AreGroupsIndependent()))
1857  {
1858  // Set itCell as dirty as itCell may be interpreted in InterpretTail()
1859  (*itCell)->SetDirtyVar();
1860  bAllowThreading = false;
1861  return;
1862  }
1863 
1864  // update the counters by 1.
1865  nCellIdx += 1;
1866  nRow += 1;
1867  nRowsToRead -= 1;
1868  ++itCell;
1869  }
1870  }
1871  break;
1872  }
1873  default:
1874  // Skip this block.
1875  nRow += it->size - nOffset;
1876  continue;
1877  }
1878  }
1879 
1880  if (bThreadingDepEval)
1881  bAllowThreading = true;
1882 
1883 }
1884 
1885 // Returns true if at least one FC is dirty.
1886 bool ScColumn::EnsureFormulaCellResults( SCROW nRow1, SCROW nRow2, bool bSkipRunning )
1887 {
1888  if (!GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2) || nRow1 > nRow2)
1889  return false;
1890 
1891  if (!HasFormulaCell(nRow1, nRow2))
1892  return false;
1893 
1894  bool bAnyDirty = false, bTmp = false;
1895  lcl_EvalDirty(maCells, nRow1, nRow2, GetDoc(), nullptr, false, bSkipRunning, bAnyDirty, bTmp);
1896  return bAnyDirty;
1897 }
1898 
1900 {
1901  if (nRow1 > nRow2)
1902  return false;
1903 
1904  bool bAllowThreading = true, bTmp = false;
1905  lcl_EvalDirty(maCells, nRow1, nRow2, GetDoc(), mxGroup, true, false, bTmp, bAllowThreading);
1906 
1907  return bAllowThreading;
1908 }
1909 
1910 namespace {
1911 
1912 class StoreToCacheFunc
1913 {
1914  SvStream& mrStrm;
1915 public:
1916 
1917  StoreToCacheFunc(SvStream& rStrm):
1918  mrStrm(rStrm)
1919  {
1920  }
1921 
1922  void operator() ( const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize )
1923  {
1924  SCROW nStartRow = node.position + nOffset;
1925  mrStrm.WriteUInt64(nStartRow);
1926  mrStrm.WriteUInt64(nDataSize);
1927  switch (node.type)
1928  {
1930  {
1931  mrStrm.WriteUChar(0);
1932  }
1933  break;
1935  {
1936  mrStrm.WriteUChar(1);
1937  sc::numeric_block::const_iterator it = sc::numeric_block::begin(*node.data);
1938  std::advance(it, nOffset);
1939  sc::numeric_block::const_iterator itEnd = it;
1940  std::advance(itEnd, nDataSize);
1941 
1942  for (; it != itEnd; ++it)
1943  {
1944  mrStrm.WriteDouble(*it);
1945  }
1946  }
1947  break;
1949  {
1950  mrStrm.WriteUChar(2);
1951  sc::string_block::const_iterator it = sc::string_block::begin(*node.data);
1952  std::advance(it, nOffset);
1953  sc::string_block::const_iterator itEnd = it;
1954  std::advance(itEnd, nDataSize);
1955 
1956  for (; it != itEnd; ++it)
1957  {
1958  OString aStr = OUStringToOString(it->getString(), RTL_TEXTENCODING_UTF8);
1959  sal_Int32 nStrLength = aStr.getLength();
1960  mrStrm.WriteInt32(nStrLength);
1961  mrStrm.WriteOString(aStr);
1962  }
1963  }
1964  break;
1966  {
1967  mrStrm.WriteUChar(3);
1968  sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
1969  std::advance(it, nOffset);
1970  sc::formula_block::const_iterator itEnd = it;
1971  std::advance(itEnd, nDataSize);
1972 
1973  for (; it != itEnd; /* incrementing through std::advance*/)
1974  {
1975  const ScFormulaCell* pCell = *it;
1976  OUString aFormula;
1978  const auto& xCellGroup = pCell->GetCellGroup();
1979  sal_uInt64 nGroupLength = 0;
1980  if (xCellGroup)
1981  {
1982  nGroupLength = xCellGroup->mnLength;
1983  }
1984  else
1985  {
1986  nGroupLength = 1;
1987  }
1988  mrStrm.WriteUInt64(nGroupLength);
1989  mrStrm.WriteInt32(aFormula.getLength());
1990  mrStrm.WriteOString(OUStringToOString(aFormula, RTL_TEXTENCODING_UTF8));
1991 
1992  // incrementing the iterator
1993  std::advance(it, nGroupLength);
1994  }
1995  }
1996  break;
1997  }
1998  }
1999 };
2000 
2001 }
2002 
2004 {
2005  rStrm.WriteUInt64(nCol);
2006  SCROW nLastRow = GetLastDataPos();
2007  rStrm.WriteUInt64(nLastRow + 1); // the rows are zero based
2008 
2009  StoreToCacheFunc aFunc(rStrm);
2010  sc::ParseBlock(maCells.begin(), maCells, aFunc, SCROW(0), nLastRow);
2011 }
2012 
2014 {
2015  sal_uInt64 nStoredCol = 0;
2016  rStrm.ReadUInt64(nStoredCol);
2017  if (nStoredCol != static_cast<sal_uInt64>(nCol))
2018  throw std::exception();
2019 
2020  sal_uInt64 nLastRow = 0;
2021  rStrm.ReadUInt64(nLastRow);
2022  sal_uInt64 nReadRow = 0;
2023  ScDocument& rDocument = GetDoc();
2024  while (nReadRow < nLastRow)
2025  {
2026  sal_uInt64 nStartRow = 0;
2027  sal_uInt64 nDataSize = 0;
2028  rStrm.ReadUInt64(nStartRow);
2029  rStrm.ReadUInt64(nDataSize);
2030  sal_uInt8 nType = 0;
2031  rStrm.ReadUChar(nType);
2032  switch (nType)
2033  {
2034  case 0:
2035  // nothing to do
2036  maCells.set_empty(nStartRow, nDataSize);
2037  break;
2038  case 1:
2039  {
2040  // nDataSize double values
2041  std::vector<double> aValues(nDataSize);
2042  for (auto& rValue : aValues)
2043  {
2044  rStrm.ReadDouble(rValue);
2045  }
2046  maCells.set(nStartRow, aValues.begin(), aValues.end());
2047  }
2048  break;
2049  case 2:
2050  {
2051  std::vector<svl::SharedString> aStrings(nDataSize);
2052  svl::SharedStringPool& rPool = rDocument.GetSharedStringPool();
2053  for (auto& rString : aStrings)
2054  {
2055  sal_Int32 nStrLength = 0;
2056  rStrm.ReadInt32(nStrLength);
2057  std::unique_ptr<char[]> pStr(new char[nStrLength]);
2058  rStrm.ReadBytes(pStr.get(), nStrLength);
2059  OString aOStr(pStr.get(), nStrLength);
2060  OUString aStr = OStringToOUString(aOStr, RTL_TEXTENCODING_UTF8);
2061  rString = rPool.intern(aStr);
2062  }
2063  maCells.set(nStartRow, aStrings.begin(), aStrings.end());
2064 
2065  }
2066  break;
2067  case 3:
2068  {
2069  std::vector<ScFormulaCell*> aFormulaCells(nDataSize);
2070 
2071  ScAddress aAddr(nCol, nStartRow, nTab);
2073  for (SCROW nRow = 0; nRow < static_cast<SCROW>(nDataSize);)
2074  {
2075  sal_uInt64 nFormulaGroupSize = 0;
2076  rStrm.ReadUInt64(nFormulaGroupSize);
2077  sal_Int32 nStrLength = 0;
2078  rStrm.ReadInt32(nStrLength);
2079  std::unique_ptr<char[]> pStr(new char[nStrLength]);
2080  rStrm.ReadBytes(pStr.get(), nStrLength);
2081  OString aOStr(pStr.get(), nStrLength);
2082  OUString aStr = OStringToOUString(aOStr, RTL_TEXTENCODING_UTF8);
2083  for (sal_uInt64 i = 0; i < nFormulaGroupSize; ++i)
2084  {
2085  aFormulaCells[nRow + i] = new ScFormulaCell(rDocument, aAddr, aStr, eGrammar);
2086  aAddr.IncRow();
2087  }
2088 
2089  nRow += nFormulaGroupSize;
2090  }
2091 
2092  maCells.set(nStartRow, aFormulaCells.begin(), aFormulaCells.end());
2093  }
2094  break;
2095  }
2096 
2097  nReadRow += nDataSize;
2098  }
2099 }
2100 
2101 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void reset(size_t nSize)
Definition: cellvalues.cxx:127
void AdjustReferenceOnMovedOrigin(const ScAddress &rOldPos, const ScAddress &rNewPos)
Adjust all internal references on base position change.
Definition: token.cxx:4392
std::map< SCROW, std::vector< SdrObject * > > GetObjectsAnchoredToRange(SCTAB nTab, SCCOL nCol, SCROW nStartRow, SCROW nEndRow)
Definition: drwlayer.cxx:2477
void CellStorageModified()
Called whenever the state of cell array gets modified i.e.
Definition: column2.cxx:1601
std::unordered_set< OpCode, std::hash< std::underlying_type< OpCode >::type > > unordered_opcode_set
SCROW GetNotePosition(size_t nIndex) const
Definition: column4.cxx:684
svl::SharedString maString
::boost::intrusive_ptr< ScFormulaCellGroup > ScFormulaCellGroupRef
Definition: types.hxx:43
bool GetSeenInPath() const
SvStream & WriteUInt64(sal_uInt64 nuInt64)
void SplitFormulaGroupByRelativeRef(const ScRange &rBoundRange)
Definition: column4.cxx:1223
CellType meType
Definition: cellvalue.hxx:37
OUString getString() const
ScAddress aStart
Definition: address.hxx:499
SharedString intern(const OUString &rStr)
SC_DLLPUBLIC svl::SharedStringPool & GetSharedStringPool()
Definition: documen2.cxx:565
void DeleteArea(SCROW nStartRow, SCROW nEndRow, InsertDeleteFlags nDelFlag, bool bBroadcast=true, sc::ColumnSpanSet *pBroadcastSpans=nullptr)
Definition: column3.cxx:989
void GetAllNoteEntries(std::vector< sc::NoteEntry > &rNotes) const
Definition: column4.cxx:749
std::unique_ptr< ScAttrArray > pAttrArray
Definition: column.hxx:131
ScDocument & GetDoc() const
Definition: column.hxx:184
const ScPatternAttr * GetPattern(SCROW nRow) const
Definition: column.cxx:370
void StoreToCache(SvStream &rStrm) const
Definition: column4.cxx:2003
bool NeedsInterpret() const
ocName
void swap(SCTAB nTab, SCCOL nCol, CellValues &rColValue)
Swap the entire column.
Definition: cellvalues.cxx:322
Sheet / outlining (grouping) information.
SCROW Row() const
Definition: address.hxx:261
void RestoreFromCache(SvStream &rStrm)
Definition: column4.cxx:2013
SvStream & WriteInt32(sal_Int32 nInt32)
void ForgetCaption(bool bPreserveData=false)
Forgets the pointer to the note caption object.
Definition: postit.cxx:957
void SwapNonEmpty(sc::TableValues &rValues, sc::StartListeningContext &rStartCxt, sc::EndListeningContext &rEndCxt)
Definition: column4.cxx:495
CellTextAttrStoreType::iterator miCellTextAttrPos
const mdds::mtv::element_t element_type_celltextattr
Definition: mtvelements.hxx:45
SCROW GetSharedTopRow() const
sal_uInt32 GetRefCount() const
Think of this as a mini-ScColumn like storage that only stores cell values in a column.
Definition: cellvalues.hxx:40
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()
std::unique_ptr< ScPostIt > ReleaseNote(SCROW nRow)
Definition: column4.cxx:616
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
ListenersType & GetAllListeners()
sal_Int32 mnCol
Store position data for column array storage.
const SfxItemSet & GetItemSet() const
void TransferCellValuesTo(SCROW nRow, size_t nLen, sc::CellValues &rDest)
Definition: column4.cxx:341
const ContentProperties & rData
InsertDeleteFlags getInsertFlag() const
Stores cell values for multiple tables.
Definition: cellvalues.hxx:85
double mfValue
Definition: cellvalue.hxx:39
void transferFrom(ScColumn &rCol, SCROW nRow, size_t nLen)
Transfer values from specified column.
Definition: cellvalues.cxx:52
bool isSkipAttrForEmptyCells() const
ScAddress aEnd
Definition: address.hxx:500
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.
static const SharedString & getEmptyString()
void ApplyPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr &rPatAttr, ScEditDataArray *pDataArray=nullptr, bool *const pIsChanged=nullptr)
Definition: column.cxx:516
void CompileHybridFormula(sc::StartListeningContext &rStartListenCxt, sc::CompileFormulaContext &rCompileCxt)
Definition: column4.cxx:1000
void Swap(ScColumn &rOther, SCROW nRow1, SCROW nRow2, bool bPattern)
Definition: column4.cxx:1110
bool isTableProtected() 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)
SC_DLLPUBLIC formula::FormulaGrammar::Grammar GetGrammar() const
Definition: document.hxx:984
SCROW GetMaxRowCount() const
Definition: sheetlimits.hxx:61
mdds::multi_type_vector< CellFunc, CellStoreEvent > CellStoreType
SvStream & ReadUInt64(sal_uInt64 &rUInt64)
void DeleteRanges(const std::vector< sc::RowSpan > &rRanges, InsertDeleteFlags nDelFlag)
Definition: column4.cxx:534
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
void UpdateDrawObjectsForRow(std::vector< SdrObject * > &pObjects, SCCOL nTargetCol, SCROW nTargetRow)
Definition: column.cxx:1941
Internal use only (d&d undo): do not delete caption objects of cell notes.
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6087
const mdds::mtv::element_t element_type_cellnote
Definition: mtvelements.hxx:51
void ParseFormula(const CellStoreType &rStore, Func &rFunc)
Definition: mtvcellfunc.hxx:63
Store arbitrary cell value of any kind.
Definition: cellvalue.hxx:35
const ScFormulaCellGroupRef & GetCellGroup() const
void PreprocessRangeNameUpdate(sc::EndListeningContext &rEndListenCxt, sc::CompileFormulaContext &rCompileCxt)
Definition: column4.cxx:971
void PreprocessDBDataUpdate(sc::EndListeningContext &rEndListenCxt, sc::CompileFormulaContext &rCompileCxt)
Definition: column4.cxx:985
virtual void Clear() override
Definition: token.cxx:1914
const mdds::mtv::element_t element_type_formula
Definition: mtvelements.hxx:49
bool HasFormulaCell() const
Definition: column4.cxx:1292
void StartListeningFormulaCells(sc::StartListeningContext &rStartCxt, sc::EndListeningContext &rEndCxt, SCROW nRow1, SCROW nRow2)
Definition: column4.cxx:1499
ScClipParam & GetClipParam()
Definition: document.cxx:2565
Keep track of spans in a single column only.
std::vector< SvtListener * > ListenersType
enumrange< T >::Iterator begin(enumrange< T >)
ScFormulaCell * mpFormula
Definition: cellvalue.hxx:42
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:872
void ForgetNoteCaptions(SCROW nRow1, SCROW nRow2, bool bPreserveData)
Definition: column4.cxx:671
Additional class containing cell annotation data.
Definition: postit.hxx:159
void StartListeningTo(ScDocument &rDoc)
ScConditionalFormatList * getCondFormatList()
void CreateAllNoteCaptions()
Definition: column4.cxx:665
void EndListeningFormulaCells(sc::EndListeningContext &rCxt, SCROW nRow1, SCROW nRow2, SCROW *pStartRow, SCROW *pEndRow)
Definition: column4.cxx:1510
int nCount
sc::CellStoreType maCells
Definition: column.hxx:129
void ResetFormulaCellPositions(SCROW nRow1, SCROW nRow2, bool bUpdateRefs)
Reset column position of formula cells within specified row range.
Definition: column4.cxx:1189
void set(const ScDocument &rDoc, SCTAB nTab, SCCOL nCol, SCROW nRow, bool bVal)
void SetRow(SCROW nRowP)
Definition: address.hxx:274
SCROW GetLastDataPos() const
Definition: column2.cxx:1339
void SetCode(std::unique_ptr< ScTokenArray > pNew)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
ScAddress aPos
void CheckRelativeReferenceBounds(const sc::RefUpdateContext &rCxt, const ScAddress &rPos, SCROW nGroupLen, std::vector< SCROW > &rBounds) const
Definition: token.cxx:4661
void SetNeedsListening(bool bVar)
void SetCol(SCCOL nColP)
Definition: address.hxx:278
size_t mnBlkCountFormula
Definition: column.hxx:133
void swapNonEmpty(ScColumn &rCol)
Definition: cellvalues.cxx:67
void setValue(size_t nRow, double fVal)
Definition: cellvalues.cxx:138
void SetDirty(bool bDirtyFlag=true)
const SfxPoolItem & GetItem(sal_uInt16 nWhichP) const
Definition: patattr.hxx:70
void AdjustReferenceOnMovedOriginIfOtherSheet(const ScAddress &rOldPos, const ScAddress &rNewPos)
Adjust all internal references on base position change if they point to a sheet other than the one of...
Definition: token.cxx:4430
SCROW GetSharedLength() const
bool IsShared() const
SC_DLLPUBLIC ScDrawLayer * GetDrawLayer()
Definition: document.hxx:1058
SCCOL nCol
Definition: column.hxx:135
void getSpans(SpansType &rSpans) const
ScRecursionHelper & GetRecursionHelper()
Definition: document.cxx:6846
void InitBlockPosition(sc::ColumnBlockPosition &rBlockPos)
Definition: column3.cxx:1044
int i
void SetValues(const SCROW nRow, const std::vector< double > &rVals)
Definition: column4.cxx:311
sal_Int16 SCCOL
Definition: types.hxx:21
InsertDeleteFlags
Definition: global.hxx:157
void RegroupFormulaCells(std::vector< ScAddress > *pGroupPos=nullptr)
Regroup formula cells for the entire column.
Definition: column3.cxx:3533
sc::MultiDataCellState::StateType HasDataCellsInRange(SCROW nRow1, SCROW nRow2, SCROW *pRow1) const
Definition: column4.cxx:47
size_t size() const
Definition: cellvalues.cxx:121
SvtScriptType mnScriptType
bool HasCellNote(SCROW nStartRow, SCROW nEndRow) const
Definition: column4.cxx:770
svl::SharedString * mpString
Definition: cellvalue.hxx:40
sc::CellTextAttrStoreType maCellTextAttrs
Definition: column.hxx:118
std::unique_ptr< ScPostIt > Clone(const ScAddress &rOwnPos, ScDocument &rDestDoc, const ScAddress &rDestPos, bool bCloneCaption) const
Clones this note and its caption object, if specified.
Definition: postit.cxx:877
const ScPatternAttr * SetPattern(SCROW nRow, std::unique_ptr< ScPatternAttr >)
Definition: column.cxx:699
bool Interpret(SCROW nStartOffset=-1, SCROW nEndOffset=-1)
static void JoinNewFormulaCell(const sc::CellStoreType::position_type &aPos, ScFormulaCell &rCell)
Definition: column3.cxx:273
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
const mdds::mtv::element_t element_type_empty
Definition: mtvelements.hxx:55
void IncRow(SCROW nDelta=1)
Definition: address.hxx:299
void EndListeningGroup(sc::EndListeningContext &rCxt, SCROW nRow)
Definition: column4.cxx:1606
Structure that stores segments of boolean flags per column, and perform custom action on those segmen...
ocBad
void GetUnprotectedCells(SCROW nStartRow, SCROW nEndRow, ScRangeList &rRangeList) const
Definition: column4.cxx:802
const mdds::mtv::element_t element_type_numeric
Mapped standard element types (for convenience).
Definition: mtvelements.hxx:54
SdrCaptionObj * GetOrCreateCaption(const ScAddress &rPos) const
Returns the caption object of this note.
Definition: postit.cxx:951
const ScRange & getRange() const
Definition: cellvalues.cxx:317
bool IsSharedTop() const
void EndListeningIntersectedGroups(sc::EndListeningContext &rCxt, SCROW nRow1, SCROW nRow2, std::vector< ScAddress > *pGroupPos)
Definition: column4.cxx:1561
void ProcessNote(CellNoteStoreType &rStore, Func &rFunc)
sal_uInt32 GetNumberFormat(SvNumberFormatter *) const
Definition: patattr.cxx:1255
bool EnsureFormulaCellResults(SCROW nRow1, SCROW nRow2, bool bSkipRunning=false)
Definition: column4.cxx:1886
void SetMatColsRows(SCCOL nCols, SCROW nRows)
SvStream & ReadUChar(unsigned char &rChar)
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
void UpdateScriptTypes(SCROW nRow1, SCROW nRow2)
Definition: column4.cxx:1099
static bool lcl_InterpretSpan(sc::formula_block::const_iterator &rSpanIter, SCROW nStartOffset, SCROW nEndOffset, const ScFormulaCellGroupRef &mxParentGroup, bool &bAllowThreading, ScDocument &rDoc)
Definition: column4.cxx:1674
void DetachFormulaCells(const sc::CellStoreType::position_type &aPos, size_t nLength, std::vector< SCROW > *pNewSharedRows)
Definition: column3.cxx:404
SC_DLLPUBLIC const SfxItemSet * GetCondResult(SCCOL nCol, SCROW nRow, SCTAB nTab, ScRefCellValue *pCell=nullptr) const
Definition: documen4.cxx:789
SvStream & ReadDouble(double &rDouble)
void CollectFormulaCells(std::vector< ScFormulaCell * > &rCells, SCROW nRow1, SCROW nRow2)
Definition: column4.cxx:1283
const ScPatternAttr * getSingleCellPattern(size_t nColOffset) const
ScCellValue & getSingleCell(size_t nColOffset)
CellStoreType::iterator miCellPos
std::vector< CellValueSpan > getNonEmptySpans(SCTAB nTab, SCCOL nCol) const
Definition: cellvalues.cxx:340
SvStream & ReadInt32(sal_Int32 &rInt32)
Internal use only (undo etc.): do not copy/delete caption objects of cell notes.
std::size_t ReadBytes(void *pData, std::size_t nSize)
void SyncSharedCode()
void copyTo(ScColumn &rCol, SCROW nRow) const
Definition: cellvalues.cxx:61
const ScPostIt * getSingleCellNote(size_t nColOffset) const
void DeleteCellNotes(sc::ColumnBlockPosition &rBlockPos, SCROW nRow1, SCROW nRow2, bool bForgetCaptionOwnership)
Definition: column2.cxx:2007
void SetHybridFormula(const OUString &r, const formula::FormulaGrammar::Grammar eGrammar)
For import only: set a temporary formula string to be compiled later.
A class to wrap ScRecursionHelper::PushFormulaGroup(), ScRecursionHelper::PopFormulaGroup() and make ...
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
sal_Int32 SCROW
Definition: types.hxx:17
ScRange getWholeRange() const
Return a single range that encompasses all individual ranges.
Definition: clipparam.cxx:109
sc::BroadcasterStoreType maBroadcasters
Definition: column.hxx:124
void CollectListeners(std::vector< SvtListener * > &rListeners, SCROW nRow1, SCROW nRow2)
Definition: column4.cxx:1274
bool ValidRow(SCROW nRow) const
Definition: document.hxx:875
bool IsMerged(SCROW nRow) const
Definition: column4.cxx:42
sc::CellNoteStoreType maCellNotes
Definition: column.hxx:121
void CopyCellValuesFrom(SCROW nRow, const sc::CellValues &rSrc)
Definition: column4.cxx:366
#define SAL_WARN_IF(condition, area, stream)
SvStream & WriteOString(std::string_view rStr)
void Join(const ScRange &, bool bIsInList=false)
Definition: rangelst.cxx:164
SCCOL GetCol() const
Definition: column.hxx:186
unsigned char sal_uInt8
ScPatternAttr * PutInPool(ScDocument *pDestDoc, ScDocument *pSrcDoc) const
Definition: patattr.cxx:1030
ScFormulaCell ** mpCells
void GetMatColsRows(SCCOL &nCols, SCROW &nRows) const
ScFormulaCell * mpCell
const mdds::mtv::element_t element_type_edittext
Definition: mtvelements.hxx:48
sc::CellTextAttr & getSingleCellAttr(size_t nColOffset)
SvStream & WriteUChar(unsigned char nChar)
void RemoveEditAttribs(SCROW nStartRow, SCROW nEndRow)
Definition: column2.cxx:1184
virtual std::unique_ptr< EditTextObject > Clone() const =0
CellNoteStoreType::iterator miCellNotePos
void CopyOneCellFromClip(sc::CopyFromClipContext &rCxt, SCROW nRow1, SCROW nRow2, size_t nColOffset)
Definition: column4.cxx:195
const T & Put(std::unique_ptr< T > xItem, sal_uInt16 nWhich=0)
ocTableRef
ocColRowName
static bool splitFormulaCellGroups(const ScDocument &rDoc, CellStoreType &rCells, std::vector< SCROW > &rBounds)
Split existing shared formula ranges at specified row positions.
constexpr TypedWhichId< ScCondFormatItem > ATTR_CONDITIONAL(154)
ScDocument * getClipDoc()
Definition: clipcontext.cxx:96
void * p
QPRO_FUNC_TYPE nType
Definition: qproform.cxx:400
std::vector< RowSpan > SpansType
std::vector< sc::FormulaGroupEntry > GetFormulaGroupEntries()
Get all non-grouped formula cells and formula cell groups in the whole column.
Definition: column.cxx:2543
sc::FormulaResultValue GetResult()
ScMatrixMode
const ScCondFormatIndexes & GetCondFormatData() const
Definition: attrib.hxx:279
EditTextObject * mpEditText
Definition: cellvalue.hxx:41
size_t GetNoteCount() const
Definition: column4.cxx:626
InsertDeleteFlags getDeleteFlag() const
void ConvertFormulaToValue(sc::EndListeningContext &rCxt, SCROW nRow1, SCROW nRow2, sc::TableValues *pUndo)
Definition: column4.cxx:432
std::optional< sc::ColumnIterator > GetColumnIterator(SCROW nRow1, SCROW nRow2) const
Definition: column4.cxx:1666
void scan(const ScColumn &rColumn)
Scan an entire column and tag all non-empty cell positions.
const OUString & GetHybridFormula() const
void BroadcastCells(const std::vector< SCROW > &rRows, SfxHintId nHint)
Definition: column3.cxx:75
bool ValidRow(SCROW nRow, SCROW nMaxRow)
Definition: address.hxx:98
bool HandleRefArrayForParallelism(SCROW nRow1, SCROW nRow2, const ScFormulaCellGroupRef &mxGroup)
Definition: column4.cxx:1899
SCTAB GetTab() const
Definition: column.hxx:185
Range getDestRange() const
Definition: clipcontext.cxx:81
std::pair< CellStoreType::const_iterator, size_t > FindFormula(const CellStoreType &rStore, SCROW nRow1, SCROW nRow2, Func &rFunc)
#define SAL_WARN(area, stream)
This iterator lets you iterate over cells over specified range in a single column.
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:31
SvStream & WriteDouble(const double &rDouble)
void RemoveFromFormulaTree(ScFormulaCell *pCell)
Definition: documen7.cxx:274
void DeleteCells(sc::ColumnBlockPosition &rBlockPos, SCROW nRow1, SCROW nRow2, InsertDeleteFlags nDelFlag, sc::SingleColumnSpanSet &rDeleted)
Definition: column3.cxx:967
void DeleteBeforeCopyFromClip(sc::CopyFromClipContext &rCxt, const ScColumn &rClipCol, sc::ColumnSpanSet &rBroadcastSpans)
Definition: column4.cxx:95
ScMatrixMode GetMatrixFlag() const
void EndListeningIntersectedGroup(sc::EndListeningContext &rCxt, SCROW nRow, std::vector< ScAddress > *pGroupPos)
Definition: column4.cxx:1527
void SetNeedsListeningGroup(SCROW nRow)
Definition: column4.cxx:1636
const mdds::mtv::element_t element_type_string
Definition: mtvelements.hxx:47
mdds::multi_type_vector< CTAttrFunc > CellTextAttrStoreType
void EndListeningTo(ScDocument &rDoc, ScTokenArray *pArr=nullptr, ScAddress aPos=ScAddress())
void CloneFormulaCell(const ScFormulaCell &rSrc, const sc::CellTextAttr &rAttr, const std::vector< sc::RowSpan > &rRanges)
Definition: column4.cxx:540
aStr
bool HasOpCodes(const unordered_opcode_set &rOpCodes) const
void GetNotesInRange(SCROW nStartRow, SCROW nEndRow, std::vector< sc::NoteEntry > &rNotes) const
Definition: column4.cxx:754
Strings (and string results if InsertDeleteFlags::FORMULA is not set).
::basegfx::B2DRectangle maBounds
ocDBArea
void StartListeningUnshared(const std::vector< SCROW > &rNewSharedRows)
Re-establish listeners on unshared formula groups.
Definition: column3.cxx:346
sal_Int16 SCTAB
Definition: types.hxx:22
ColumnBlockPosition * getBlockPosition(SCTAB nTab, SCCOL nCol)
Definition: clipcontext.cxx:31
static void lcl_EvalDirty(sc::CellStoreType &rCells, SCROW nRow1, SCROW nRow2, ScDocument &rDoc, const ScFormulaCellGroupRef &mxGroup, bool bThreadingDepEval, bool bSkipRunning, bool &bIsDirty, bool &bAllowThreading)
Definition: column4.cxx:1752
void swapNonEmpty(SCTAB nTab, SCCOL nCol, ScColumn &rCol)
Swap non-empty blocks with the column storage.
Definition: cellvalues.cxx:331
void DeleteArea(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: conditio.cxx:2189
BroadcasterStoreType::iterator ProcessBroadcaster(const BroadcasterStoreType::iterator &it, BroadcasterStoreType &rStore, SCROW nRow1, SCROW nRow2, FuncElem &rFuncElem)