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>
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 }
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 }
235 pAttrArray->DeleteHardAttr(nRow1, nRow2);
236 }
237}
238
239void 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.getType() != 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.getType())
277 {
278 case CELLTYPE_VALUE:
279 {
280 std::vector<double> aVals(nDestSize, rSrcCell.getDouble());
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.getSharedString()->getString()) :
295 *rSrcCell.getSharedString());
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.getEditText()->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.getFormula(), 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
396void 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
426void 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
476namespace {
477
478class ConvertFormulaToValueHandler
479{
480 sc::CellValues maResValues;
481 bool mbModified;
482
483public:
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
547namespace {
548
549class StartListeningHandler
550{
552
553public:
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
563class EndListeningHandler
564{
566
567public:
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
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
617void 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
711std::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
731namespace {
732
733class NoteCaptionCreator
734{
735 ScAddress maPos;
736public:
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
746class NoteCaptionCleaner
747{
748 bool mbPreserveData;
749public:
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
766void 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
779SCROW 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
803namespace {
804
805class NoteEntryCollector
806{
807 std::vector<sc::NoteEntry>& mrNotes;
808 SCTAB mnTab;
809 SCCOL mnCol;
810 SCROW mnStartRow;
811 SCROW mnEndRow;
812public:
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
844void 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
849void 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
865bool 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
897void 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
928namespace {
929
930class RecompileByOpcodeHandler
931{
932 ScDocument* mpDoc;
934 sc::EndListeningContext& mrEndListenCxt;
935 sc::CompileFormulaContext& mrCompileFormulaCxt;
936
937public:
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
998class CompileHybridFormulaHandler
999{
1000 ScDocument& mrDoc;
1001 sc::StartListeningContext& mrStartListenCxt;
1002 sc::CompileFormulaContext& mrCompileFormulaCxt;
1003
1004public:
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
1105namespace {
1106
1107class 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
1117private:
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
1153public:
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
1204void 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
1250namespace {
1251
1252class FormulaColPosSetter
1253{
1254 SCCOL mnCol;
1255 bool mbUpdateRefs;
1256public:
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
1283void 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
1289namespace {
1290
1291class RelativeRefBoundChecker
1292{
1293 std::vector<SCROW> maBounds;
1294 ScRange maBoundRange;
1295
1296public:
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
1338namespace {
1339
1340class ListenerCollector
1341{
1342 std::vector<SvtListener*>& mrListeners;
1343public:
1344 explicit ListenerCollector( std::vector<SvtListener*>& rListener ) :
1345 mrListeners(rListener) {}
1346
1347 void operator() ( size_t /*nRow*/, SvtBroadcaster* p )
1348 {
1349 SvtBroadcaster::ListenersType& rLis = p->GetAllListeners();
1350 mrListeners.insert(mrListeners.end(), rLis.begin(), rLis.end());
1351 }
1352};
1353
1354class FormulaCellCollector
1355{
1356 std::vector<ScFormulaCell*>& mrCells;
1357public:
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
1368void 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
1377void 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
1391namespace {
1392
1393struct FindAnyFormula
1394{
1395 bool operator() ( size_t /*nRow*/, const ScFormulaCell* /*pCell*/ ) const
1396 {
1397 return true;
1398 }
1399};
1400
1401}
1402
1403bool 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
1421namespace {
1422
1423void 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
1432class StartListeningFormulaCellsHandler
1433{
1434 sc::StartListeningContext& mrStartCxt;
1435 sc::EndListeningContext& mrEndCxt;
1436 SCROW mnStartRow;
1437
1438public:
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
1510class EndListeningFormulaCellsHandler
1511{
1512 sc::EndListeningContext& mrEndCxt;
1513 SCROW mnStartRow;
1514 SCROW mnEndRow;
1515
1516public:
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
1760std::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
1768static 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
1846static 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.
1980bool 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
2004namespace {
2005
2006class StoreToCacheFunc
2007{
2008 SvStream& mrStrm;
2009public:
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;
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{
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;
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
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: */
bool ValidRow(SCROW nRow, SCROW nMaxRow)
Definition: address.hxx:105
::basegfx::B2DRectangle maBounds
virtual std::unique_ptr< EditTextObject > Clone() const=0
void SetCol(SCCOL nColP)
Definition: address.hxx:291
SCROW Row() const
Definition: address.hxx:274
void SetRow(SCROW nRowP)
Definition: address.hxx:287
void IncRow(SCROW nDelta=1)
Definition: address.hxx:312
SCCOL Col() const
Definition: address.hxx:279
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
std::unique_ptr< ScAttrArray > pAttrArray
Definition: column.hxx:118
void ApplyPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr &rPatAttr, ScEditDataArray *pDataArray=nullptr, bool *const pIsChanged=nullptr)
Definition: column.cxx:482
void DeleteCellNotes(sc::ColumnBlockPosition &rBlockPos, SCROW nRow1, SCROW nRow2, bool bForgetCaptionOwnership)
Definition: column2.cxx:2228
void CollectFormulaCells(std::vector< ScFormulaCell * > &rCells, SCROW nRow1, SCROW nRow2)
Definition: column4.cxx:1377
SCTAB GetTab() const
Definition: column.hxx:254
void CellStorageModified()
Called whenever the state of cell array gets modified i.e.
Definition: column2.cxx:1648
void DeleteBeforeCopyFromClip(sc::CopyFromClipContext &rCxt, const ScColumn &rClipCol, sc::ColumnSpanSet &rBroadcastSpans)
Definition: column4.cxx:93
SCROW GetNotePosition(size_t nIndex) const
Definition: column4.cxx:779
SCCOL nCol
Definition: column.hxx:203
bool HasCellNote(SCROW nStartRow, SCROW nEndRow) const
Definition: column4.cxx:865
void PreprocessDBDataUpdate(sc::EndListeningContext &rEndListenCxt, sc::CompileFormulaContext &rCompileCxt)
Definition: column4.cxx:1080
sc::CellTextAttrStoreType maCellTextAttrs
Definition: column.hxx:187
void GetAllNoteEntries(std::vector< sc::NoteEntry > &rNotes) const
Definition: column4.cxx:844
bool HasFormulaCell() const
Definition: column4.cxx:1386
void EndListeningGroup(sc::EndListeningContext &rCxt, SCROW nRow)
Definition: column4.cxx:1700
const ScPatternAttr * GetPattern(SCROW nRow) const
Definition: column.hxx:952
SCTAB nTab
Definition: column.hxx:204
void SplitFormulaGroupByRelativeRef(const ScRange &rBoundRange)
Definition: column4.cxx:1317
void PreprocessRangeNameUpdate(sc::EndListeningContext &rEndListenCxt, sc::CompileFormulaContext &rCompileCxt)
Definition: column4.cxx:1066
void TransferCellValuesTo(SCROW nRow, size_t nLen, sc::CellValues &rDest)
Definition: column4.cxx:426
void GetUnprotectedCells(SCROW nStartRow, SCROW nEndRow, ScRangeList &rRangeList) const
Definition: column4.cxx:897
void RegroupFormulaCells(std::vector< ScAddress > *pGroupPos=nullptr)
Regroup formula cells for the entire column.
Definition: column3.cxx:3674
void CloneFormulaCell(sc::ColumnBlockPosition &rBlockPos, const ScFormulaCell &rSrc, const sc::CellTextAttr &rAttr, const std::vector< sc::RowSpan > &rRanges)
Definition: column4.cxx:623
void UpdateDrawObjectsForRow(std::vector< SdrObject * > &pObjects, SCCOL nTargetCol, SCROW nTargetRow)
Definition: column.cxx:1844
void CollectListeners(std::vector< SvtListener * > &rListeners, SCROW nRow1, SCROW nRow2)
Definition: column4.cxx:1368
void BroadcastCells(const std::vector< SCROW > &rRows, SfxHintId nHint)
Definition: column3.cxx:80
void CheckIntegrity() const
Definition: column4.cxx:2194
void DeleteRanges(const std::vector< sc::RowSpan > &rRanges, InsertDeleteFlags nDelFlag)
Definition: column4.cxx:617
void RestoreFromCache(SvStream &rStrm)
Definition: column4.cxx:2106
void InitBlockPosition(sc::ColumnBlockPosition &rBlockPos)
Definition: column3.cxx:1122
std::vector< sc::FormulaGroupEntry > GetFormulaGroupEntries()
Get all non-grouped formula cells and formula cell groups in the whole column.
Definition: column.cxx:2448
void ConvertFormulaToValue(sc::EndListeningContext &rCxt, SCROW nRow1, SCROW nRow2, sc::TableValues *pUndo)
Definition: column4.cxx:517
void RemoveEditAttribs(sc::ColumnBlockPosition &rBlockPos, SCROW nStartRow, SCROW nEndRow)
Definition: column2.cxx:1235
sc::CellNoteStoreType maCellNotes
Definition: column.hxx:190
std::optional< sc::ColumnIterator > GetColumnIterator(SCROW nRow1, SCROW nRow2) const
Definition: column4.cxx:1760
void EndListeningFormulaCells(sc::EndListeningContext &rCxt, SCROW nRow1, SCROW nRow2, SCROW *pStartRow, SCROW *pEndRow)
Definition: column4.cxx:1604
sc::MultiDataCellState::StateType HasDataCellsInRange(SCROW nRow1, SCROW nRow2, SCROW *pRow1) const
Definition: column4.cxx:45
void SwapNonEmpty(sc::TableValues &rValues, sc::StartListeningContext &rStartCxt, sc::EndListeningContext &rEndCxt)
Definition: column4.cxx:579
void ResetFormulaCellPositions(SCROW nRow1, SCROW nRow2, bool bUpdateRefs)
Reset column position of formula cells within specified row range.
Definition: column4.cxx:1283
void StoreToCache(SvStream &rStrm) const
Definition: column4.cxx:2096
SCCOL GetCol() const
Definition: column.hxx:255
void DeleteCells(sc::ColumnBlockPosition &rBlockPos, SCROW nRow1, SCROW nRow2, InsertDeleteFlags nDelFlag, sc::SingleColumnSpanSet &rDeleted)
Definition: column3.cxx:1040
std::unique_ptr< ScPostIt > ReleaseNote(SCROW nRow)
Definition: column4.cxx:711
void EndListeningIntersectedGroup(sc::EndListeningContext &rCxt, SCROW nRow, std::vector< ScAddress > *pGroupPos)
Definition: column4.cxx:1621
size_t mnBlkCountFormula
Definition: column.hxx:201
void EndListeningIntersectedGroups(sc::EndListeningContext &rCxt, SCROW nRow1, SCROW nRow2, std::vector< ScAddress > *pGroupPos)
Definition: column4.cxx:1655
void Swap(ScColumn &rOther, SCROW nRow1, SCROW nRow2, bool bPattern)
Definition: column4.cxx:1204
void UpdateScriptTypes(SCROW nRow1, SCROW nRow2)
Definition: column4.cxx:1193
void SetNeedsListeningGroup(SCROW nRow)
Definition: column4.cxx:1730
void CompileHybridFormula(sc::StartListeningContext &rStartListenCxt, sc::CompileFormulaContext &rCompileCxt)
Definition: column4.cxx:1095
void CopyOneCellFromClip(sc::CopyFromClipContext &rCxt, SCROW nRow1, SCROW nRow2, size_t nColOffset)
Definition: column4.cxx:239
const ScPatternAttr * SetPattern(SCROW nRow, std::unique_ptr< ScPatternAttr >)
Definition: column.hxx:1017
sc::CellStoreType maCells
Definition: column.hxx:196
void DetachFormulaCells(const sc::CellStoreType::position_type &aPos, size_t nLength, std::vector< SCROW > *pNewSharedRows)
Definition: column3.cxx:492
void SetValues(const SCROW nRow, const std::vector< double > &rVals)
Definition: column4.cxx:396
void StartListeningUnshared(const std::vector< SCROW > &rNewSharedRows)
Re-establish listeners on unshared formula groups.
Definition: column3.cxx:434
void ForgetNoteCaptions(SCROW nRow1, SCROW nRow2, bool bPreserveData)
Definition: column4.cxx:766
void CreateAllNoteCaptions()
Definition: column4.cxx:760
void StartListeningFormulaCells(sc::StartListeningContext &rStartCxt, sc::EndListeningContext &rEndCxt, SCROW nRow1, SCROW nRow2)
Definition: column4.cxx:1593
void CopyCellValuesFrom(SCROW nRow, const sc::CellValues &rSrc)
Definition: column4.cxx:451
void DeleteSparklineCells(sc::ColumnBlockPosition &rBlockPos, SCROW nRow1, SCROW nRow2)
Definition: column2.cxx:2036
void GetNotesInRange(SCROW nStartRow, SCROW nEndRow, std::vector< sc::NoteEntry > &rNotes) const
Definition: column4.cxx:849
void DeleteArea(SCROW nStartRow, SCROW nEndRow, InsertDeleteFlags nDelFlag, bool bBroadcast=true, sc::ColumnSpanSet *pBroadcastSpans=nullptr)
Definition: column3.cxx:1062
size_t GetNoteCount() const
Definition: column4.cxx:721
bool HandleRefArrayForParallelism(SCROW nRow1, SCROW nRow2, const ScFormulaCellGroupRef &mxGroup)
Definition: column4.cxx:1993
static void JoinNewFormulaCell(const sc::CellStoreType::position_type &aPos, ScFormulaCell &rCell)
Definition: column3.cxx:361
void duplicateSparkline(sc::CopyFromClipContext &rContext, sc::ColumnBlockPosition *pBlockPos, size_t nColOffset, size_t nDestSize, ScAddress aDestPosition)
Definition: column4.cxx:367
sc::BroadcasterStoreType maBroadcasters
Definition: column.hxx:193
SCROW GetLastDataPos() const
Definition: column2.cxx:1385
ScDocument & GetDoc() const
Definition: column.hxx:127
sc::SparklineStoreType maSparklines
Definition: column.hxx:199
bool EnsureFormulaCellResults(SCROW nRow1, SCROW nRow2, bool bSkipRunning=false)
Definition: column4.cxx:1980
const ScCondFormatIndexes & GetCondFormatData() const
Definition: attrib.hxx:282
void DeleteArea(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: conditio.cxx:2197
static void LOKCommentNotify(LOKCommentNotificationType nType, const ScDocument *pDocument, const ScAddress &rPos, const ScPostIt *pNote)
Definition: docsh4.cxx:2524
bool ValidRow(SCROW nRow) const
Definition: document.hxx:899
ScClipParam & GetClipParam()
Definition: document.cxx:2600
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6169
void RemoveFromFormulaTree(ScFormulaCell *pCell)
Definition: documen7.cxx:287
SC_DLLPUBLIC SvtScriptType GetStringScriptType(const OUString &rString)
Definition: documen6.cxx:76
ScRecursionHelper & GetRecursionHelper()
Definition: document.cxx:7045
SC_DLLPUBLIC ScDrawLayer * GetDrawLayer()
Definition: document.hxx:1082
SC_DLLPUBLIC std::shared_ptr< sc::SparklineGroup > SearchSparklineGroup(tools::Guid const &rGuid)
Definition: document.cxx:6708
SC_DLLPUBLIC formula::FormulaGrammar::Grammar GetGrammar() const
Definition: document.hxx:1008
SC_DLLPUBLIC svl::SharedStringPool & GetSharedStringPool()
Definition: documen2.cxx:586
SC_DLLPUBLIC const SfxItemSet * GetCondResult(SCCOL nCol, SCROW nRow, SCTAB nTab, ScRefCellValue *pCell=nullptr) const
Definition: documen4.cxx:798
std::map< SCROW, std::vector< SdrObject * > > GetObjectsAnchoredToRange(SCTAB nTab, SCCOL nCol, SCROW nStartRow, SCROW nEndRow)
Definition: drwlayer.cxx:2490
bool NeedsInterpret() const
void GetMatColsRows(SCCOL &nCols, SCROW &nRows) const
bool IsShared() const
SCROW GetSharedLength() const
ScMatrixMode GetMatrixFlag() const
const ScFormulaCellGroupRef & GetCellGroup() const
SCROW GetSharedTopRow() const
void SetNeedsListening(bool bVar)
sc::FormulaResultValue GetResult()
bool IsSharedTop() const
bool GetSeenInPath() const
OUString GetHybridFormula() const
void SetCode(std::unique_ptr< ScTokenArray > pNew)
void EndListeningTo(ScDocument &rDoc, ScTokenArray *pArr=nullptr, ScAddress aPos=ScAddress())
void StartListeningTo(ScDocument &rDoc)
void SetDirty(bool bDirtyFlag=true)
void SetMatColsRows(SCCOL nCols, SCROW nRows)
ScTokenArray * GetCode()
void SetHybridFormula(const OUString &r, const formula::FormulaGrammar::Grammar eGrammar)
For import only: set a temporary formula string to be compiled later.
ScAddress aPos
bool Interpret(SCROW nStartOffset=-1, SCROW nEndOffset=-1)
OUString GetFormula(const formula::FormulaGrammar::Grammar=formula::FormulaGrammar::GRAM_DEFAULT, const ScInterpreterContext *pContext=nullptr) const
A class to wrap ScRecursionHelper::PushFormulaGroup(), ScRecursionHelper::PopFormulaGroup() and make ...
ScPatternAttr * PutInPool(ScDocument *pDestDoc, ScDocument *pSrcDoc) const
Definition: patattr.cxx:1083
sal_uInt32 GetNumberFormat(SvNumberFormatter *) const
Definition: patattr.cxx:1301
SfxItemSet & GetItemSet()
Definition: patattr.hxx:155
const SfxPoolItem & GetItem(sal_uInt16 nWhichP) const
Definition: patattr.hxx:72
Additional class containing cell annotation data.
Definition: postit.hxx:58
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:513
void Join(const ScRange &, bool bIsInList=false)
Definition: rangelst.cxx:152
ScAddress aEnd
Definition: address.hxx:498
ScAddress aStart
Definition: address.hxx:497
void CheckRelativeReferenceBounds(const sc::RefUpdateContext &rCxt, const ScAddress &rPos, SCROW nGroupLen, std::vector< SCROW > &rBounds) const
Definition: token.cxx:4742
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
void AdjustReferenceOnMovedOrigin(const ScAddress &rOldPos, const ScAddress &rNewPos)
Adjust all internal references on base position change.
Definition: token.cxx:4473
virtual void Clear() override
Definition: token.cxx:1924
const T & Put(std::unique_ptr< T > xItem, sal_uInt16 nWhich=0)
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
sal_uInt32 GetRefCount() const
SvStream & WriteDouble(const double &rDouble)
SvStream & ReadUInt64(sal_uInt64 &rUInt64)
SvStream & WriteInt32(sal_Int32 nInt32)
SvStream & ReadDouble(double &rDouble)
SvStream & WriteUChar(unsigned char nChar)
SvStream & WriteOString(std::string_view rStr)
SvStream & WriteUInt64(sal_uInt64 nuInt64)
SvStream & ReadInt32(sal_Int32 &rInt32)
std::size_t ReadBytes(void *pData, std::size_t nSize)
SvStream & ReadUChar(unsigned char &rChar)
std::vector< SvtListener * > ListenersType
bool HasOpCodes(const unordered_opcode_set &rOpCodes) const
Think of this as a mini-ScColumn like storage that only stores cell values in a column.
Definition: cellvalues.hxx:41
void transferFrom(ScColumn &rCol, SCROW nRow, size_t nLen)
Transfer values from specified column.
Definition: cellvalues.cxx:52
void reset(size_t nSize)
Definition: cellvalues.cxx:127
size_t size() const
Definition: cellvalues.cxx:121
void copyTo(ScColumn &rCol, SCROW nRow) const
Definition: cellvalues.cxx:61
void swapNonEmpty(ScColumn &rCol)
Definition: cellvalues.cxx:67
void setValue(size_t nRow, double fVal)
Definition: cellvalues.cxx:138
ColumnBlockPosition * getBlockPosition(SCTAB nTab, SCCOL nCol)
Definition: clipcontext.cxx:32
This iterator lets you iterate over cells over specified range in a single column.
Structure that stores segments of boolean flags per column, and perform custom action on those segmen...
void set(const ScDocument &rDoc, SCTAB nTab, SCCOL nCol, SCROW nRow, bool bVal)
sc::CellTextAttr & getSingleCellAttr(size_t nColOffset)
InsertDeleteFlags getDeleteFlag() const
ScConditionalFormatList * getCondFormatList()
bool isSkipEmptyCells() const
Get the flag that indicates whether the "skip empty cells" paste option is selected.
ScCellValue & getSingleCell(size_t nColOffset)
InsertDeleteFlags getInsertFlag() const
std::shared_ptr< sc::Sparkline > const & getSingleSparkline(size_t nColOffset) const
const ScPatternAttr * getSingleCellPattern(size_t nColOffset) const
bool isTableProtected() const
Range getDestRange() const
Definition: clipcontext.cxx:81
const ScPostIt * getSingleCellNote(size_t nColOffset) const
ScDocument * getClipDoc()
Definition: clipcontext.cxx:96
static void startListeningAsGroup(StartListeningContext &rCxt, ScFormulaCell **ppSharedTop)
Have all formula cells belonging to a group start listening to their references.
static bool splitFormulaCellGroups(const ScDocument &rDoc, CellStoreType &rCells, std::vector< SCROW > &rBounds)
Split existing shared formula ranges at specified row positions.
Keep track of spans in a single column only.
void scan(const ScColumn &rColumn)
Scan an entire column and tag all non-empty cell positions.
std::vector< RowSpan > SpansType
void getSpans(SpansType &rSpans) const
Holder of a sparkline, that is connected to a cell specific.
Stores cell values for multiple tables.
Definition: cellvalues.hxx:86
void swap(SCTAB nTab, SCCOL nCol, CellValues &rColValue)
Swap the entire column.
Definition: cellvalues.cxx:322
std::vector< CellValueSpan > getNonEmptySpans(SCTAB nTab, SCCOL nCol) const
Definition: cellvalues.cxx:340
const ScRange & getRange() const
Definition: cellvalues.cxx:317
void swapNonEmpty(SCTAB nTab, SCCOL nCol, ScColumn &rCol)
Swap non-empty blocks with the column storage.
Definition: cellvalues.cxx:331
SharedString intern(const OUString &rStr)
const OUString & getString() const
static const SharedString & getEmptyString()
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
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
int nCount
sal_Int32 mnCol
ScMatrixMode
@ CELLTYPE_EDIT
Definition: global.hxx:276
@ CELLTYPE_STRING
Definition: global.hxx:274
@ CELLTYPE_FORMULA
Definition: global.hxx:275
@ CELLTYPE_NONE
Definition: global.hxx:272
@ CELLTYPE_VALUE
Definition: global.hxx:273
InsertDeleteFlags
Definition: global.hxx:149
@ SPARKLINES
Sheet / outlining (grouping) information.
@ NOTE
Strings (and string results if InsertDeleteFlags::FORMULA is not set).
@ NOCAPTIONS
Sparklines in a cell.
@ EDITATTR
Drawing objects.
@ ADDNOTES
Internal use only (undo etc.): do not copy/delete caption objects of cell notes.
@ ATTRIB
Internal use only (d&d undo): do not delete caption objects of cell notes.
@ HARDATTR
Formula cells.
sal_Int32 nIndex
void * p
sal_Int64 n
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
aStr
std::unordered_set< OpCode, std::hash< std::underlying_type< OpCode >::type > > unordered_opcode_set
int i
void SvStream & rStrm
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
enumrange< T >::Iterator begin(enumrange< T >)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
CellStoreType::const_iterator ParseAllNonEmpty(const typename CellStoreType::const_iterator &itPos, const CellStoreType &rCells, SCROW nRow1, SCROW nRow2, Func &rFunc)
Definition: mtvcellfunc.hxx:95
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.
const mdds::mtv::element_t element_type_celltextattr
Definition: mtvelements.hxx:46
const mdds::mtv::element_t element_type_edittext
Definition: mtvelements.hxx:49
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
std::pair< CellStoreType::const_iterator, size_t > FindFormula(const CellStoreType &rStore, SCROW nRow1, SCROW nRow2, Func &rFunc)
const mdds::mtv::element_t element_type_formula
Definition: mtvelements.hxx:50
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.
BroadcasterStoreType::iterator ProcessBroadcaster(const BroadcasterStoreType::iterator &it, BroadcasterStoreType &rStore, SCROW nRow1, SCROW nRow2, FuncElem &rFuncElem)
void ParseFormula(const CellStoreType &rStore, Func &rFunc)
Definition: mtvcellfunc.hxx:63
mdds::mtv::soa::multi_type_vector< CellFunc, CellStoreTrait > CellStoreType
const mdds::mtv::element_t element_type_numeric
Mapped standard element types (for convenience).
Definition: mtvelements.hxx:56
void ProcessNote(CellNoteStoreType &rStore, Func &rFunc)
const mdds::mtv::element_t element_type_string
Definition: mtvelements.hxx:48
mdds::mtv::soa::multi_type_vector< CTAttrFunc > CellTextAttrStoreType
const mdds::mtv::element_t element_type_cellnote
Definition: mtvelements.hxx:52
const mdds::mtv::element_t element_type_empty
Definition: mtvelements.hxx:57
ocTableRef
ocColRowName
ocBad
ocDBArea
ocName
QPRO_FUNC_TYPE nType
Definition: qproform.cxx:398
const sc::CellStoreType & mrCells
Definition: queryiter.cxx:907
constexpr TypedWhichId< ScProtectionAttr > ATTR_PROTECTION(149)
constexpr TypedWhichId< ScCondFormatItem > ATTR_CONDITIONAL(154)
Store arbitrary cell value of any kind.
Definition: cellvalue.hxx:32
const svl::SharedString * getSharedString() const
Definition: cellvalue.hxx:60
CellType getType() const
Definition: cellvalue.cxx:296
ScFormulaCell * getFormula() const
Definition: cellvalue.hxx:59
EditTextObject * getEditText() const
Definition: cellvalue.hxx:61
double getDouble() const
Definition: cellvalue.hxx:58
ScRange getWholeRange() const
Return a single range that encompasses all individual ranges.
Definition: clipparam.cxx:109
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:108
SCROW GetMaxRowCount() const
Definition: sheetlimits.hxx:66
SvtScriptType mnScriptType
Store position data for column array storage.
SparklineStoreType::iterator miSparklinePos
CellTextAttrStoreType::iterator miCellTextAttrPos
CellStoreType::iterator miCellPos
CellNoteStoreType::iterator miCellNotePos
ScFormulaCell * mpCell
ScFormulaCell ** mpCells
svl::SharedString maString
unsigned char sal_uInt8
sal_Int16 SCTAB
Definition: types.hxx:22
::boost::intrusive_ptr< ScFormulaCellGroup > ScFormulaCellGroupRef
Definition: types.hxx:43
sal_Int16 SCCOL
Definition: types.hxx:21
sal_Int32 SCROW
Definition: types.hxx:17