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