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