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