LibreOffice Module sc (master) 1
column.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 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <column.hxx>
21#include <scitems.hxx>
22#include <formulacell.hxx>
23#include <document.hxx>
24#include <table.hxx>
25#include <docpool.hxx>
26#include <attarray.hxx>
27#include <patattr.hxx>
28#include <compiler.hxx>
29#include <brdcst.hxx>
30#include <markdata.hxx>
31#include <postit.hxx>
32#include <cellvalue.hxx>
33#include <tokenarray.hxx>
34#include <clipcontext.hxx>
35#include <types.hxx>
36#include <editutil.hxx>
37#include <mtvcellfunc.hxx>
38#include <columnspanset.hxx>
39#include <scopetools.hxx>
40#include <sharedformula.hxx>
41#include <refupdatecontext.hxx>
42#include <listenercontext.hxx>
43#include <formulagroup.hxx>
44#include <drwlayer.hxx>
45#include <mtvelements.hxx>
46#include <bcaslot.hxx>
47
48#include <svl/numformat.hxx>
49#include <svl/poolcach.hxx>
50#include <svl/zforlist.hxx>
54#include <o3tl/safeint.hxx>
55#include <osl/diagnose.h>
56
57#include <map>
58#include <cstdio>
59#include <memory>
60
61using ::editeng::SvxBorderLine;
62using namespace formula;
63
64namespace {
65
66bool IsAmbiguousScriptNonZero( SvtScriptType nScript )
67{
68 //TODO: move to a header file
69 return ( nScript != SvtScriptType::LATIN &&
70 nScript != SvtScriptType::ASIAN &&
71 nScript != SvtScriptType::COMPLEX &&
72 nScript != SvtScriptType::NONE );
73}
74
75}
76
78 pPattern(nullptr), bFormula(false), bSkipMerged(true), bGetFont(true), bTotalSize(false)
79{
80}
81
82ScColumn::ScColumn(ScSheetLimits const & rSheetLimits) :
83 maCellTextAttrs(rSheetLimits.GetMaxRowCount()),
84 maCellNotes(rSheetLimits.GetMaxRowCount()),
85 maBroadcasters(rSheetLimits.GetMaxRowCount()),
86 maCells(sc::CellStoreEvent(this)),
87 maSparklines(rSheetLimits.GetMaxRowCount()),
88 mnBlkCountFormula(0),
89 nCol( 0 ),
90 nTab( 0 ),
91 mbEmptyBroadcastersPending( false )
92{
93 maCells.resize(rSheetLimits.GetMaxRowCount());
94}
95
96ScColumn::~ScColumn() COVERITY_NOEXCEPT_FALSE
97{
98 FreeAll();
99}
100
101void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument& rDoc, bool bEmptyAttrArray)
102{
103 nCol = nNewCol;
104 nTab = nNewTab;
105 if ( bEmptyAttrArray )
106 InitAttrArray(new ScAttrArray( nCol, nTab, rDoc, nullptr ));
107 else
108 InitAttrArray(new ScAttrArray( nCol, nTab, rDoc, &rDoc.maTabs[nTab]->aDefaultColData.AttrArray()));
109}
110
112 bool bNoMatrixAtAll ) const
113{
114 using namespace sc;
115
116 if (!GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2) || nRow1 > nRow2)
117 return MatrixEdge::Nothing;
118
120
121 if (nRow1 == nRow2)
122 {
123 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
124 if (aPos.first->type != sc::element_type_formula)
125 return MatrixEdge::Nothing;
126
127 const ScFormulaCell* pCell = sc::formula_block::at(*aPos.first->data, aPos.second);
128 if (pCell->GetMatrixFlag() == ScMatrixMode::NONE)
129 return MatrixEdge::Nothing;
130
131 return pCell->GetMatrixEdge(GetDoc(), aOrigin);
132 }
133
134 bool bOpen = false;
135 MatrixEdge nEdges = MatrixEdge::Nothing;
136
137 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
138 sc::CellStoreType::const_iterator it = aPos.first;
139 size_t nOffset = aPos.second;
140 SCROW nRow = nRow1;
141 for (;it != maCells.end() && nRow <= nRow2; ++it, nOffset = 0)
142 {
143 if (it->type != sc::element_type_formula)
144 {
145 // Skip this block.
146 nRow += it->size - nOffset;
147 continue;
148 }
149
150 size_t nRowsToRead = nRow2 - nRow + 1;
151 size_t nEnd = std::min(it->size, nOffset+nRowsToRead); // last row + 1
152 sc::formula_block::const_iterator itCell = sc::formula_block::begin(*it->data);
153 std::advance(itCell, nOffset);
154 for (size_t i = nOffset; i < nEnd; ++itCell, ++i)
156 // Loop inside the formula block.
157 const ScFormulaCell* pCell = *itCell;
158 if (pCell->GetMatrixFlag() == ScMatrixMode::NONE)
159 continue;
160
161 nEdges = pCell->GetMatrixEdge(GetDoc(), aOrigin);
162 if (nEdges == MatrixEdge::Nothing)
163 continue;
164
165 // A 1x1 matrix array formula is OK even for no matrix at all.
166 if (bNoMatrixAtAll
167 && (nEdges != (MatrixEdge::Top | MatrixEdge::Left | MatrixEdge::Bottom | MatrixEdge::Right)))
168 return MatrixEdge::Inside; // per convention Inside
169
170 if (nEdges & MatrixEdge::Top)
171 bOpen = true; // top edge opens, keep on looking
172 else if (!bOpen)
173 return nEdges | MatrixEdge::Open; // there's something that wasn't opened
174 else if (nEdges & MatrixEdge::Inside)
175 return nEdges; // inside
176 if (((nMask & MatrixEdge::Right) && (nEdges & MatrixEdge::Left) && !(nEdges & MatrixEdge::Right)) ||
177 ((nMask & MatrixEdge::Left) && (nEdges & MatrixEdge::Right) && !(nEdges & MatrixEdge::Left)))
178 return nEdges; // only left/right edge
179
180 if (nEdges & MatrixEdge::Bottom)
181 bOpen = false; // bottom edge closes
182 }
183
184 nRow += nEnd - nOffset;
185 }
186 if (bOpen)
187 nEdges |= MatrixEdge::Open; // not closed, matrix continues
188
189 return nEdges;
190}
191
192bool ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark, const ScRangeList& rRangeList) const
193{
194 using namespace sc;
195
196 if (!rMark.IsMultiMarked())
197 return false;
198
200 ScAddress aCurOrigin = aOrigin;
201
202 bool bOpen = false;
203 ScRangeList aRanges = rRangeList; // cached rMark.GetMarkedRanges(), for performance reasons (tdf#148147)
204 for (size_t i = 0, n = aRanges.size(); i < n; ++i)
205 {
206 const ScRange& r = aRanges[i];
207 if (nTab < r.aStart.Tab() || r.aEnd.Tab() < nTab)
208 continue;
209
210 if (nCol < r.aStart.Col() || r.aEnd.Col() < nCol)
211 continue;
212
213 SCROW nTop = r.aStart.Row(), nBottom = r.aEnd.Row();
214 SCROW nRow = nTop;
215 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
216 sc::CellStoreType::const_iterator it = aPos.first;
217 size_t nOffset = aPos.second;
218
219 for (;it != maCells.end() && nRow <= nBottom; ++it, nOffset = 0)
220 {
221 if (it->type != sc::element_type_formula)
222 {
223 // Skip this block.
224 nRow += it->size - nOffset;
225 continue;
226 }
227
228 // This is a formula cell block.
229 size_t nRowsToRead = nBottom - nRow + 1;
230 size_t nEnd = std::min(it->size, nRowsToRead);
231 sc::formula_block::const_iterator itCell = sc::formula_block::begin(*it->data);
232 std::advance(itCell, nOffset);
233 for (size_t j = nOffset; j < nEnd; ++itCell, ++j)
234 {
235 // Loop inside the formula block.
236 const ScFormulaCell* pCell = *itCell;
237 if (pCell->GetMatrixFlag() == ScMatrixMode::NONE)
238 // cell is not a part of a matrix.
239 continue;
240
241 MatrixEdge nEdges = pCell->GetMatrixEdge(GetDoc(), aOrigin);
242 if (nEdges == MatrixEdge::Nothing)
243 continue;
244
245 bool bFound = false;
246
247 if (nEdges & MatrixEdge::Top)
248 bOpen = true; // top edge opens, keep on looking
249 else if (!bOpen)
250 return true; // there's something that wasn't opened
251 else if (nEdges & MatrixEdge::Inside)
252 bFound = true; // inside, all selected?
253
254 if (((nEdges & MatrixEdge::Left) | MatrixEdge::Right) ^ ((nEdges & MatrixEdge::Right) | MatrixEdge::Left))
255 // either left or right, but not both.
256 bFound = true; // only left/right edge, all selected?
257
258 if (nEdges & MatrixEdge::Bottom)
259 bOpen = false; // bottom edge closes
260
261 if (bFound)
262 {
263 // Check if the matrix is inside the selection in its entirety.
264 //
265 // TODO: It's more efficient to skip the matrix range if
266 // it's within selection, to avoid checking it again and
267 // again.
268
269 if (aCurOrigin != aOrigin)
270 { // new matrix to check?
271 aCurOrigin = aOrigin;
272 const ScFormulaCell* pFCell;
274 pFCell = GetDoc().GetFormulaCell(aOrigin);
275 else
276 pFCell = pCell;
277
278 SCCOL nC;
279 SCROW nR;
280 pFCell->GetMatColsRows(nC, nR);
281 ScRange aRange(aOrigin, ScAddress(aOrigin.Col()+nC-1, aOrigin.Row()+nR-1, aOrigin.Tab()));
282 if (rMark.IsAllMarked(aRange))
283 bFound = false;
284 }
285 else
286 bFound = false; // done already
287 }
288
289 if (bFound)
290 return true;
291 }
292
293 nRow += nEnd;
294 }
295 }
296
297 return bOpen;
298}
299
300bool ScColumn::HasAttribSelection( const ScMarkData& rMark, HasAttrFlags nMask ) const
301{
302 bool bFound = false;
303
304 SCROW nTop;
305 SCROW nBottom;
306
307 if (rMark.IsMultiMarked())
308 {
309 ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
310 while (aMultiIter.Next( nTop, nBottom ) && !bFound)
311 {
312 if (pAttrArray->HasAttrib( nTop, nBottom, nMask ))
313 bFound = true;
314 }
315 }
316
317 return bFound;
318}
319
320void ScColumn::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, bool bDeep ) const
321{
322 SCROW nTop;
323 SCROW nBottom;
324
325 if ( rMark.IsMultiMarked() )
326 {
327 const ScMultiSel& rMultiSel = rMark.GetMultiSelData();
328 if ( rMultiSel.HasMarks( nCol ) )
329 {
330 ScMultiSelIter aMultiIter( rMultiSel, nCol );
331 while (aMultiIter.Next( nTop, nBottom ))
332 pAttrArray->MergePatternArea( nTop, nBottom, rState, bDeep );
333 }
334 }
335}
336
338{
339 ::std::map< const ScPatternAttr*, size_t > aAttrMap;
340 const ScPatternAttr* pMaxPattern = nullptr;
341 size_t nMaxCount = 0;
342
343 ScAttrIterator aAttrIter( pAttrArray.get(), nStartRow, nEndRow, GetDoc().GetDefPattern() );
344 const ScPatternAttr* pPattern;
345 SCROW nAttrRow1 = 0, nAttrRow2 = 0;
346
347 while( (pPattern = aAttrIter.Next( nAttrRow1, nAttrRow2 )) != nullptr )
348 {
349 size_t& rnCount = aAttrMap[ pPattern ];
350 rnCount += (nAttrRow2 - nAttrRow1 + 1);
351 if( rnCount > nMaxCount )
352 {
353 pMaxPattern = pPattern;
354 nMaxCount = rnCount;
355 }
356 }
357
358 return pMaxPattern;
359}
360
361sal_uInt32 ScColumnData::GetNumberFormat( SCROW nStartRow, SCROW nEndRow ) const
362{
363 SCROW nPatStartRow, nPatEndRow;
364 const ScPatternAttr* pPattern = pAttrArray->GetPatternRange(nPatStartRow, nPatEndRow, nStartRow);
365 sal_uInt32 nFormat = pPattern->GetNumberFormat(GetDoc().GetFormatTable());
366 while (nEndRow > nPatEndRow)
367 {
368 nStartRow = nPatEndRow + 1;
369 pPattern = pAttrArray->GetPatternRange(nPatStartRow, nPatEndRow, nStartRow);
370 sal_uInt32 nTmpFormat = pPattern->GetNumberFormat(GetDoc().GetFormatTable());
371 if (nFormat != nTmpFormat)
372 return 0;
373 }
374 return nFormat;
375}
376
378 bool* const pIsChanged )
379{
380 return ScColumnData::ApplySelectionCache( pCache, rMark, pDataArray, pIsChanged, nCol );
381}
382
384 bool* const pIsChanged, SCCOL nCol )
385{
386 SCROW nTop = 0;
387 SCROW nBottom = 0;
388 bool bFound = false;
389
390 if ( rMark.IsMultiMarked() )
391 {
392 ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
393 while (aMultiIter.Next( nTop, nBottom ))
394 {
395 pAttrArray->ApplyCacheArea( nTop, nBottom, pCache, pDataArray, pIsChanged );
396 bFound = true;
397 }
398 }
399
400 if (!bFound)
401 return -1;
402 else if (nTop==0 && nBottom==GetDoc().MaxRow())
403 return 0;
404 else
405 return nBottom;
406}
407
408void ScColumnData::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark, SCCOL nCol )
409{
410 assert(rMark.IsMultiMarked());
411 if ( pAttrArray && rMark.IsMultiMarked() )
412 {
413 ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
414 SCROW nTop;
415 SCROW nBottom;
416 while (aMultiIter.Next( nTop, nBottom ))
417 pAttrArray->ChangeIndent(nTop, nBottom, bIncrement);
418 }
419}
420
421void ScColumn::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
422{
423 return ScColumnData::ChangeSelectionIndent( bIncrement, rMark, nCol );
424}
425
426void ScColumnData::ClearSelectionItems( const sal_uInt16* pWhich,const ScMarkData& rMark, SCCOL nCol )
427{
428 if (!pAttrArray)
429 return;
430
431 if (rMark.IsMultiMarked() )
432 {
433 ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
434 SCROW nTop;
435 SCROW nBottom;
436 while (aMultiIter.Next( nTop, nBottom ))
437 pAttrArray->ClearItems(nTop, nBottom, pWhich);
438 }
439 else if (rMark.IsMarked())
440 {
441 const ScRange& aRange = rMark.GetMarkArea();
442 if (aRange.aStart.Col() <= nCol && nCol <= aRange.aEnd.Col())
443 {
444 pAttrArray->ClearItems(aRange.aStart.Row(), aRange.aEnd.Row(), pWhich);
445 }
446 }
447}
448
449void ScColumn::ClearSelectionItems( const sal_uInt16* pWhich,const ScMarkData& rMark )
450{
451 ScColumnData::ClearSelectionItems( pWhich, rMark, nCol );
452}
453
454void ScColumn::DeleteSelection( InsertDeleteFlags nDelFlag, const ScMarkData& rMark, bool bBroadcast )
455{
456 SCROW nTop;
457 SCROW nBottom;
458
459 if ( rMark.IsMultiMarked() )
460 {
461 ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
462 while (aMultiIter.Next( nTop, nBottom ))
463 DeleteArea(nTop, nBottom, nDelFlag, bBroadcast);
464 }
465}
466
467void ScColumn::ApplyPattern( SCROW nRow, const ScPatternAttr& rPatAttr )
468{
469 const SfxItemSet* pSet = &rPatAttr.GetItemSet();
470 SfxItemPoolCache aCache( GetDoc().GetPool(), pSet );
471
472 const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
473
474 // true = keep old content
475
476 const ScPatternAttr* pNewPattern = static_cast<const ScPatternAttr*>( &aCache.ApplyTo( *pPattern ) );
477
478 if (pNewPattern != pPattern)
479 pAttrArray->SetPattern( nRow, pNewPattern );
480}
481
482void ScColumnData::ApplyPatternArea( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr& rPatAttr,
483 ScEditDataArray* pDataArray, bool* const pIsChanged )
484{
485 const SfxItemSet* pSet = &rPatAttr.GetItemSet();
486 SfxItemPoolCache aCache( GetDoc().GetPool(), pSet );
487 pAttrArray->ApplyCacheArea( nStartRow, nEndRow, &aCache, pDataArray, pIsChanged );
488}
489
491 const ScPatternAttr& rPattern, SvNumFormatType nNewType )
492{
493 const SfxItemSet* pSet = &rPattern.GetItemSet();
494 SfxItemPoolCache aCache( GetDoc().GetPool(), pSet );
495 SvNumberFormatter* pFormatter = GetDoc().GetFormatTable();
496 SCROW nEndRow = rRange.aEnd.Row();
497 for ( SCROW nRow = rRange.aStart.Row(); nRow <= nEndRow; nRow++ )
498 {
499 SCROW nRow1, nRow2;
500 const ScPatternAttr* pPattern = pAttrArray->GetPatternRange(
501 nRow1, nRow2, nRow );
502 sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
503 SvNumFormatType nOldType = pFormatter->GetType( nFormat );
504 if ( nOldType == nNewType || SvNumberFormatter::IsCompatible( nOldType, nNewType ) )
505 nRow = nRow2;
506 else
507 {
508 SCROW nNewRow1 = std::max( nRow1, nRow );
509 SCROW nNewRow2 = std::min( nRow2, nEndRow );
510 pAttrArray->ApplyCacheArea( nNewRow1, nNewRow2, &aCache );
511 nRow = nNewRow2;
512 }
513 }
514}
515
516void ScColumn::ApplyStyle( SCROW nRow, const ScStyleSheet* rStyle )
517{
518 const ScPatternAttr* pPattern = pAttrArray->GetPattern(nRow);
519 std::unique_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr(*pPattern));
520 pNewPattern->SetStyleSheet(const_cast<ScStyleSheet*>(rStyle));
521 pAttrArray->SetPattern(nRow, std::move(pNewPattern), true);
522}
523
525{
526 SCROW nTop;
527 SCROW nBottom;
528
529 if ( rMark.IsMultiMarked() )
530 {
531 ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
532 while (aMultiIter.Next( nTop, nBottom ))
533 pAttrArray->ApplyStyleArea(nTop, nBottom, rStyle);
534 }
535}
536
538 const SvxBorderLine* pLine, bool bColorOnly )
539{
540 if ( bColorOnly && !pLine )
541 return;
542
543 SCROW nTop;
544 SCROW nBottom;
545
546 if (rMark.IsMultiMarked())
547 {
548 ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
549 while (aMultiIter.Next( nTop, nBottom ))
550 pAttrArray->ApplyLineStyleArea(nTop, nBottom, pLine, bColorOnly );
551 }
552}
553
554const ScStyleSheet* ScColumn::GetSelectionStyle( const ScMarkData& rMark, bool& rFound ) const
555{
556 rFound = false;
557 if (!rMark.IsMultiMarked())
558 {
559 OSL_FAIL("No selection in ScColumn::GetSelectionStyle");
560 return nullptr;
561 }
562
563 bool bEqual = true;
564
565 const ScStyleSheet* pStyle = nullptr;
566 const ScStyleSheet* pNewStyle;
567
568 ScDocument& rDocument = GetDoc();
569 ScMultiSelIter aMultiIter( rMark.GetMultiSelData(), nCol );
570 SCROW nTop;
571 SCROW nBottom;
572 while (bEqual && aMultiIter.Next( nTop, nBottom ))
573 {
574 ScAttrIterator aAttrIter( pAttrArray.get(), nTop, nBottom, rDocument.GetDefPattern() );
575 SCROW nRow;
576 SCROW nDummy;
577 while (bEqual)
578 {
579 const ScPatternAttr* pPattern = aAttrIter.Next( nRow, nDummy );
580 if (!pPattern)
581 break;
582 pNewStyle = pPattern->GetStyleSheet();
583 rFound = true;
584 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
585 bEqual = false; // difference
586 pStyle = pNewStyle;
587 }
588 }
589
590 return bEqual ? pStyle : nullptr;
591}
592
593const ScStyleSheet* ScColumn::GetAreaStyle( bool& rFound, SCROW nRow1, SCROW nRow2 ) const
594{
595 rFound = false;
596
597 bool bEqual = true;
598
599 const ScStyleSheet* pStyle = nullptr;
600 const ScStyleSheet* pNewStyle;
601
602 ScAttrIterator aAttrIter( pAttrArray.get(), nRow1, nRow2, GetDoc().GetDefPattern() );
603 SCROW nRow;
604 SCROW nDummy;
605 while (bEqual)
606 {
607 const ScPatternAttr* pPattern = aAttrIter.Next( nRow, nDummy );
608 if (!pPattern)
609 break;
610 pNewStyle = pPattern->GetStyleSheet();
611 rFound = true;
612 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
613 bEqual = false; // difference
614 pStyle = pNewStyle;
615 }
616
617 return bEqual ? pStyle : nullptr;
618}
619
620void ScColumn::ApplyAttr( SCROW nRow, const SfxPoolItem& rAttr )
621{
622 // in order to only create a new SetItem, we don't need SfxItemPoolCache.
623 //TODO: Warning: SfxItemPoolCache seems to create too many Refs for the new SetItem ??
624
625 ScDocumentPool* pDocPool = GetDoc().GetPool();
626
627 const ScPatternAttr* pOldPattern = pAttrArray->GetPattern( nRow );
628 ScPatternAttr aTemp(*pOldPattern);
629 aTemp.GetItemSet().Put(rAttr);
630 const ScPatternAttr* pNewPattern = &pDocPool->Put( aTemp );
631
632 if ( pNewPattern != pOldPattern )
633 pAttrArray->SetPattern( nRow, pNewPattern );
634 else
635 pDocPool->Remove( *pNewPattern ); // free up resources
636}
637
639{
640 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
641 if (aPos.first == maCells.end())
642 return ScRefCellValue();
643
644 return GetCellValue(aPos.first, aPos.second);
645}
646
648{
649 std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(rBlockPos.miCellPos, nRow);
650 if (aPos.first == maCells.end())
651 return ScRefCellValue();
652
653 rBlockPos.miCellPos = aPos.first; // Store this for next call.
654 return GetCellValue(aPos.first, aPos.second);
655}
656
658{
659 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rBlockPos.miCellPos, nRow);
660 if (aPos.first == maCells.end())
661 return ScRefCellValue();
662
663 rBlockPos.miCellPos = aPos.first; // Store this for next call.
664 return GetCellValue(aPos.first, aPos.second);
665}
666
667ScRefCellValue ScColumn::GetCellValue( const sc::CellStoreType::const_iterator& itPos, size_t nOffset )
668{
669 switch (itPos->type)
670 {
672 // Numeric cell
673 return ScRefCellValue(sc::numeric_block::at(*itPos->data, nOffset));
674 break;
676 // String cell
677 return ScRefCellValue(&sc::string_block::at(*itPos->data, nOffset));
678 break;
680 // Edit cell
681 return ScRefCellValue(sc::edittext_block::at(*itPos->data, nOffset));
682 break;
684 // Formula cell
685 return ScRefCellValue(sc::formula_block::at(*itPos->data, nOffset));
686 break;
687 default:
688 return ScRefCellValue(); // empty cell
689 }
690}
691
693{
695 aBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
696 return GetCellTextAttr(aBlockPos, nRow);
697}
698
700{
701 sc::CellTextAttrStoreType::const_position_type aPos = maCellTextAttrs.position(rBlockPos.miCellTextAttrPos, nRow);
702 if (aPos.first == maCellTextAttrs.end())
703 return nullptr;
704
705 rBlockPos.miCellTextAttrPos = aPos.first;
706
707 if (aPos.first->type != sc::element_type_celltextattr)
708 return nullptr;
709
710 return &sc::celltextattr_block::at(*aPos.first->data, aPos.second);
711}
712
713bool ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
714{
715 if (IsEmptyData() && IsEmptyAttr())
716 return true;
717
718 // Return false if we have any non-empty cells between nStartRow and nEndRow inclusive.
719 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
720 sc::CellStoreType::const_iterator it = aPos.first;
721 if (it->type != sc::element_type_empty)
722 return false;
723
724 // Get the length of the remaining empty segment.
725 size_t nLen = it->size - aPos.second;
726 SCROW nNextNonEmptyRow = nStartRow + nLen;
727 if (nNextNonEmptyRow <= nEndRow)
728 return false;
729
730 // AttrArray only looks for merged cells
731
732 return pAttrArray == nullptr || pAttrArray->TestInsertCol(nStartRow, nEndRow);
733}
734
735bool ScColumn::TestInsertRow( SCROW nStartRow, SCSIZE nSize ) const
736{
737 // AttrArray only looks for merged cells
738 {
739 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
740 sc::CellStoreType::const_iterator it = aPos.first;
741 if (it->type == sc::element_type_empty && maCells.block_size() == 1)
742 // The entire cell array is empty.
743 return pAttrArray->TestInsertRow(nSize);
744 }
745
746 // See if there would be any non-empty cell that gets pushed out.
747
748 // Find the position of the last non-empty cell below nStartRow.
749 size_t nLastNonEmptyRow = GetDoc().MaxRow();
750 sc::CellStoreType::const_reverse_iterator it = maCells.rbegin();
751 if (it->type == sc::element_type_empty)
752 nLastNonEmptyRow -= it->size;
753
754 if (nLastNonEmptyRow < o3tl::make_unsigned(nStartRow))
755 // No cells would get pushed out.
756 return pAttrArray->TestInsertRow(nSize);
757
758 if (nLastNonEmptyRow + nSize > o3tl::make_unsigned(GetDoc().MaxRow()))
759 // At least one cell would get pushed out. Not good.
760 return false;
761
762 return pAttrArray->TestInsertRow(nSize);
763}
764
765void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
766{
767 pAttrArray->InsertRow( nStartRow, nSize );
768
769 maCellNotes.insert_empty(nStartRow, nSize);
770 maCellNotes.resize(GetDoc().GetMaxRowCount());
771
772 maSparklines.insert_empty(nStartRow, nSize);
773 maSparklines.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
774
775 maBroadcasters.insert_empty(nStartRow, nSize);
776 maBroadcasters.resize(GetDoc().GetMaxRowCount());
777
778 maCellTextAttrs.insert_empty(nStartRow, nSize);
779 maCellTextAttrs.resize(GetDoc().GetMaxRowCount());
780
781 maCells.insert_empty(nStartRow, nSize);
782 maCells.resize(GetDoc().GetMaxRowCount());
783
785
786 // We *probably* don't need to broadcast here since the parent call seems
787 // to take care of it.
788}
789
790namespace {
791
792class CopyToClipHandler
793{
794 const ScDocument& mrSrcDoc;
795 const ScColumn& mrSrcCol;
796 ScColumn& mrDestCol;
797 sc::ColumnBlockPosition maDestPos;
798 sc::ColumnBlockPosition* mpDestPos;
799
800 void setDefaultAttrsToDest(size_t nRow, size_t nSize)
801 {
802 std::vector<sc::CellTextAttr> aAttrs(nSize); // default values
803 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
804 maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
805 }
806
807public:
808 CopyToClipHandler(const ScDocument& rSrcDoc, const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos) :
809 mrSrcDoc(rSrcDoc), mrSrcCol(rSrcCol), mrDestCol(rDestCol), mpDestPos(pDestPos)
810 {
811 if (mpDestPos)
812 maDestPos = *mpDestPos;
813 else
814 mrDestCol.InitBlockPosition(maDestPos);
815 }
816
817 ~CopyToClipHandler()
818 {
819 if (mpDestPos)
820 *mpDestPos = maDestPos;
821 }
822
823 void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
824 {
825 size_t nTopRow = aNode.position + nOffset;
826
827 bool bSet = true;
828
829 switch (aNode.type)
830 {
832 {
833 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aNode.data);
834 std::advance(it, nOffset);
835 sc::numeric_block::const_iterator itEnd = it;
836 std::advance(itEnd, nDataSize);
837 maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nTopRow, it, itEnd);
838 }
839 break;
841 {
842 sc::string_block::const_iterator it = sc::string_block::begin(*aNode.data);
843 std::advance(it, nOffset);
844 sc::string_block::const_iterator itEnd = it;
845 std::advance(itEnd, nDataSize);
846 maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nTopRow, it, itEnd);
847
848 }
849 break;
851 {
852 sc::edittext_block::const_iterator it = sc::edittext_block::begin(*aNode.data);
853 std::advance(it, nOffset);
854 sc::edittext_block::const_iterator itEnd = it;
855 std::advance(itEnd, nDataSize);
856
857 std::vector<EditTextObject*> aCloned;
858 aCloned.reserve(nDataSize);
859 for (; it != itEnd; ++it)
860 aCloned.push_back(ScEditUtil::Clone(**it, mrDestCol.GetDoc()).release());
861
862 maDestPos.miCellPos = mrDestCol.GetCellStore().set(
863 maDestPos.miCellPos, nTopRow, aCloned.begin(), aCloned.end());
864 }
865 break;
867 {
868 sc::formula_block::const_iterator it = sc::formula_block::begin(*aNode.data);
869 std::advance(it, nOffset);
870 sc::formula_block::const_iterator itEnd = it;
871 std::advance(itEnd, nDataSize);
872
873 std::vector<ScFormulaCell*> aCloned;
874 aCloned.reserve(nDataSize);
875 ScAddress aDestPos(mrDestCol.GetCol(), nTopRow, mrDestCol.GetTab());
876 for (; it != itEnd; ++it, aDestPos.IncRow())
877 {
878 const ScFormulaCell& rOld = **it;
879 if (rOld.GetDirty() && mrSrcCol.GetDoc().GetAutoCalc())
880 const_cast<ScFormulaCell&>(rOld).Interpret();
881
882 aCloned.push_back(new ScFormulaCell(rOld, mrDestCol.GetDoc(), aDestPos));
883 }
884
885 // Group the cloned formula cells.
886 if (!aCloned.empty())
887 sc::SharedFormulaUtil::groupFormulaCells(aCloned.begin(), aCloned.end());
888
889 sc::CellStoreType& rDestCells = mrDestCol.GetCellStore();
890 maDestPos.miCellPos = rDestCells.set(
891 maDestPos.miCellPos, nTopRow, aCloned.begin(), aCloned.end());
892
893 // Merge adjacent formula cell groups (if applicable).
894 sc::CellStoreType::position_type aPos =
895 rDestCells.position(maDestPos.miCellPos, nTopRow);
896 maDestPos.miCellPos = aPos.first;
898 size_t nLastRow = nTopRow + nDataSize;
899 if (nLastRow < o3tl::make_unsigned(mrSrcDoc.MaxRow()))
900 {
901 aPos = rDestCells.position(maDestPos.miCellPos, nLastRow+1);
903 }
904 }
905 break;
906 default:
907 bSet = false;
908 }
909
910 if (bSet)
911 setDefaultAttrsToDest(nTopRow, nDataSize);
912
913 mrSrcCol.DuplicateNotes(nTopRow, nDataSize, mrDestCol, maDestPos, false);
914 mrSrcCol.DuplicateSparklines(nTopRow, nDataSize, mrDestCol, maDestPos);
915 }
916};
917
918class CopyTextAttrToClipHandler
919{
920 sc::CellTextAttrStoreType& mrDestAttrs;
921 sc::CellTextAttrStoreType::iterator miPos;
922
923public:
924 explicit CopyTextAttrToClipHandler( sc::CellTextAttrStoreType& rAttrs ) :
925 mrDestAttrs(rAttrs), miPos(mrDestAttrs.begin()) {}
926
927 void operator() ( const sc::CellTextAttrStoreType::value_type& aNode, size_t nOffset, size_t nDataSize )
928 {
929 if (aNode.type != sc::element_type_celltextattr)
930 return;
931
932 sc::celltextattr_block::const_iterator it = sc::celltextattr_block::begin(*aNode.data);
933 std::advance(it, nOffset);
934 sc::celltextattr_block::const_iterator itEnd = it;
935 std::advance(itEnd, nDataSize);
936
937 size_t nPos = aNode.position + nOffset;
938 miPos = mrDestAttrs.set(miPos, nPos, it, itEnd);
939 }
940};
941
942
943}
944
946 sc::CopyToClipContext& rCxt, SCROW nRow1, SCROW nRow2, ScColumn& rColumn ) const
947{
948 pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray,
950
951 {
952 CopyToClipHandler aFunc(GetDoc(), *this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol));
953 sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
954 }
955
956 {
957 CopyTextAttrToClipHandler aFunc(rColumn.maCellTextAttrs);
958 sc::ParseBlock(maCellTextAttrs.begin(), maCellTextAttrs, aFunc, nRow1, nRow2);
959 }
960
961 rColumn.CellStorageModified();
962}
963
965 SCROW nRow1, SCROW nRow2, const SvNumberFormatterMergeMap& rMap, ScColumn& rDestCol )
966{
967 if (nRow1 > nRow2)
968 return;
969
971 CopyCellTextAttrsToDocument(nRow1, nRow2, rDestCol);
972 CopyCellNotesToDocument(nRow1, nRow2, rDestCol);
973
974 // First, clear the destination column for the specified row range.
975 rDestCol.maCells.set_empty(nRow1, nRow2);
976
977 aDestPos.miCellPos = rDestCol.maCells.begin();
978
979 ScDocument& rDocument = GetDoc();
980 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
981 sc::CellStoreType::const_iterator it = aPos.first;
982 size_t nOffset = aPos.second;
983 size_t nDataSize = 0;
984 size_t nCurRow = nRow1;
985
986 for (; it != maCells.end() && nCurRow <= o3tl::make_unsigned(nRow2); ++it, nOffset = 0, nCurRow += nDataSize)
987 {
988 bool bLastBlock = false;
989 nDataSize = it->size - nOffset;
990 if (nCurRow + nDataSize - 1 > o3tl::make_unsigned(nRow2))
991 {
992 // Truncate the block to copy to clipboard.
993 nDataSize = nRow2 - nCurRow + 1;
994 bLastBlock = true;
995 }
996
997 switch (it->type)
998 {
1000 {
1001 sc::numeric_block::const_iterator itData = sc::numeric_block::begin(*it->data);
1002 std::advance(itData, nOffset);
1003 sc::numeric_block::const_iterator itDataEnd = itData;
1004 std::advance(itDataEnd, nDataSize);
1005 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, itData, itDataEnd);
1006 }
1007 break;
1009 {
1010 sc::string_block::const_iterator itData = sc::string_block::begin(*it->data);
1011 std::advance(itData, nOffset);
1012 sc::string_block::const_iterator itDataEnd = itData;
1013 std::advance(itDataEnd, nDataSize);
1014 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, itData, itDataEnd);
1015 }
1016 break;
1018 {
1019 sc::edittext_block::const_iterator itData = sc::edittext_block::begin(*it->data);
1020 std::advance(itData, nOffset);
1021 sc::edittext_block::const_iterator itDataEnd = itData;
1022 std::advance(itDataEnd, nDataSize);
1023
1024 // Convert to simple strings.
1025 std::vector<svl::SharedString> aConverted;
1026 aConverted.reserve(nDataSize);
1027 for (; itData != itDataEnd; ++itData)
1028 {
1029 const EditTextObject& rObj = **itData;
1030 svl::SharedString aSS = rDocument.GetSharedStringPool().intern(ScEditUtil::GetString(rObj, &rDocument));
1031 aConverted.push_back(aSS);
1032 }
1033 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, aConverted.begin(), aConverted.end());
1034 }
1035 break;
1037 {
1038 sc::formula_block::const_iterator itData = sc::formula_block::begin(*it->data);
1039 std::advance(itData, nOffset);
1040 sc::formula_block::const_iterator itDataEnd = itData;
1041 std::advance(itDataEnd, nDataSize);
1042
1043 // Interpret and convert to raw values.
1044 for (SCROW i = 0; itData != itDataEnd; ++itData, ++i)
1045 {
1046 SCROW nRow = nCurRow + i;
1047
1048 ScFormulaCell& rFC = **itData;
1049 if (rFC.GetDirty() && rDocument.GetAutoCalc())
1050 rFC.Interpret();
1051
1052 if (rFC.GetErrCode() != FormulaError::NONE)
1053 // Skip cells with error.
1054 continue;
1055
1056 if (rFC.IsValue())
1057 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nRow, rFC.GetValue());
1058 else
1059 {
1060 svl::SharedString aSS = rFC.GetString();
1061 if (aSS.isValid())
1062 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nRow, aSS);
1063 }
1064 }
1065 }
1066 break;
1067 default:
1068 ;
1069 }
1070
1071 if (bLastBlock)
1072 break;
1073 }
1074
1075 // Don't forget to copy the number formats over. Charts may reference them.
1076 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
1077 {
1078 sal_uInt32 nNumFmt = GetNumberFormat(rDocument.GetNonThreadedContext(), nRow);
1079 SvNumberFormatterMergeMap::const_iterator itNum = rMap.find(nNumFmt);
1080 if (itNum != rMap.end())
1081 nNumFmt = itNum->second;
1082
1083 rDestCol.SetNumberFormat(nRow, nNumFmt);
1084 }
1085
1086 rDestCol.CellStorageModified();
1087}
1088
1089void ScColumn::CopyCellToDocument( SCROW nSrcRow, SCROW nDestRow, ScColumn& rDestCol )
1090{
1091 ScDocument& rDocument = GetDoc();
1092 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nSrcRow);
1093 sc::CellStoreType::const_iterator it = aPos.first;
1094 bool bSet = true;
1095 switch (it->type)
1096 {
1098 rDestCol.maCells.set(nDestRow, sc::numeric_block::at(*it->data, aPos.second));
1099 break;
1101 rDestCol.maCells.set(nDestRow, sc::string_block::at(*it->data, aPos.second));
1102 break;
1104 {
1105 EditTextObject* p = sc::edittext_block::at(*it->data, aPos.second);
1106 if (&rDocument == &rDestCol.GetDoc())
1107 rDestCol.maCells.set(nDestRow, p->Clone().release());
1108 else
1109 rDestCol.maCells.set(nDestRow, ScEditUtil::Clone(*p, rDestCol.GetDoc()).release());
1110 }
1111 break;
1113 {
1114 ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
1115 if (p->GetDirty() && rDocument.GetAutoCalc())
1116 p->Interpret();
1117
1118 ScAddress aDestPos = p->aPos;
1119 aDestPos.SetRow(nDestRow);
1120 ScFormulaCell* pNew = new ScFormulaCell(*p, rDestCol.GetDoc(), aDestPos);
1121 rDestCol.SetFormulaCell(nDestRow, pNew);
1122 }
1123 break;
1125 default:
1126 // empty
1127 rDestCol.maCells.set_empty(nDestRow, nDestRow);
1128 bSet = false;
1129 }
1130
1131 if (bSet)
1132 {
1133 rDestCol.maCellTextAttrs.set(nDestRow, maCellTextAttrs.get<sc::CellTextAttr>(nSrcRow));
1134 ScPostIt* pNote = maCellNotes.get<ScPostIt*>(nSrcRow);
1135 if (pNote)
1136 {
1137 pNote = pNote->Clone(ScAddress(nCol, nSrcRow, nTab),
1138 rDestCol.GetDoc(),
1139 ScAddress(rDestCol.nCol, nDestRow, rDestCol.nTab),
1140 false).release();
1141 rDestCol.maCellNotes.set(nDestRow, pNote);
1142 pNote->UpdateCaptionPos(ScAddress(rDestCol.nCol, nDestRow, rDestCol.nTab));
1143 }
1144 else
1145 rDestCol.maCellNotes.set_empty(nDestRow, nDestRow);
1146 }
1147 else
1148 {
1149 rDestCol.maCellTextAttrs.set_empty(nDestRow, nDestRow);
1150 rDestCol.maCellNotes.set_empty(nDestRow, nDestRow);
1151 }
1152
1153 rDestCol.CellStorageModified();
1154}
1155
1156namespace {
1157
1158bool canCopyValue(const ScDocument& rDoc, const ScAddress& rPos, InsertDeleteFlags nFlags)
1159{
1160 sal_uInt32 nNumIndex = rDoc.GetAttr(rPos, ATTR_VALUE_FORMAT)->GetValue();
1161 SvNumFormatType nType = rDoc.GetFormatTable()->GetType(nNumIndex);
1162 if ((nType == SvNumFormatType::DATE) || (nType == SvNumFormatType::TIME) || (nType == SvNumFormatType::DATETIME))
1164
1166}
1167
1168class CopyAsLinkHandler
1169{
1170 const ScColumn& mrSrcCol;
1171 ScColumn& mrDestCol;
1172 sc::ColumnBlockPosition maDestPos;
1173 sc::ColumnBlockPosition* mpDestPos;
1174 InsertDeleteFlags mnCopyFlags;
1175
1176 sc::StartListeningType meListenType;
1177
1178 void setDefaultAttrToDest(size_t nRow)
1179 {
1180 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1181 maDestPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
1182 }
1183
1184 void setDefaultAttrsToDest(size_t nRow, size_t nSize)
1185 {
1186 std::vector<sc::CellTextAttr> aAttrs(nSize); // default values
1187 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1188 maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
1189 }
1190
1191 ScFormulaCell* createRefCell(size_t nRow)
1192 {
1193 ScSingleRefData aRef;
1194 aRef.InitAddress(ScAddress(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab())); // Absolute reference.
1195 aRef.SetFlag3D(true);
1196
1197 ScTokenArray aArr(mrDestCol.GetDoc());
1198 aArr.AddSingleReference(aRef);
1199 return new ScFormulaCell(mrDestCol.GetDoc(), ScAddress(mrDestCol.GetCol(), nRow, mrDestCol.GetTab()), aArr);
1200 }
1201
1202 void createRefBlock(const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
1203 {
1204 size_t nTopRow = aNode.position + nOffset;
1205
1206 for (size_t i = 0; i < nDataSize; ++i)
1207 {
1208 SCROW nRow = nTopRow + i;
1209 mrDestCol.SetFormulaCell(maDestPos, nRow, createRefCell(nRow), meListenType);
1210 }
1211
1212 setDefaultAttrsToDest(nTopRow, nDataSize);
1213 }
1214
1215public:
1216 CopyAsLinkHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos, InsertDeleteFlags nCopyFlags) :
1217 mrSrcCol(rSrcCol),
1218 mrDestCol(rDestCol),
1219 mpDestPos(pDestPos),
1220 mnCopyFlags(nCopyFlags),
1221 meListenType(sc::SingleCellListening)
1222 {
1223 if (mpDestPos)
1224 maDestPos = *mpDestPos;
1225 }
1226
1227 ~CopyAsLinkHandler()
1228 {
1229 if (mpDestPos)
1230 {
1231 // Similar to CopyByCloneHandler, don't copy a singular iterator.
1232 {
1233 sc::ColumnBlockPosition aTempBlock;
1234 mrDestCol.InitBlockPosition(aTempBlock);
1235 maDestPos.miBroadcasterPos = aTempBlock.miBroadcasterPos;
1236 }
1237
1238 *mpDestPos = maDestPos;
1239 }
1240 }
1241
1242 void setStartListening( bool b )
1243 {
1244 meListenType = b ? sc::SingleCellListening : sc::NoListening;
1245 }
1246
1247 void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
1248 {
1249 size_t nRow = aNode.position + nOffset;
1250
1252 {
1253 bool bCloneCaption = (mnCopyFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE;
1254 mrSrcCol.DuplicateNotes(nRow, nDataSize, mrDestCol, maDestPos, bCloneCaption);
1255 }
1256
1257 switch (aNode.type)
1258 {
1260 {
1262 return;
1263
1264 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aNode.data);
1265 std::advance(it, nOffset);
1266 sc::numeric_block::const_iterator itEnd = it;
1267 std::advance(itEnd, nDataSize);
1268
1269 ScAddress aSrcPos(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab());
1270 for (; it != itEnd; ++it, aSrcPos.IncRow(), ++nRow)
1271 {
1272 if (!canCopyValue(mrSrcCol.GetDoc(), aSrcPos, mnCopyFlags))
1273 continue;
1274
1275 maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, createRefCell(nRow));
1276 setDefaultAttrToDest(nRow);
1277 }
1278 }
1279 break;
1282 {
1283 if (!(mnCopyFlags & InsertDeleteFlags::STRING))
1284 return;
1285
1286 createRefBlock(aNode, nOffset, nDataSize);
1287 }
1288 break;
1290 {
1291 if (!(mnCopyFlags & InsertDeleteFlags::FORMULA))
1292 return;
1293
1294 createRefBlock(aNode, nOffset, nDataSize);
1295 }
1296 break;
1297 default:
1298 ;
1299 }
1300 }
1301};
1302
1303class CopyByCloneHandler
1304{
1305 const ScColumn& mrSrcCol;
1306 ScColumn& mrDestCol;
1307 sc::ColumnBlockPosition maDestPos;
1308 sc::ColumnBlockPosition* mpDestPos;
1309 svl::SharedStringPool* mpSharedStringPool;
1310 InsertDeleteFlags mnCopyFlags;
1311
1312 sc::StartListeningType meListenType;
1313 ScCloneFlags mnFormulaCellCloneFlags;
1314
1315 void setDefaultAttrToDest(size_t nRow)
1316 {
1317 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1318 maDestPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
1319 }
1320
1321 void setDefaultAttrsToDest(size_t nRow, size_t nSize)
1322 {
1323 std::vector<sc::CellTextAttr> aAttrs(nSize); // default values
1324 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
1325 maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
1326 }
1327
1328 void cloneFormulaCell(size_t nRow, ScFormulaCell& rSrcCell)
1329 {
1330 ScAddress aDestPos(mrDestCol.GetCol(), nRow, mrDestCol.GetTab());
1331
1332 bool bCloneValue = (mnCopyFlags & InsertDeleteFlags::VALUE) != InsertDeleteFlags::NONE;
1333 bool bCloneDateTime = (mnCopyFlags & InsertDeleteFlags::DATETIME) != InsertDeleteFlags::NONE;
1334 bool bCloneString = (mnCopyFlags & InsertDeleteFlags::STRING) != InsertDeleteFlags::NONE;
1335 bool bCloneSpecialBoolean = (mnCopyFlags & InsertDeleteFlags::SPECIAL_BOOLEAN) != InsertDeleteFlags::NONE;
1336 bool bCloneFormula = (mnCopyFlags & InsertDeleteFlags::FORMULA) != InsertDeleteFlags::NONE;
1337
1338 bool bForceFormula = false;
1339
1340 if (bCloneSpecialBoolean)
1341 {
1342 // See if the formula consists of =TRUE() or =FALSE().
1343 const ScTokenArray* pCode = rSrcCell.GetCode();
1344 if (pCode && pCode->GetLen() == 1)
1345 {
1346 const formula::FormulaToken* p = pCode->FirstToken();
1347 if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse)
1348 // This is a boolean formula.
1349 bForceFormula = true;
1350 }
1351 }
1352
1353 if (bForceFormula || bCloneFormula)
1354 {
1355 // Clone as formula cell.
1356 ScFormulaCell* pCell = new ScFormulaCell(rSrcCell, mrDestCol.GetDoc(), aDestPos, mnFormulaCellCloneFlags);
1357 pCell->SetDirtyVar();
1358 mrDestCol.SetFormulaCell(maDestPos, nRow, pCell, meListenType, rSrcCell.NeedsNumberFormat());
1359 setDefaultAttrToDest(nRow);
1360 return;
1361 }
1362
1363 if (mrDestCol.GetDoc().IsUndo())
1364 return;
1365
1366 if (bCloneValue)
1367 {
1368 FormulaError nErr = rSrcCell.GetErrCode();
1369 if (nErr != FormulaError::NONE)
1370 {
1371 // error codes are cloned with values
1372 ScFormulaCell* pErrCell = new ScFormulaCell(mrDestCol.GetDoc(), aDestPos);
1373 pErrCell->SetErrCode(nErr);
1374 mrDestCol.SetFormulaCell(maDestPos, nRow, pErrCell, meListenType);
1375 setDefaultAttrToDest(nRow);
1376 return;
1377 }
1378 }
1379
1380 if (bCloneValue || bCloneDateTime)
1381 {
1382 if (rSrcCell.IsValue())
1383 {
1384 if (canCopyValue(mrSrcCol.GetDoc(), ScAddress(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab()), mnCopyFlags))
1385 {
1386 maDestPos.miCellPos = mrDestCol.GetCellStore().set(
1387 maDestPos.miCellPos, nRow, rSrcCell.GetValue());
1388 setDefaultAttrToDest(nRow);
1389 }
1390
1391 return;
1392 }
1393 }
1394
1395 if (!bCloneString)
1396 return;
1397
1398 svl::SharedString aStr = rSrcCell.GetString();
1399 if (aStr.isEmpty())
1400 // Don't create empty string cells.
1401 return;
1402
1403 if (rSrcCell.IsMultilineResult())
1404 {
1405 // Clone as an edit text object.
1406 EditEngine& rEngine = mrDestCol.GetDoc().GetEditEngine();
1407 rEngine.SetText(aStr.getString());
1408 maDestPos.miCellPos =
1409 mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, rEngine.CreateTextObject().release());
1410 }
1411 else
1412 {
1413 maDestPos.miCellPos =
1414 mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, aStr);
1415 }
1416
1417 setDefaultAttrToDest(nRow);
1418 }
1419
1420public:
1421 CopyByCloneHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos,
1422 InsertDeleteFlags nCopyFlags, svl::SharedStringPool* pSharedStringPool, bool bGlobalNamesToLocal) :
1423 mrSrcCol(rSrcCol),
1424 mrDestCol(rDestCol),
1425 mpDestPos(pDestPos),
1426 mpSharedStringPool(pSharedStringPool),
1427 mnCopyFlags(nCopyFlags),
1428 meListenType(sc::SingleCellListening),
1429 mnFormulaCellCloneFlags(bGlobalNamesToLocal ? ScCloneFlags::NamesToLocal : ScCloneFlags::Default)
1430 {
1431 if (mpDestPos)
1432 maDestPos = *mpDestPos;
1433 }
1434
1435 ~CopyByCloneHandler()
1436 {
1437 if (!mpDestPos)
1438 return;
1439
1440 // If broadcasters were setup in the same column,
1441 // maDestPos.miBroadcasterPos doesn't match
1442 // mrDestCol.maBroadcasters because it is never passed anywhere.
1443 // Assign a corresponding iterator before copying all over.
1444 // Otherwise this may result in wrongly copying a singular
1445 // iterator.
1446
1447 {
1448 /* XXX Using a temporary ColumnBlockPosition just for
1449 * initializing from ScColumn::maBroadcasters.begin() is ugly,
1450 * on the other hand we don't want to expose
1451 * ScColumn::maBroadcasters to the outer world and have a
1452 * getter. */
1453 sc::ColumnBlockPosition aTempBlock;
1454 mrDestCol.InitBlockPosition(aTempBlock);
1455 maDestPos.miBroadcasterPos = aTempBlock.miBroadcasterPos;
1456 }
1457
1458 *mpDestPos = maDestPos;
1459 }
1460
1461 void setStartListening( bool b )
1462 {
1463 meListenType = b ? sc::SingleCellListening : sc::NoListening;
1464 }
1465
1466 void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
1467 {
1468 size_t nRow = aNode.position + nOffset;
1469
1471 {
1472 bool bCloneCaption = (mnCopyFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE;
1473 mrSrcCol.DuplicateNotes(nRow, nDataSize, mrDestCol, maDestPos, bCloneCaption);
1474 }
1475
1476 switch (aNode.type)
1477 {
1479 {
1481 return;
1482
1483 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aNode.data);
1484 std::advance(it, nOffset);
1485 sc::numeric_block::const_iterator itEnd = it;
1486 std::advance(itEnd, nDataSize);
1487
1488 ScAddress aSrcPos(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab());
1489 for (; it != itEnd; ++it, aSrcPos.IncRow(), ++nRow)
1490 {
1491 if (!canCopyValue(mrSrcCol.GetDoc(), aSrcPos, mnCopyFlags))
1492 continue;
1493
1494 maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, *it);
1495 setDefaultAttrToDest(nRow);
1496 }
1497 }
1498 break;
1500 {
1501 if (!(mnCopyFlags & InsertDeleteFlags::STRING))
1502 return;
1503
1504 sc::string_block::const_iterator it = sc::string_block::begin(*aNode.data);
1505 std::advance(it, nOffset);
1506 sc::string_block::const_iterator itEnd = it;
1507 std::advance(itEnd, nDataSize);
1508
1509 for (; it != itEnd; ++it, ++nRow)
1510 {
1511 const svl::SharedString& rStr = *it;
1512 if (rStr.isEmpty())
1513 {
1514 // String cell with empty value is used to special-case cell value removal.
1515 maDestPos.miCellPos = mrDestCol.GetCellStore().set_empty(
1516 maDestPos.miCellPos, nRow, nRow);
1517 maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set_empty(
1518 maDestPos.miCellTextAttrPos, nRow, nRow);
1519 }
1520 else
1521 {
1522 if (mpSharedStringPool)
1523 {
1524 // Re-intern the string if source is a different document.
1525 svl::SharedString aInterned = mpSharedStringPool->intern( rStr.getString());
1526 maDestPos.miCellPos =
1527 mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, aInterned);
1528 }
1529 else
1530 {
1531 maDestPos.miCellPos =
1532 mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, rStr);
1533 }
1534 setDefaultAttrToDest(nRow);
1535 }
1536 }
1537 }
1538 break;
1540 {
1541 if (!(mnCopyFlags & InsertDeleteFlags::STRING))
1542 return;
1543
1544 sc::edittext_block::const_iterator it = sc::edittext_block::begin(*aNode.data);
1545 std::advance(it, nOffset);
1546 sc::edittext_block::const_iterator itEnd = it;
1547 std::advance(itEnd, nDataSize);
1548
1549 std::vector<EditTextObject*> aCloned;
1550 aCloned.reserve(nDataSize);
1551 for (; it != itEnd; ++it)
1552 aCloned.push_back(ScEditUtil::Clone(**it, mrDestCol.GetDoc()).release());
1553
1554 maDestPos.miCellPos = mrDestCol.GetCellStore().set(
1555 maDestPos.miCellPos, nRow, aCloned.begin(), aCloned.end());
1556
1557 setDefaultAttrsToDest(nRow, nDataSize);
1558 }
1559 break;
1561 {
1562 sc::formula_block::const_iterator it = sc::formula_block::begin(*aNode.data);
1563 std::advance(it, nOffset);
1564 sc::formula_block::const_iterator itEnd = it;
1565 std::advance(itEnd, nDataSize);
1566
1567 sc::DelayStartListeningFormulaCells startDelay(mrDestCol); // disabled
1568 if(nDataSize > 1024 && (mnCopyFlags & InsertDeleteFlags::FORMULA) != InsertDeleteFlags::NONE)
1569 {
1570 // If the column to be replaced contains a long formula group (tdf#102364), there can
1571 // be so many listeners in a single vector that the quadratic cost of repeatedly removing
1572 // the first element becomes very high. Optimize this by removing them in one go.
1573 sc::EndListeningContext context(mrDestCol.GetDoc());
1574 mrDestCol.EndListeningFormulaCells( context, nRow, nRow + nDataSize - 1, nullptr, nullptr );
1575 // There can be a similar problem with starting to listen to cells repeatedly (tdf#133302).
1576 // Delay it.
1577 startDelay.set();
1578 }
1579
1580 for (; it != itEnd; ++it, ++nRow)
1581 cloneFormulaCell(nRow, **it);
1582 }
1583 break;
1584 default:
1585 ;
1586 }
1587 }
1588};
1589
1590}
1591
1594 SCROW nRow1, SCROW nRow2, InsertDeleteFlags nFlags, bool bMarked, ScColumn& rColumn,
1595 const ScMarkData* pMarkData, bool bAsLink, bool bGlobalNamesToLocal) const
1596{
1597 if (bMarked)
1598 {
1599 SCROW nStart, nEnd;
1600 if (pMarkData && pMarkData->IsMultiMarked())
1601 {
1602 ScMultiSelIter aIter( pMarkData->GetMultiSelData(), nCol );
1603
1604 while ( aIter.Next( nStart, nEnd ) && nStart <= nRow2 )
1605 {
1606 if ( nEnd >= nRow1 )
1607 CopyToColumn(rCxt, std::max(nRow1,nStart), std::min(nRow2,nEnd),
1608 nFlags, false, rColumn, pMarkData, bAsLink );
1609 }
1610 }
1611 else
1612 {
1613 OSL_FAIL("CopyToColumn: bMarked, but no mark");
1614 }
1615 return;
1616 }
1617
1619 {
1621 { // keep the StyleSheets in the target document
1622 // e.g. DIF and RTF Clipboard-Import
1623 for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ )
1624 {
1625 const ScStyleSheet* pStyle =
1626 rColumn.pAttrArray->GetPattern( nRow )->GetStyleSheet();
1627 const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
1628 std::unique_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr( *pPattern ));
1629 pNewPattern->SetStyleSheet( const_cast<ScStyleSheet*>(pStyle) );
1630 rColumn.pAttrArray->SetPattern( nRow, std::move(pNewPattern), true );
1631 }
1632 }
1633 else
1634 pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray);
1635 }
1636
1638 return;
1639
1640 if (bAsLink)
1641 {
1642 CopyAsLinkHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), nFlags);
1643 aFunc.setStartListening(rCxt.isStartListening());
1644 sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
1645 }
1646 else
1647 {
1648 // Compare the ScDocumentPool* to determine if we are copying
1649 // within the same document. If not, re-intern shared strings.
1650 svl::SharedStringPool* pSharedStringPool =
1651 (GetDoc().GetPool() != rColumn.GetDoc().GetPool()) ?
1652 &rColumn.GetDoc().GetSharedStringPool() : nullptr;
1653 CopyByCloneHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), nFlags,
1654 pSharedStringPool, bGlobalNamesToLocal);
1655 aFunc.setStartListening(rCxt.isStartListening());
1656 sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
1657 }
1658
1659 rColumn.CellStorageModified();
1660}
1661
1663 sc::CopyToDocContext& rCxt, SCROW nRow1, SCROW nRow2, InsertDeleteFlags nFlags, bool bMarked,
1664 ScColumn& rColumn ) const
1665{
1666 if (nRow1 > 0)
1667 CopyToColumn(rCxt, 0, nRow1-1, InsertDeleteFlags::FORMULA, false, rColumn);
1668
1669 CopyToColumn(rCxt, nRow1, nRow2, nFlags, bMarked, rColumn); //TODO: bMarked ????
1670
1671 if (nRow2 < GetDoc().MaxRow())
1672 CopyToColumn(rCxt, nRow2+1, GetDoc().MaxRow(), InsertDeleteFlags::FORMULA, false, rColumn);
1673}
1674
1675void ScColumn::CopyUpdated( const ScColumn* pPosCol, ScColumn& rDestCol ) const
1676{
1677 // Copy cells from this column to the destination column only for those
1678 // rows that are present in the position column (pPosCol).
1679
1680 // First, mark all the non-empty cell ranges from the position column.
1681 sc::SingleColumnSpanSet aRangeSet(GetDoc().GetSheetLimits());
1682 if(pPosCol)
1683 aRangeSet.scan(*pPosCol);
1684
1685 // Now, copy cells from this column to the destination column for those
1686 // marked row ranges.
1688 aRangeSet.getSpans(aRanges);
1689
1690 CopyToClipHandler aFunc(GetDoc(), *this, rDestCol, nullptr);
1691 sc::CellStoreType::const_iterator itPos = maCells.begin();
1692 for (const auto& rRange : aRanges)
1693 itPos = sc::ParseBlock(itPos, maCells, aFunc, rRange.mnRow1, rRange.mnRow2);
1694
1695 rDestCol.CellStorageModified();
1696}
1697
1699{
1700 // This is the scenario table, the data is copied into it
1701 ScDocument& rDocument = GetDoc();
1702 ScAttrIterator aAttrIter( pAttrArray.get(), 0, GetDoc().MaxRow(), rDocument.GetDefPattern() );
1703 SCROW nStart = -1, nEnd = -1;
1704 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1705 while (pPattern)
1706 {
1707 if ( pPattern->GetItem( ATTR_MERGE_FLAG ).IsScenario() )
1708 {
1709 DeleteArea( nStart, nEnd, InsertDeleteFlags::CONTENTS );
1710 sc::CopyToDocContext aCxt(rDocument);
1711 rSrcCol.
1712 CopyToColumn(aCxt, nStart, nEnd, InsertDeleteFlags::CONTENTS, false, *this);
1713
1714 // UpdateUsed not needed, already done in TestCopyScenario (obsolete comment ?)
1715
1716 sc::RefUpdateContext aRefCxt(rDocument);
1717 aRefCxt.meMode = URM_COPY;
1718 aRefCxt.maRange = ScRange(nCol, nStart, nTab, nCol, nEnd, nTab);
1719 aRefCxt.mnTabDelta = nTab - rSrcCol.nTab;
1720 UpdateReferenceOnCopy(aRefCxt);
1721 UpdateCompile();
1722 }
1723 pPattern = aAttrIter.Next( nStart, nEnd );
1724 }
1725}
1726
1727void ScColumn::CopyScenarioTo( ScColumn& rDestCol ) const
1728{
1729 // This is the scenario table, the data is copied to the other
1730 ScDocument& rDocument = GetDoc();
1731 ScAttrIterator aAttrIter( pAttrArray.get(), 0, GetDoc().MaxRow(), rDocument.GetDefPattern() );
1732 SCROW nStart = -1, nEnd = -1;
1733 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1734 while (pPattern)
1735 {
1736 if ( pPattern->GetItem( ATTR_MERGE_FLAG ).IsScenario() )
1737 {
1738 rDestCol.DeleteArea( nStart, nEnd, InsertDeleteFlags::CONTENTS );
1739 sc::CopyToDocContext aCxt(rDestCol.GetDoc());
1740 CopyToColumn(aCxt, nStart, nEnd, InsertDeleteFlags::CONTENTS, false, rDestCol);
1741
1742 sc::RefUpdateContext aRefCxt(rDocument);
1743 aRefCxt.meMode = URM_COPY;
1744 aRefCxt.maRange = ScRange(rDestCol.nCol, nStart, rDestCol.nTab, rDestCol.nCol, nEnd, rDestCol.nTab);
1745 aRefCxt.mnTabDelta = rDestCol.nTab - nTab;
1746 rDestCol.UpdateReferenceOnCopy(aRefCxt);
1747 rDestCol.UpdateCompile();
1748 }
1749 pPattern = aAttrIter.Next( nStart, nEnd );
1750 }
1751}
1752
1753bool ScColumn::TestCopyScenarioTo( const ScColumn& rDestCol ) const
1754{
1755 bool bOk = true;
1756 ScAttrIterator aAttrIter( pAttrArray.get(), 0, GetDoc().MaxRow(), GetDoc().GetDefPattern() );
1757 SCROW nStart = 0, nEnd = 0;
1758 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1759 while (pPattern && bOk)
1760 {
1761 if ( pPattern->GetItem( ATTR_MERGE_FLAG ).IsScenario() )
1762 if ( rDestCol.pAttrArray->HasAttrib( nStart, nEnd, HasAttrFlags::Protected ) )
1763 bOk = false;
1764
1765 pPattern = aAttrIter.Next( nStart, nEnd );
1766 }
1767 return bOk;
1768}
1769
1770void ScColumn::MarkScenarioIn( ScMarkData& rDestMark ) const
1771{
1772 ScRange aRange( nCol, 0, nTab );
1773
1774 ScAttrIterator aAttrIter( pAttrArray.get(), 0, GetDoc().MaxRow(), GetDoc().GetDefPattern() );
1775 SCROW nStart = -1, nEnd = -1;
1776 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1777 while (pPattern)
1778 {
1779 if ( pPattern->GetItem( ATTR_MERGE_FLAG ).IsScenario() )
1780 {
1781 aRange.aStart.SetRow( nStart );
1782 aRange.aEnd.SetRow( nEnd );
1783 rDestMark.SetMultiMarkArea( aRange );
1784 }
1785
1786 pPattern = aAttrIter.Next( nStart, nEnd );
1787 }
1788}
1789
1790namespace {
1791
1792void resetColumnPosition(sc::CellStoreType& rCells, SCCOL nCol)
1793{
1794 for (auto& rCellItem : rCells)
1795 {
1796 if (rCellItem.type != sc::element_type_formula)
1797 continue;
1798
1799 sc::formula_block::iterator itCell = sc::formula_block::begin(*rCellItem.data);
1800 sc::formula_block::iterator itCellEnd = sc::formula_block::end(*rCellItem.data);
1801 for (; itCell != itCellEnd; ++itCell)
1802 {
1803 ScFormulaCell& rCell = **itCell;
1804 rCell.aPos.SetCol(nCol);
1805 }
1806 }
1807}
1808
1809class NoteCaptionUpdater
1810{
1811 SCCOL mnCol;
1812 SCTAB mnTab;
1813public:
1814 NoteCaptionUpdater( SCCOL nCol, SCTAB nTab ) : mnCol(nCol), mnTab(nTab) {}
1815
1816 void operator() ( size_t nRow, ScPostIt* p )
1817 {
1818 p->UpdateCaptionPos(ScAddress(mnCol,nRow,mnTab));
1819 }
1820};
1821
1822}
1823
1825{
1826 NoteCaptionUpdater aFunc(nCol, nTab);
1827 sc::ProcessNote(maCellNotes.begin(), maCellNotes, nRow1, nRow2, aFunc);
1828}
1829
1830void ScColumn::UpdateDrawObjects(std::vector<std::vector<SdrObject*>>& pObjects, SCROW nRowStart, SCROW nRowEnd)
1831{
1832 assert(static_cast<int>(pObjects.size()) >= nRowEnd - nRowStart + 1);
1833
1834 int nObj = 0;
1835 for (SCROW nCurrentRow = nRowStart; nCurrentRow <= nRowEnd; nCurrentRow++, nObj++)
1836 {
1837 if (pObjects[nObj].empty())
1838 continue; // No draw objects in this row
1839
1840 UpdateDrawObjectsForRow(pObjects[nObj], nCol, nCurrentRow);
1841 }
1842}
1843
1844void ScColumn::UpdateDrawObjectsForRow( std::vector<SdrObject*>& pObjects, SCCOL nTargetCol, SCROW nTargetRow )
1845{
1846 for (auto &pObject : pObjects)
1847 {
1848 ScAddress aNewAddress(nTargetCol, nTargetRow, nTab);
1849
1850 // Update draw object according to new anchor
1851 ScDrawLayer* pDrawLayer = GetDoc().GetDrawLayer();
1852 if (pDrawLayer)
1853 pDrawLayer->MoveObject(pObject, aNewAddress);
1854 }
1855}
1856
1857bool ScColumn::IsDrawObjectsEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
1858{
1859 ScDrawLayer* pDrawLayer = GetDoc().GetDrawLayer();
1860 if (!pDrawLayer)
1861 return true;
1862
1863 ScRange aRange(nCol, nStartRow, nTab, nCol, nEndRow, nTab);
1864 return !pDrawLayer->HasObjectsAnchoredInRange(aRange);
1865}
1866
1868{
1869 maBroadcasters.swap(rCol.maBroadcasters);
1870 maCells.swap(rCol.maCells);
1872 maCellNotes.swap(rCol.maCellNotes);
1873 maSparklines.swap(rCol.maSparklines);
1874
1875 // Swap all CellStoreEvent mdds event_func related.
1876 maCells.event_handler().swap(rCol.maCells.event_handler());
1877 std::swap( mnBlkCountFormula, rCol.mnBlkCountFormula);
1878
1879 // notes update caption
1880 UpdateNoteCaptions(0, GetDoc().MaxRow());
1881 rCol.UpdateNoteCaptions(0, GetDoc().MaxRow());
1882
1883 std::swap(pAttrArray, rCol.pAttrArray);
1884
1885 // AttrArray needs to have the right column number
1886 pAttrArray->SetCol(nCol);
1887 rCol.pAttrArray->SetCol(rCol.nCol);
1888
1889 // Reset column positions in formula cells.
1890 resetColumnPosition(maCells, nCol);
1891 resetColumnPosition(rCol.maCells, rCol.nCol);
1892
1894 rCol.CellStorageModified();
1895}
1896
1897void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol)
1898{
1899 pAttrArray->MoveTo(nStartRow, nEndRow, *rCol.pAttrArray);
1900
1901 // Mark the non-empty cells within the specified range, for later broadcasting.
1902 sc::SingleColumnSpanSet aNonEmpties(GetDoc().GetSheetLimits());
1903 aNonEmpties.scan(*this, nStartRow, nEndRow);
1905 aNonEmpties.getSpans(aRanges);
1906
1907 // Split the formula grouping at the top and bottom boundaries.
1908 sc::CellStoreType::position_type aPos = maCells.position(nStartRow);
1910 if (GetDoc().ValidRow(nEndRow+1))
1911 {
1912 aPos = maCells.position(aPos.first, nEndRow+1);
1914 }
1915
1916 // Do the same with the destination column.
1917 aPos = rCol.maCells.position(nStartRow);
1919 if (GetDoc().ValidRow(nEndRow+1))
1920 {
1921 aPos = rCol.maCells.position(aPos.first, nEndRow+1);
1923 }
1924
1925 // Move the broadcasters to the destination column.
1926 maBroadcasters.transfer(nStartRow, nEndRow, rCol.maBroadcasters, nStartRow);
1927 maCells.transfer(nStartRow, nEndRow, rCol.maCells, nStartRow);
1928 maCellTextAttrs.transfer(nStartRow, nEndRow, rCol.maCellTextAttrs, nStartRow);
1929
1930 // move the notes to the destination column
1931 maCellNotes.transfer(nStartRow, nEndRow, rCol.maCellNotes, nStartRow);
1932 UpdateNoteCaptions(0, GetDoc().MaxRow());
1933
1934 // Re-group transferred formula cells.
1935 aPos = rCol.maCells.position(nStartRow);
1937 if (GetDoc().ValidRow(nEndRow+1))
1938 {
1939 aPos = rCol.maCells.position(aPos.first, nEndRow+1);
1941 }
1942
1944 rCol.CellStorageModified();
1945
1946 // Broadcast on moved ranges. Area-broadcast only.
1947 ScDocument& rDocument = GetDoc();
1948 ScHint aHint(SfxHintId::ScDataChanged, ScAddress(nCol, 0, nTab));
1949 for (const auto& rRange : aRanges)
1950 {
1951 for (SCROW nRow = rRange.mnRow1; nRow <= rRange.mnRow2; ++nRow)
1952 {
1953 aHint.SetAddressRow(nRow);
1954 rDocument.AreaBroadcast(aHint);
1955 }
1956 }
1957}
1958
1959namespace {
1960
1961class SharedTopFormulaCellPicker
1962{
1963public:
1964 SharedTopFormulaCellPicker() = default;
1965 SharedTopFormulaCellPicker(SharedTopFormulaCellPicker const &) = default;
1966 SharedTopFormulaCellPicker(SharedTopFormulaCellPicker &&) = default;
1967 SharedTopFormulaCellPicker & operator =(SharedTopFormulaCellPicker const &) = default;
1968 SharedTopFormulaCellPicker & operator =(SharedTopFormulaCellPicker &&) = default;
1969
1970 virtual ~SharedTopFormulaCellPicker() {}
1971
1972 void operator() ( sc::CellStoreType::value_type& node )
1973 {
1974 if (node.type != sc::element_type_formula)
1975 return;
1976
1977 size_t nTopRow = node.position;
1978
1979 sc::formula_block::iterator itBeg = sc::formula_block::begin(*node.data);
1980 sc::formula_block::iterator itEnd = sc::formula_block::end(*node.data);
1981
1982 // Only pick shared formula cells that are the top cells of their
1983 // respective shared ranges.
1984 for (sc::formula_block::iterator it = itBeg; it != itEnd; ++it)
1985 {
1986 ScFormulaCell* pCell = *it;
1987 size_t nRow = nTopRow + std::distance(itBeg, it);
1988 if (!pCell->IsShared())
1989 {
1990 processNonShared(pCell, nRow);
1991 continue;
1992 }
1993
1994 if (pCell->IsSharedTop())
1995 {
1996 ScFormulaCell** pp = &(*it);
1997 processSharedTop(pp, nRow, pCell->GetSharedLength());
1998
1999 // Move to the last cell in the group, to get incremented to
2000 // the next cell in the next iteration.
2001 size_t nOffsetToLast = pCell->GetSharedLength() - 1;
2002 std::advance(it, nOffsetToLast);
2003 }
2004 }
2005 }
2006
2007 virtual void processNonShared( ScFormulaCell* /*pCell*/, size_t /*nRow*/ ) {}
2008 virtual void processSharedTop( ScFormulaCell** /*ppCells*/, size_t /*nRow*/, size_t /*nLength*/ ) {}
2009};
2010
2011class UpdateRefOnCopy
2012{
2013 const sc::RefUpdateContext& mrCxt;
2014 ScDocument* mpUndoDoc;
2015 bool mbUpdated;
2016
2017public:
2018 UpdateRefOnCopy(const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc) :
2019 mrCxt(rCxt), mpUndoDoc(pUndoDoc), mbUpdated(false) {}
2020
2021 bool isUpdated() const { return mbUpdated; }
2022
2023 void operator() (sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
2024 {
2025 if (node.type != sc::element_type_formula)
2026 return;
2027
2028 sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
2029 std::advance(it, nOffset);
2030 sc::formula_block::iterator itEnd = it;
2031 std::advance(itEnd, nDataSize);
2032
2033 for (; it != itEnd; ++it)
2034 {
2035 ScFormulaCell& rCell = **it;
2036 mbUpdated |= rCell.UpdateReference(mrCxt, mpUndoDoc);
2037 }
2038 }
2039};
2040
2041class UpdateRefOnNonCopy
2042{
2043 SCCOL mnCol;
2044 SCROW mnTab;
2045 const sc::RefUpdateContext* mpCxt;
2046 ScDocument* mpUndoDoc;
2047 bool mbUpdated;
2048 bool mbClipboardSource;
2049
2050 void recompileTokenArray( ScFormulaCell& rTopCell )
2051 {
2052 // We need to re-compile the token array when a range name is
2053 // modified, to correctly reflect the new references in the
2054 // name.
2055 ScCompiler aComp(mpCxt->mrDoc, rTopCell.aPos, *rTopCell.GetCode(), mpCxt->mrDoc.GetGrammar(),
2056 true, rTopCell.GetMatrixFlag() != ScMatrixMode::NONE);
2057 aComp.CompileTokenArray();
2058 }
2059
2060 void updateRefOnShift( sc::FormulaGroupEntry& rGroup )
2061 {
2062 if (!rGroup.mbShared)
2063 {
2064 ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
2065 mbUpdated |= rGroup.mpCell->UpdateReferenceOnShift(*mpCxt, mpUndoDoc, &aUndoPos);
2066 return;
2067 }
2068
2069 // Update references of a formula group.
2070 ScFormulaCell** pp = rGroup.mpCells;
2071 ScFormulaCell** ppEnd = pp + rGroup.mnLength;
2072 ScFormulaCell* pTop = *pp;
2073 ScTokenArray* pCode = pTop->GetCode();
2074 ScTokenArray aOldCode(pCode->CloneValue());
2075 ScAddress aOldPos = pTop->aPos;
2076
2077 // Run this before the position gets updated.
2078 sc::RefUpdateResult aRes = pCode->AdjustReferenceOnShift(*mpCxt, aOldPos);
2079
2080 bool bGroupShifted = false;
2081 if (pTop->UpdatePosOnShift(*mpCxt))
2082 {
2084 // Update the positions of all formula cells.
2085 for (++pp; pp != ppEnd; ++pp) // skip the top cell.
2086 {
2087 ScFormulaCell* pFC = *pp;
2088 if (!pFC->aPos.Move(mpCxt->mnColDelta, mpCxt->mnRowDelta, mpCxt->mnTabDelta,
2089 aErrorPos, mpCxt->mrDoc))
2090 {
2091 assert(!"can't move formula cell");
2092 }
2093 }
2094
2095 if (pCode->IsRecalcModeOnRefMove())
2096 aRes.mbValueChanged = true;
2097
2098 // FormulaGroupAreaListener (contrary to ScBroadcastArea) is not
2099 // updated but needs to be re-setup, else at least its mpColumn
2100 // would indicate the old column to collect cells from. tdf#129396
2101 /* TODO: investigate if that could be short-cut to avoid all the
2102 * EndListeningTo() / StartListeningTo() overhead and is really
2103 * only necessary when shifting the column, not also when shifting
2104 * rows. */
2105 bGroupShifted = true;
2106 }
2107 else if (aRes.mbReferenceModified && pCode->IsRecalcModeOnRefMove())
2108 {
2109 // The cell itself hasn't shifted. But it may have ROW or COLUMN
2110 // referencing another cell that has.
2111 aRes.mbValueChanged = true;
2112 }
2113
2114 if (aRes.mbNameModified)
2115 recompileTokenArray(*pTop);
2116
2117 if (aRes.mbReferenceModified || aRes.mbNameModified || bGroupShifted)
2118 {
2119 sc::EndListeningContext aEndCxt(mpCxt->mrDoc, &aOldCode);
2120 aEndCxt.setPositionDelta(
2121 ScAddress(-mpCxt->mnColDelta, -mpCxt->mnRowDelta, -mpCxt->mnTabDelta));
2122
2123 for (pp = rGroup.mpCells; pp != ppEnd; ++pp)
2124 {
2125 ScFormulaCell* p = *pp;
2126 p->EndListeningTo(aEndCxt);
2127 p->SetNeedsListening(true);
2128 }
2129
2130 mbUpdated = true;
2131
2132 fillUndoDoc(aOldPos, rGroup.mnLength, aOldCode);
2133 }
2134
2135 if (aRes.mbValueChanged)
2136 {
2137 for (pp = rGroup.mpCells; pp != ppEnd; ++pp)
2138 {
2139 ScFormulaCell* p = *pp;
2140 p->SetNeedsDirty(true);
2141 }
2142 }
2143 }
2144
2145 void updateRefOnMove( sc::FormulaGroupEntry& rGroup )
2146 {
2147 if (!rGroup.mbShared)
2148 {
2149 ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
2150 mbUpdated |= rGroup.mpCell->UpdateReferenceOnMove(*mpCxt, mpUndoDoc, &aUndoPos);
2151 return;
2152 }
2153
2154 // Update references of a formula group.
2155 ScFormulaCell** pp = rGroup.mpCells;
2156 ScFormulaCell** ppEnd = pp + rGroup.mnLength;
2157 ScFormulaCell* pTop = *pp;
2158 ScTokenArray* pCode = pTop->GetCode();
2159 ScTokenArray aOldCode(pCode->CloneValue());
2160
2161 ScAddress aPos = pTop->aPos;
2162 ScAddress aOldPos = aPos;
2163
2164 bool bCellMoved;
2165 if (mpCxt->maRange.Contains(aPos))
2166 {
2167 bCellMoved = true;
2168
2169 // The cell is being moved or copied to a new position. The
2170 // position has already been updated prior to this call.
2171 // Determine its original position before the move which will be
2172 // used to adjust relative references later.
2173
2174 aOldPos.Set(
2175 aPos.Col() - mpCxt->mnColDelta,
2176 aPos.Row() - mpCxt->mnRowDelta,
2177 aPos.Tab() - mpCxt->mnTabDelta);
2178 }
2179 else
2180 {
2181 bCellMoved = false;
2182 }
2183
2184 bool bRecalcOnMove = pCode->IsRecalcModeOnRefMove();
2185 if (bRecalcOnMove)
2186 bRecalcOnMove = aPos != aOldPos;
2187
2188 sc::RefUpdateResult aRes = pCode->AdjustReferenceOnMove(*mpCxt, aOldPos, aPos);
2189
2190 if (!(aRes.mbReferenceModified || aRes.mbNameModified || bRecalcOnMove))
2191 return;
2192
2193 sc::AutoCalcSwitch aACSwitch(mpCxt->mrDoc, false);
2194
2195 if (aRes.mbNameModified)
2196 recompileTokenArray(*pTop);
2197
2198 // Perform end-listening, start-listening, and dirtying on all
2199 // formula cells in the group.
2200
2201 // Make sure that the start and end listening contexts share the
2202 // same block position set, else an invalid iterator may ensue.
2203 auto pPosSet = std::make_shared<sc::ColumnBlockPositionSet>(mpCxt->mrDoc);
2204
2205 sc::StartListeningContext aStartCxt(mpCxt->mrDoc, pPosSet);
2206 sc::EndListeningContext aEndCxt(mpCxt->mrDoc, pPosSet, &aOldCode);
2207
2208 aEndCxt.setPositionDelta(
2209 ScAddress(-mpCxt->mnColDelta, -mpCxt->mnRowDelta, -mpCxt->mnTabDelta));
2210
2211 for (; pp != ppEnd; ++pp)
2212 {
2213 ScFormulaCell* p = *pp;
2214 p->EndListeningTo(aEndCxt);
2215 p->StartListeningTo(aStartCxt);
2216 p->SetDirty();
2217 }
2218
2219 mbUpdated = true;
2220
2221 // Move from clipboard is Cut&Paste, then do not copy the original
2222 // positions' formula cells to the Undo document.
2223 if (!mbClipboardSource || !bCellMoved)
2224 fillUndoDoc(aOldPos, rGroup.mnLength, aOldCode);
2225 }
2226
2227 void fillUndoDoc( const ScAddress& rOldPos, SCROW nLength, const ScTokenArray& rOldCode )
2228 {
2229 if (!mpUndoDoc || nLength <= 0)
2230 return;
2231
2232 // Insert the old formula group into the undo document.
2233 ScAddress aUndoPos = rOldPos;
2234 ScFormulaCell* pFC = new ScFormulaCell(*mpUndoDoc, aUndoPos, rOldCode.Clone());
2235
2236 if (nLength == 1)
2237 {
2238 mpUndoDoc->SetFormulaCell(aUndoPos, pFC);
2239 return;
2240 }
2241
2242 std::vector<ScFormulaCell*> aCells;
2243 aCells.reserve(nLength);
2244 ScFormulaCellGroupRef xGroup = pFC->CreateCellGroup(nLength, false);
2245 aCells.push_back(pFC);
2246 aUndoPos.IncRow();
2247 for (SCROW i = 1; i < nLength; ++i, aUndoPos.IncRow())
2248 {
2249 pFC = new ScFormulaCell(*mpUndoDoc, aUndoPos, xGroup);
2250 aCells.push_back(pFC);
2251 }
2252
2253 if (!mpUndoDoc->SetFormulaCells(rOldPos, aCells))
2254 // Insertion failed. Delete all formula cells.
2255 std::for_each(aCells.begin(), aCells.end(), std::default_delete<ScFormulaCell>());
2256 }
2257
2258public:
2259 UpdateRefOnNonCopy(
2260 SCCOL nCol, SCTAB nTab, const sc::RefUpdateContext* pCxt,
2261 ScDocument* pUndoDoc) :
2262 mnCol(nCol), mnTab(nTab), mpCxt(pCxt),
2263 mpUndoDoc(pUndoDoc), mbUpdated(false),
2264 mbClipboardSource(pCxt->mrDoc.IsClipboardSource()){}
2265
2266 void operator() ( sc::FormulaGroupEntry& rGroup )
2267 {
2268 switch (mpCxt->meMode)
2269 {
2270 case URM_INSDEL:
2271 updateRefOnShift(rGroup);
2272 return;
2273 case URM_MOVE:
2274 updateRefOnMove(rGroup);
2275 return;
2276 default:
2277 ;
2278 }
2279
2280 if (rGroup.mbShared)
2281 {
2282 ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
2283 ScFormulaCell** pp = rGroup.mpCells;
2284 ScFormulaCell** ppEnd = pp + rGroup.mnLength;
2285 for (; pp != ppEnd; ++pp, aUndoPos.IncRow())
2286 {
2287 ScFormulaCell* p = *pp;
2288 mbUpdated |= p->UpdateReference(*mpCxt, mpUndoDoc, &aUndoPos);
2289 }
2290 }
2291 else
2292 {
2293 ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
2294 mbUpdated |= rGroup.mpCell->UpdateReference(*mpCxt, mpUndoDoc, &aUndoPos);
2295 }
2296 }
2297
2298 bool isUpdated() const { return mbUpdated; }
2299};
2300
2301class UpdateRefGroupBoundChecker : public SharedTopFormulaCellPicker
2302{
2303 const sc::RefUpdateContext& mrCxt;
2304 std::vector<SCROW>& mrBounds;
2305
2306public:
2307 UpdateRefGroupBoundChecker(const sc::RefUpdateContext& rCxt, std::vector<SCROW>& rBounds) :
2308 mrCxt(rCxt), mrBounds(rBounds) {}
2309
2310 virtual void processSharedTop( ScFormulaCell** ppCells, size_t /*nRow*/, size_t /*nLength*/ ) override
2311 {
2312 // Check its tokens and record its reference boundaries.
2313 ScFormulaCell& rCell = **ppCells;
2314 const ScTokenArray& rCode = *rCell.GetCode();
2316 mrCxt, rCell.aPos, rCell.GetSharedLength(), mrBounds);
2317 }
2318};
2319
2320class UpdateRefExpandGroupBoundChecker : public SharedTopFormulaCellPicker
2321{
2322 const sc::RefUpdateContext& mrCxt;
2323 std::vector<SCROW>& mrBounds;
2324
2325public:
2326 UpdateRefExpandGroupBoundChecker(const sc::RefUpdateContext& rCxt, std::vector<SCROW>& rBounds) :
2327 mrCxt(rCxt), mrBounds(rBounds) {}
2328
2329 virtual void processSharedTop( ScFormulaCell** ppCells, size_t /*nRow*/, size_t /*nLength*/ ) override
2330 {
2331 // Check its tokens and record its reference boundaries.
2332 ScFormulaCell& rCell = **ppCells;
2333 const ScTokenArray& rCode = *rCell.GetCode();
2335 mrCxt, rCell.aPos, rCell.GetSharedLength(), mrBounds);
2336 }
2337};
2338
2339class FormulaGroupPicker : public SharedTopFormulaCellPicker
2340{
2341 std::vector<sc::FormulaGroupEntry>& mrGroups;
2342
2343public:
2344 explicit FormulaGroupPicker( std::vector<sc::FormulaGroupEntry>& rGroups ) : mrGroups(rGroups) {}
2345
2346 virtual void processNonShared( ScFormulaCell* pCell, size_t nRow ) override
2347 {
2348 mrGroups.emplace_back(pCell, nRow);
2349 }
2350
2351 virtual void processSharedTop( ScFormulaCell** ppCells, size_t nRow, size_t nLength ) override
2352 {
2353 mrGroups.emplace_back(ppCells, nRow, nLength);
2354 }
2355};
2356
2357}
2358
2360{
2361 // When copying, the range equals the destination range where cells
2362 // are pasted, and the dx, dy, dz refer to the distance from the
2363 // source range.
2364
2365 UpdateRefOnCopy aHandler(rCxt, pUndoDoc);
2367 sc::CellStoreType::position_type aPos = blockPos
2368 ? maCells.position(blockPos->miCellPos, rCxt.maRange.aStart.Row())
2369 : maCells.position(rCxt.maRange.aStart.Row());
2370 sc::ProcessBlock(aPos.first, maCells, aHandler, rCxt.maRange.aStart.Row(), rCxt.maRange.aEnd.Row());
2371
2372 // The formula groups at the top and bottom boundaries are expected to
2373 // have been split prior to this call. Here, we only do the joining.
2375 if (rCxt.maRange.aEnd.Row() < GetDoc().MaxRow())
2376 {
2377 aPos = maCells.position(aPos.first, rCxt.maRange.aEnd.Row()+1);
2379 }
2380
2381 return aHandler.isUpdated();
2382}
2383
2385{
2386 if (IsEmptyData() || GetDoc().IsClipOrUndo())
2387 // Cells in this column are all empty, or clip or undo doc. No update needed.
2388 return false;
2389
2390 if (rCxt.meMode == URM_COPY)
2391 return UpdateReferenceOnCopy(rCxt, pUndoDoc);
2392
2393 std::vector<SCROW> aBounds;
2394
2395 bool bThisColShifted = (rCxt.maRange.aStart.Tab() <= nTab && nTab <= rCxt.maRange.aEnd.Tab() &&
2396 rCxt.maRange.aStart.Col() <= nCol && nCol <= rCxt.maRange.aEnd.Col());
2397 if (bThisColShifted)
2398 {
2399 // Cells in this column is being shifted. Split formula grouping at
2400 // the top and bottom boundaries before they get shifted.
2401 // Also, for deleted rows split at the top of the deleted area to adapt
2402 // the affected group length.
2403 SCROW nSplitPos;
2404 if (rCxt.mnRowDelta < 0)
2405 {
2406 nSplitPos = rCxt.maRange.aStart.Row() + rCxt.mnRowDelta;
2407 if (GetDoc().ValidRow(nSplitPos))
2408 aBounds.push_back(nSplitPos);
2409 }
2410 nSplitPos = rCxt.maRange.aStart.Row();
2411 if (GetDoc().ValidRow(nSplitPos))
2412 {
2413 aBounds.push_back(nSplitPos);
2414 nSplitPos = rCxt.maRange.aEnd.Row() + 1;
2415 if (GetDoc().ValidRow(nSplitPos))
2416 aBounds.push_back(nSplitPos);
2417 }
2418 }
2419
2420 // Check the row positions at which the group must be split per relative
2421 // references.
2422 UpdateRefGroupBoundChecker aBoundChecker(rCxt, aBounds);
2423 std::for_each(maCells.begin(), maCells.end(), aBoundChecker);
2424
2425 // If expand reference edges is on, splitting groups may happen anywhere
2426 // where a reference points to an adjacent row of the insertion.
2427 if (rCxt.mnRowDelta > 0 && rCxt.mrDoc.IsExpandRefs())
2428 {
2429 UpdateRefExpandGroupBoundChecker aExpandChecker(rCxt, aBounds);
2430 std::for_each(maCells.begin(), maCells.end(), aExpandChecker);
2431 }
2432
2433 // Do the actual splitting.
2434 const bool bSplit = sc::SharedFormulaUtil::splitFormulaCellGroups(GetDoc(), maCells, aBounds);
2435
2436 // Collect all formula groups.
2437 std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries();
2438
2439 // Process all collected formula groups.
2440 UpdateRefOnNonCopy aHandler(nCol, nTab, &rCxt, pUndoDoc);
2441 aHandler = std::for_each(aGroups.begin(), aGroups.end(), aHandler);
2442 if (bSplit || aHandler.isUpdated())
2443 rCxt.maRegroupCols.set(nTab, nCol);
2444
2445 return aHandler.isUpdated();
2446}
2447
2448std::vector<sc::FormulaGroupEntry> ScColumn::GetFormulaGroupEntries()
2449{
2450 std::vector<sc::FormulaGroupEntry> aGroups;
2451 std::for_each(maCells.begin(), maCells.end(), FormulaGroupPicker(aGroups));
2452 return aGroups;
2453}
2454
2455namespace {
2456
2457class UpdateTransHandler
2458{
2459 ScColumn& mrColumn;
2460 sc::CellStoreType::iterator miPos;
2461 ScRange maSource;
2462 ScAddress maDest;
2463 ScDocument* mpUndoDoc;
2464public:
2465 UpdateTransHandler(ScColumn& rColumn, const ScRange& rSource, const ScAddress& rDest, ScDocument* pUndoDoc) :
2466 mrColumn(rColumn),
2467 miPos(rColumn.GetCellStore().begin()),
2468 maSource(rSource), maDest(rDest), mpUndoDoc(pUndoDoc) {}
2469
2470 void operator() (size_t nRow, ScFormulaCell* pCell)
2471 {
2472 sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow);
2473 miPos = aPos.first;
2475 pCell->UpdateTranspose(maSource, maDest, mpUndoDoc);
2476 ScColumn::JoinNewFormulaCell(aPos, *pCell);
2477 }
2478};
2479
2480class UpdateGrowHandler
2481{
2482 ScColumn& mrColumn;
2483 sc::CellStoreType::iterator miPos;
2484 ScRange maArea;
2485 SCCOL mnGrowX;
2486 SCROW mnGrowY;
2487public:
2488 UpdateGrowHandler(ScColumn& rColumn, const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY) :
2489 mrColumn(rColumn),
2490 miPos(rColumn.GetCellStore().begin()),
2491 maArea(rArea), mnGrowX(nGrowX), mnGrowY(nGrowY) {}
2492
2493 void operator() (size_t nRow, ScFormulaCell* pCell)
2494 {
2495 sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow);
2496 miPos = aPos.first;
2498 pCell->UpdateGrow(maArea, mnGrowX, mnGrowY);
2499 ScColumn::JoinNewFormulaCell(aPos, *pCell);
2500 }
2501};
2502
2503class InsertTabUpdater
2504{
2506 sc::CellTextAttrStoreType& mrTextAttrs;
2507 sc::CellTextAttrStoreType::iterator miAttrPos;
2508 SCTAB mnTab;
2509 bool mbModified;
2510
2511public:
2512 InsertTabUpdater(sc::RefUpdateInsertTabContext& rCxt, sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab) :
2513 mrCxt(rCxt),
2514 mrTextAttrs(rTextAttrs),
2515 miAttrPos(rTextAttrs.begin()),
2516 mnTab(nTab),
2517 mbModified(false) {}
2518
2519 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2520 {
2521 pCell->UpdateInsertTab(mrCxt);
2522 mbModified = true;
2523 }
2524
2525 void operator() (size_t nRow, EditTextObject* pCell)
2526 {
2527 editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
2528 aUpdater.updateTableFields(mnTab);
2529 miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
2530 mbModified = true;
2531 }
2532
2533 bool isModified() const { return mbModified; }
2534};
2535
2536class DeleteTabUpdater
2537{
2539 sc::CellTextAttrStoreType& mrTextAttrs;
2540 sc::CellTextAttrStoreType::iterator miAttrPos;
2541 SCTAB mnTab;
2542 bool mbModified;
2543public:
2544 DeleteTabUpdater(sc::RefUpdateDeleteTabContext& rCxt, sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab) :
2545 mrCxt(rCxt),
2546 mrTextAttrs(rTextAttrs),
2547 miAttrPos(rTextAttrs.begin()),
2548 mnTab(nTab),
2549 mbModified(false) {}
2550
2551 void operator() (size_t, ScFormulaCell* pCell)
2552 {
2553 pCell->UpdateDeleteTab(mrCxt);
2554 mbModified = true;
2555 }
2556
2557 void operator() (size_t nRow, EditTextObject* pCell)
2558 {
2559 editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
2560 aUpdater.updateTableFields(mnTab);
2561 miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
2562 mbModified = true;
2563 }
2564
2565 bool isModified() const { return mbModified; }
2566};
2567
2568class InsertAbsTabUpdater
2569{
2570 sc::CellTextAttrStoreType& mrTextAttrs;
2571 sc::CellTextAttrStoreType::iterator miAttrPos;
2572 SCTAB mnTab;
2573 SCTAB mnNewPos;
2574 bool mbModified;
2575public:
2576 InsertAbsTabUpdater(sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab, SCTAB nNewPos) :
2577 mrTextAttrs(rTextAttrs),
2578 miAttrPos(rTextAttrs.begin()),
2579 mnTab(nTab),
2580 mnNewPos(nNewPos),
2581 mbModified(false) {}
2582
2583 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2584 {
2585 pCell->UpdateInsertTabAbs(mnNewPos);
2586 mbModified = true;
2587 }
2588
2589 void operator() (size_t nRow, EditTextObject* pCell)
2590 {
2591 editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
2592 aUpdater.updateTableFields(mnTab);
2593 miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
2594 mbModified = true;
2595 }
2596
2597 bool isModified() const { return mbModified; }
2598};
2599
2600class MoveTabUpdater
2601{
2603 sc::CellTextAttrStoreType& mrTextAttrs;
2604 sc::CellTextAttrStoreType::iterator miAttrPos;
2605 SCTAB mnTab;
2606 bool mbModified;
2607public:
2608 MoveTabUpdater(sc::RefUpdateMoveTabContext& rCxt, sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab) :
2609 mrCxt(rCxt),
2610 mrTextAttrs(rTextAttrs),
2611 miAttrPos(rTextAttrs.begin()),
2612 mnTab(nTab),
2613 mbModified(false) {}
2614
2615 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2616 {
2617 pCell->UpdateMoveTab(mrCxt, mnTab);
2618 mbModified = true;
2619 }
2620
2621 void operator() (size_t nRow, EditTextObject* pCell)
2622 {
2623 editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
2624 aUpdater.updateTableFields(mnTab);
2625 miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
2626 mbModified = true;
2627 }
2628
2629 bool isModified() const { return mbModified; }
2630};
2631
2632class UpdateCompileHandler
2633{
2634 bool mbForceIfNameInUse:1;
2635public:
2636 explicit UpdateCompileHandler(bool bForceIfNameInUse) :
2637 mbForceIfNameInUse(bForceIfNameInUse) {}
2638
2639 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2640 {
2641 pCell->UpdateCompile(mbForceIfNameInUse);
2642 }
2643};
2644
2645class TabNoSetter
2646{
2647 SCTAB mnTab;
2648public:
2649 explicit TabNoSetter(SCTAB nTab) : mnTab(nTab) {}
2650
2651 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2652 {
2653 pCell->aPos.SetTab(mnTab);
2654 }
2655};
2656
2657class UsedRangeNameFinder
2658{
2659 sc::UpdatedRangeNames& mrIndexes;
2660public:
2661 explicit UsedRangeNameFinder(sc::UpdatedRangeNames& rIndexes) : mrIndexes(rIndexes) {}
2662
2663 void operator() (size_t /*nRow*/, const ScFormulaCell* pCell)
2664 {
2665 pCell->FindRangeNamesInUse(mrIndexes);
2666 }
2667};
2668
2669class CheckVectorizationHandler
2670{
2671public:
2672 CheckVectorizationHandler()
2673 {}
2674
2675 void operator() (size_t /*nRow*/, ScFormulaCell* p)
2676 {
2677 ScTokenArray* pCode = p->GetCode();
2678 if (pCode && pCode->IsFormulaVectorDisabled())
2679 {
2680 pCode->ResetVectorState();
2681 FormulaTokenArrayPlainIterator aIter(*pCode);
2682 FormulaToken* pFT = aIter.First();
2683 while (pFT)
2684 {
2685 pCode->CheckToken(*pFT);
2686 pFT = aIter.Next();
2687 }
2688 }
2689 }
2690};
2691
2692struct SetDirtyVarHandler
2693{
2694 void operator() (size_t /*nRow*/, ScFormulaCell* p)
2695 {
2696 p->SetDirtyVar();
2697 }
2698};
2699
2700class SetDirtyHandler
2701{
2702 ScDocument& mrDoc;
2703 const sc::SetFormulaDirtyContext& mrCxt;
2704public:
2705 SetDirtyHandler( ScDocument& rDoc, const sc::SetFormulaDirtyContext& rCxt ) :
2706 mrDoc(rDoc), mrCxt(rCxt) {}
2707
2708 void operator() (size_t /*nRow*/, ScFormulaCell* p)
2709 {
2710 if (mrCxt.mbClearTabDeletedFlag)
2711 {
2712 if (!p->IsShared() || p->IsSharedTop())
2713 {
2714 ScTokenArray* pCode = p->GetCode();
2715 pCode->ClearTabDeleted(
2716 p->aPos, mrCxt.mnTabDeletedStart, mrCxt.mnTabDeletedEnd);
2717 }
2718 }
2719
2720 p->SetDirtyVar();
2721 if (!mrDoc.IsInFormulaTree(p))
2722 mrDoc.PutInFormulaTree(p);
2723 }
2724};
2725
2726class SetDirtyOnRangeHandler
2727{
2728 sc::SingleColumnSpanSet maValueRanges;
2729 ScColumn& mrColumn;
2730public:
2731 explicit SetDirtyOnRangeHandler(ScColumn& rColumn)
2732 : maValueRanges(rColumn.GetDoc().GetSheetLimits()),
2733 mrColumn(rColumn) {}
2734
2735 void operator() (size_t /*nRow*/, ScFormulaCell* p)
2736 {
2737 p->SetDirty();
2738 }
2739
2740 void operator() (mdds::mtv::element_t type, size_t nTopRow, size_t nDataSize)
2741 {
2742 if (type == sc::element_type_empty)
2743 // Ignore empty blocks.
2744 return;
2745
2746 // Non-formula cells.
2747 SCROW nRow1 = nTopRow;
2748 SCROW nRow2 = nTopRow + nDataSize - 1;
2749 maValueRanges.set(nRow1, nRow2, true);
2750 }
2751
2752 void broadcast()
2753 {
2754 std::vector<SCROW> aRows;
2755 maValueRanges.getRows(aRows);
2756 mrColumn.BroadcastCells(aRows, SfxHintId::ScDataChanged);
2757 }
2758
2759 void fillBroadcastSpans( sc::ColumnSpanSet& rBroadcastSpans ) const
2760 {
2761 SCCOL nCol = mrColumn.GetCol();
2762 SCTAB nTab = mrColumn.GetTab();
2764 maValueRanges.getSpans(aSpans);
2765
2766 for (const auto& rSpan : aSpans)
2767 rBroadcastSpans.set(mrColumn.GetDoc(), nTab, nCol, rSpan.mnRow1, rSpan.mnRow2, true);
2768 }
2769};
2770
2771class SetTableOpDirtyOnRangeHandler
2772{
2773 sc::SingleColumnSpanSet maValueRanges;
2774 ScColumn& mrColumn;
2775public:
2776 explicit SetTableOpDirtyOnRangeHandler(ScColumn& rColumn)
2777 : maValueRanges(rColumn.GetDoc().GetSheetLimits()),
2778 mrColumn(rColumn) {}
2779
2780 void operator() (size_t /*nRow*/, ScFormulaCell* p)
2781 {
2782 p->SetTableOpDirty();
2783 }
2784
2785 void operator() (mdds::mtv::element_t type, size_t nTopRow, size_t nDataSize)
2786 {
2787 if (type == sc::element_type_empty)
2788 // Ignore empty blocks.
2789 return;
2790
2791 // Non-formula cells.
2792 SCROW nRow1 = nTopRow;
2793 SCROW nRow2 = nTopRow + nDataSize - 1;
2794 maValueRanges.set(nRow1, nRow2, true);
2795 }
2796
2797 void broadcast()
2798 {
2799 std::vector<SCROW> aRows;
2800 maValueRanges.getRows(aRows);
2801 mrColumn.BroadcastCells(aRows, SfxHintId::ScTableOpDirty);
2802 }
2803};
2804
2805struct SetDirtyAfterLoadHandler
2806{
2807 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2808 {
2809#if 1
2810 // Simply set dirty and append to FormulaTree, without broadcasting,
2811 // which is a magnitude faster. This is used to calculate the entire
2812 // document, e.g. when loading alien file formats.
2813 pCell->SetDirtyAfterLoad();
2814#else
2815/* This was used with the binary file format that stored results, where only
2816 * newly compiled and volatile functions and their dependents had to be
2817 * recalculated, which was faster then. Since that was moved to 'binfilter' to
2818 * convert to an XML file this isn't needed anymore, and not used for other
2819 * file formats. Kept for reference in case mechanism needs to be reactivated
2820 * for some file formats, we'd have to introduce a controlling parameter to
2821 * this method here then.
2822*/
2823
2824 // If the cell was already dirty because of CalcAfterLoad,
2825 // FormulaTracking has to take place.
2826 if (pCell->GetDirty())
2827 pCell->SetDirty();
2828#endif
2829 }
2830};
2831
2832struct SetDirtyIfPostponedHandler
2833{
2834 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2835 {
2837 pCell->SetDirty();
2838 }
2839};
2840
2841struct CalcAllHandler
2842{
2843#define DEBUG_SC_CHECK_FORMULATREE_CALCULATION 0
2844 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2845 {
2846#if DEBUG_SC_CHECK_FORMULATREE_CALCULATION
2847 // after F9 ctrl-F9: check the calculation for each FormulaTree
2848 double nOldVal, nNewVal;
2849 nOldVal = pCell->GetValue();
2850#endif
2851 pCell->Interpret();
2852#if DEBUG_SC_CHECK_FORMULATREE_CALCULATION
2853 if (pCell->GetCode()->IsRecalcModeNormal())
2854 nNewVal = pCell->GetValue();
2855 else
2856 nNewVal = nOldVal; // random(), jetzt() etc.
2857
2858 assert(nOldVal == nNewVal);
2859#endif
2860 }
2861#undef DEBUG_SC_CHECK_FORMULATREE_CALCULATION
2862};
2863
2864class CompileAllHandler
2865{
2867public:
2868 explicit CompileAllHandler( sc::CompileFormulaContext& rCxt ) : mrCxt(rCxt) {}
2869
2870 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2871 {
2872 // for unconditional compilation
2873 // bCompile=true and pCode->nError=0
2874 pCell->GetCode()->SetCodeError(FormulaError::NONE);
2875 pCell->SetCompile(true);
2876 pCell->CompileTokenArray(mrCxt);
2877 }
2878};
2879
2880class CompileXMLHandler
2881{
2883 ScProgress& mrProgress;
2884 const ScColumn& mrCol;
2885public:
2886 CompileXMLHandler( sc::CompileFormulaContext& rCxt, ScProgress& rProgress, const ScColumn& rCol) :
2887 mrCxt(rCxt),
2888 mrProgress(rProgress),
2889 mrCol(rCol) {}
2890
2891 void operator() (size_t nRow, ScFormulaCell* pCell)
2892 {
2893 sal_uInt32 nFormat = mrCol.GetNumberFormat(mrCol.GetDoc().GetNonThreadedContext(), nRow);
2894 if( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
2895 // Non-default number format is set.
2896 pCell->SetNeedNumberFormat(false);
2897 else if (pCell->NeedsNumberFormat())
2898 pCell->SetDirtyVar();
2899
2900 if (pCell->GetMatrixFlag() != ScMatrixMode::NONE)
2901 pCell->SetDirtyVar();
2902
2903 pCell->CompileXML(mrCxt, mrProgress);
2904 }
2905};
2906
2907class CompileErrorCellsHandler
2908{
2910 ScColumn& mrColumn;
2911 sc::CellStoreType::iterator miPos;
2912 FormulaError mnErrCode;
2913 bool mbCompiled;
2914public:
2915 CompileErrorCellsHandler( sc::CompileFormulaContext& rCxt, ScColumn& rColumn, FormulaError nErrCode ) :
2916 mrCxt(rCxt),
2917 mrColumn(rColumn),
2918 miPos(mrColumn.GetCellStore().begin()),
2919 mnErrCode(nErrCode),
2920 mbCompiled(false)
2921 {
2922 }
2923
2924 void operator() (size_t nRow, ScFormulaCell* pCell)
2925 {
2926 FormulaError nCurError = pCell->GetRawError();
2927 if (nCurError == FormulaError::NONE)
2928 // It's not an error cell. Skip it.
2929 return;
2930
2931 if (mnErrCode != FormulaError::NONE && nCurError != mnErrCode)
2932 // Error code is specified, and it doesn't match. Skip it.
2933 return;
2934
2935 sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow);
2936 miPos = aPos.first;
2938 pCell->GetCode()->SetCodeError(FormulaError::NONE);
2939 OUString aFormula = pCell->GetFormula(mrCxt);
2940 pCell->Compile(mrCxt, aFormula);
2941 ScColumn::JoinNewFormulaCell(aPos, *pCell);
2942
2943 mbCompiled = true;
2944 }
2945
2946 bool isCompiled() const { return mbCompiled; }
2947};
2948
2949class CalcAfterLoadHandler
2950{
2952 bool mbStartListening;
2953
2954public:
2955 CalcAfterLoadHandler( sc::CompileFormulaContext& rCxt, bool bStartListening ) :
2956 mrCxt(rCxt), mbStartListening(bStartListening) {}
2957
2958 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2959 {
2960 pCell->CalcAfterLoad(mrCxt, mbStartListening);
2961 }
2962};
2963
2964struct ResetChangedHandler
2965{
2966 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
2967 {
2968 pCell->SetChanged(false);
2969 }
2970};
2971
2975class FindEditCellsHandler
2976{
2977 ScColumn& mrColumn;
2978 sc::CellTextAttrStoreType::iterator miAttrPos;
2979 sc::CellStoreType::iterator miCellPos;
2980
2981public:
2982 explicit FindEditCellsHandler(ScColumn& rCol) :
2983 mrColumn(rCol),
2984 miAttrPos(rCol.GetCellAttrStore().begin()),
2985 miCellPos(rCol.GetCellStore().begin()) {}
2986
2987 bool operator() (size_t, const EditTextObject*)
2988 {
2989 // This is definitely an edit text cell.
2990 return true;
2991 }
2992
2993 bool operator() (size_t nRow, const ScFormulaCell* p)
2994 {
2995 // With a formula cell, it's considered an edit text cell when either
2996 // the result is multi-line or it has more than one script types.
2997 SvtScriptType nScriptType = mrColumn.GetRangeScriptType(miAttrPos, nRow, nRow, miCellPos);
2998 if (IsAmbiguousScriptNonZero(nScriptType))
2999 return true;
3000
3001 return const_cast<ScFormulaCell*>(p)->IsMultilineResult();
3002 }
3003
3007 std::pair<size_t,bool> operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
3008 {
3009 typedef std::pair<size_t,bool> RetType;
3010
3011 if (node.type == sc::element_type_empty)
3012 // Ignore empty blocks.
3013 return RetType(0, false);
3014
3015 // Check the script type of a non-empty element and see if it has
3016 // multiple script types.
3017 for (size_t i = 0; i < nDataSize; ++i)
3018 {
3019 SCROW nRow = node.position + i + nOffset;
3020 SvtScriptType nScriptType = mrColumn.GetRangeScriptType(miAttrPos, nRow, nRow, miCellPos);
3021 if (IsAmbiguousScriptNonZero(nScriptType))
3022 // Return the offset from the first row.
3023 return RetType(i+nOffset, true);
3024 }
3025
3026 // No edit text cell found.
3027 return RetType(0, false);
3028 }
3029};
3030
3031}
3032
3033void ScColumn::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
3034 ScDocument* pUndoDoc )
3035{
3036 UpdateTransHandler aFunc(*this, rSource, rDest, pUndoDoc);
3038}
3039
3040void ScColumn::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
3041{
3042 UpdateGrowHandler aFunc(*this, rArea, nGrowX, nGrowY);
3044}
3045
3047{
3048 if (nTab >= rCxt.mnInsertPos)
3049 {
3050 nTab += rCxt.mnSheets;
3051 pAttrArray->SetTab(nTab);
3052 }
3053
3055}
3056
3058{
3059 InsertTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
3061 if (aFunc.isModified())
3063}
3064
3066{
3067 if (nTab > rCxt.mnDeletePos)
3068 {
3069 nTab -= rCxt.mnSheets;
3070 pAttrArray->SetTab(nTab);
3071 }
3072
3073 DeleteTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
3075 if (aFunc.isModified())
3077}
3078
3080{
3081 InsertAbsTabUpdater aFunc(maCellTextAttrs, nTab, nNewPos);
3083 if (aFunc.isModified())
3085}
3086
3088{
3089 nTab = nTabNo;
3090 pAttrArray->SetTab( nTabNo );
3091
3092 MoveTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
3094 if (aFunc.isModified())
3096}
3097
3098void ScColumn::UpdateCompile( bool bForceIfNameInUse )
3099{
3100 UpdateCompileHandler aFunc(bForceIfNameInUse);
3102}
3103
3105{
3106 nTab = nNewTab;
3107 pAttrArray->SetTab( nNewTab );
3108
3109 TabNoSetter aFunc(nTab);
3111}
3112
3114{
3115 UsedRangeNameFinder aFunc(rIndexes);
3116 sc::ParseFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
3117}
3118
3120{
3121 SetDirtyVarHandler aFunc;
3123}
3124
3126{
3127 if (!GetDoc().ValidRow(nRow))
3128 return false;
3129
3130 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3131 sc::CellStoreType::const_iterator it = aPos.first;
3132 if (it->type != sc::element_type_formula)
3133 // This is not a formula cell block.
3134 return false;
3135
3136 const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
3137 return p->GetDirty();
3138}
3139
3141{
3142 sc::AutoCalcSwitch aSwitch(GetDoc(), false);
3143 CheckVectorizationHandler aFunc;
3145}
3146
3148{
3149 // is only done documentwide, no FormulaTracking
3150 sc::AutoCalcSwitch aSwitch(GetDoc(), false);
3151 SetDirtyHandler aFunc(GetDoc(), rCxt);
3153}
3154
3155void ScColumn::SetDirtyFromClip( SCROW nRow1, SCROW nRow2, sc::ColumnSpanSet& rBroadcastSpans )
3156{
3157 // Set all formula cells in the range dirty, and pick up all non-formula
3158 // cells for later broadcasting. We don't broadcast here.
3159 sc::AutoCalcSwitch aSwitch(GetDoc(), false);
3160
3161 SetDirtyOnRangeHandler aHdl(*this);
3162 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
3163 aHdl.fillBroadcastSpans(rBroadcastSpans);
3164}
3165
3166namespace {
3167
3168class BroadcastBroadcastersHandler
3169{
3170 ScHint maHint;
3171 bool mbBroadcasted;
3172
3173public:
3174 explicit BroadcastBroadcastersHandler( SfxHintId nHint, SCTAB nTab, SCCOL nCol )
3175 : maHint(nHint, ScAddress(nCol, 0, nTab))
3176 , mbBroadcasted(false)
3177 {
3178 }
3179
3180 void operator() ( size_t nRow, SvtBroadcaster* pBroadcaster )
3181 {
3182 maHint.SetAddressRow(nRow);
3183 pBroadcaster->Broadcast(maHint);
3184 mbBroadcasted = true;
3185 }
3186
3187 bool wasBroadcasted() { return mbBroadcasted; }
3188};
3189
3190}
3191
3193{
3194 BroadcastBroadcastersHandler aBroadcasterHdl(nHint, nTab, nCol);
3195 sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aBroadcasterHdl);
3196 return aBroadcasterHdl.wasBroadcasted();
3197}
3198
3199void ScColumn::SetDirty( SCROW nRow1, SCROW nRow2, BroadcastMode eMode )
3200{
3201 // broadcasts everything within the range, with FormulaTracking
3202 sc::AutoCalcSwitch aSwitch(GetDoc(), false);
3203
3204 switch (eMode)
3205 {
3206 case BROADCAST_NONE:
3207 {
3208 // Handler only used with formula cells.
3209 SetDirtyOnRangeHandler aHdl(*this);
3210 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl);
3211 }
3212 break;
3214 {
3215 // Handler used with both, formula and non-formula cells.
3216 SetDirtyOnRangeHandler aHdl(*this);
3217 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
3218 aHdl.broadcast();
3219 }
3220 break;
3222 {
3223 // Handler only used with formula cells.
3224 SetDirtyOnRangeHandler aHdl(*this);
3225 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl);
3226 // Broadcast all broadcasters in range.
3227 if (BroadcastBroadcasters( nRow1, nRow2, SfxHintId::ScDataChanged))
3228 {
3229 // SetDirtyOnRangeHandler implicitly tracks notified
3230 // formulas via ScDocument::Broadcast(), which
3231 // BroadcastBroadcastersHandler doesn't, so explicitly
3232 // track them here.
3234 }
3235 }
3236 break;
3237 }
3238}
3239
3241{
3242 sc::AutoCalcSwitch aSwitch(GetDoc(), false);
3243
3244 SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
3245 SetTableOpDirtyOnRangeHandler aHdl(*this);
3246 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
3247 aHdl.broadcast();
3248}
3249
3251{
3252 sc::AutoCalcSwitch aSwitch(GetDoc(), false);
3253 SetDirtyAfterLoadHandler aFunc;
3255}
3256
3257namespace {
3258
3259class RecalcOnRefMoveCollector
3260{
3261 std::vector<SCROW> maDirtyRows;
3262public:
3263 void operator() (size_t nRow, ScFormulaCell* pCell)
3264 {
3265 if (pCell->GetDirty() && pCell->GetCode()->IsRecalcModeOnRefMove())
3266 maDirtyRows.push_back(nRow);
3267 }
3268
3269 const std::vector<SCROW>& getDirtyRows() const
3270 {
3271 return maDirtyRows;
3272 }
3273};
3274
3275}
3276
3278{
3279 sc::AutoCalcSwitch aSwitch(GetDoc(), false);
3280 SetDirtyIfPostponedHandler aFunc;
3281 ScBulkBroadcast aBulkBroadcast( GetDoc().GetBASM(), SfxHintId::ScDataChanged);
3283}
3284
3286{
3287 sc::AutoCalcSwitch aSwitch(GetDoc(), false);
3288 RecalcOnRefMoveCollector aFunc;
3290 BroadcastCells(aFunc.getDirtyRows(), SfxHintId::ScDataChanged);
3291}
3292
3294{
3295 CalcAllHandler aFunc;
3297}
3298
3300{
3301 CompileAllHandler aFunc(rCxt);
3303}
3304
3306{
3307 CompileXMLHandler aFunc(rCxt, rProgress, *this);
3310}
3311
3313{
3314 CompileErrorCellsHandler aHdl(rCxt, *this, nErrCode);
3316 return aHdl.isCompiled();
3317}
3318
3319void ScColumn::CalcAfterLoad( sc::CompileFormulaContext& rCxt, bool bStartListening )
3320{
3321 CalcAfterLoadHandler aFunc(rCxt, bStartListening);
3323}
3324
3325void ScColumn::ResetChanged( SCROW nStartRow, SCROW nEndRow )
3326{
3327 ResetChangedHandler aFunc;
3328 sc::ProcessFormula(maCells.begin(), maCells, nStartRow, nEndRow, aFunc);
3329}
3330
3331bool ScColumn::HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst)
3332{
3333 // used in GetOptimalHeight - ambiguous script type counts as edit cell
3334
3335 FindEditCellsHandler aFunc(*this);
3336 std::pair<sc::CellStoreType::const_iterator,size_t> aPos =
3337 sc::FindFormulaEditText(maCells, nStartRow, nEndRow, aFunc);
3338
3339 if (aPos.first == maCells.end())
3340 return false;
3341
3342 rFirst = aPos.first->position + aPos.second;
3343 return true;
3344}
3345
3347 SCROW nRow, const ScStyleSheet* pSearchStyle, bool bUp, bool bInSelection,
3348 const ScMarkData& rMark) const
3349{
3350 if (bInSelection)
3351 {
3352 if (rMark.IsMultiMarked())
3353 {
3354 ScMarkArray aArray(rMark.GetMarkArray(nCol));
3355 return pAttrArray->SearchStyle(nRow, pSearchStyle, bUp, &aArray);
3356 }
3357 else
3358 return -1;
3359 }
3360 else
3361 return pAttrArray->SearchStyle( nRow, pSearchStyle, bUp );
3362}
3363
3365 SCROW& rRow, SCROW& rEndRow, const ScStyleSheet* pSearchStyle, bool bUp,
3366 bool bInSelection, const ScMarkData& rMark) const
3367{
3368 if (bInSelection)
3369 {
3370 if (rMark.IsMultiMarked())
3371 {
3372 ScMarkArray aArray(rMark.GetMarkArray(nCol));
3373 return pAttrArray->SearchStyleRange(
3374 rRow, rEndRow, pSearchStyle, bUp, &aArray);
3375 }
3376 else
3377 return false;
3378 }
3379 else
3380 return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp );
3381}
3382
3383/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
bool ValidRow(SCROW nRow, SCROW nMaxRow)
Definition: address.hxx:105
@ Scenario
field button for datapilot
@ All
dp table output
std::unique_ptr< EditTextObject > CreateTextObject()
void SetText(const OUString &rStr)
virtual editeng::FieldUpdater GetFieldUpdater()=0
@ UNINITIALIZED
Definition: address.hxx:220
SCTAB Tab() const
Definition: address.hxx:283
void Set(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: address.hxx:403
void SetCol(SCCOL nColP)
Definition: address.hxx:291
SC_DLLPUBLIC bool Move(SCCOL nDeltaX, SCROW nDeltaY, SCTAB nDeltaZ, ScAddress &rErrorPos, const ScDocument &rDoc)
Definition: address.cxx:2282
SCROW Row() const
Definition: address.hxx:274
void SetRow(SCROW nRowP)
Definition: address.hxx:287
void SetTab(SCTAB nTabP)
Definition: address.hxx:295
void IncRow(SCROW nDelta=1)
Definition: address.hxx:312
@ INITIALIZE_INVALID
Definition: address.hxx:221
SCCOL Col() const
Definition: address.hxx:279
const ScPatternAttr * Next(SCROW &rTop, SCROW &rBottom)
Definition: attarray.hxx:268
std::unique_ptr< ScAttrArray > pAttrArray
Definition: column.hxx:118
SCROW ApplySelectionCache(SfxItemPoolCache *pCache, const ScMarkData &rMark, ScEditDataArray *pDataArray, bool *const pIsChanged, SCCOL nCol)
Definition: column.cxx:383
void ClearSelectionItems(const sal_uInt16 *pWhich, const ScMarkData &rMark, SCCOL nCol)
Definition: column.cxx:426
void InitAttrArray(ScAttrArray *attrArray)
Definition: column.hxx:125
void ApplyPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr &rPatAttr, ScEditDataArray *pDataArray=nullptr, bool *const pIsChanged=nullptr)
Definition: column.cxx:482
const ScPatternAttr * GetMostUsedPattern(SCROW nStartRow, SCROW nEndRow) const
Definition: column.cxx:337
void ChangeSelectionIndent(bool bIncrement, const ScMarkData &rMark, SCCOL nCol)
Definition: column.cxx:408
ScDocument & GetDoc() const
Definition: column.hxx:127
sal_uInt32 GetNumberFormat(const ScInterpreterContext &rContext, SCROW nRow) const
Definition: column.hxx:967
void SetDirtyVar()
Definition: column.cxx:3119
void UpdateNoteCaptions(SCROW nRow1, SCROW nRow2)
Definition: column.cxx:1824
SCTAB GetTab() const
Definition: column.hxx:254
void CellStorageModified()
Called whenever the state of cell array gets modified i.e.
Definition: column2.cxx:1648
void CopyCellTextAttrsToDocument(SCROW nRow1, SCROW nRow2, ScColumn &rDestCol) const
Definition: column2.cxx:1821
~ScColumn() COVERITY_NOEXCEPT_FALSE
Definition: column.cxx:96
void ApplyPattern(SCROW nRow, const ScPatternAttr &rPatAttr)
Definition: column.cxx:467
SCCOL nCol
Definition: column.hxx:203
bool IsEmptyAttr() const
Definition: column.hxx:860
sc::CellTextAttrStoreType maCellTextAttrs
Definition: column.hxx:187
bool TestInsertCol(SCROW nStartRow, SCROW nEndRow) const
Definition: column.cxx:713
bool TestInsertRow(SCROW nStartRow, SCSIZE nSize) const
Definition: column.cxx:735
void DuplicateNotes(SCROW nStartRow, size_t nDataSize, ScColumn &rDestCol, sc::ColumnBlockPosition &rDestBlockPos, bool bCloneCaption, SCROW nRowOffsetDest=0) const
Definition: column2.cxx:1940
SCTAB nTab
Definition: column.hxx:204
void SetDirty(SCROW nRow1, SCROW nRow2, BroadcastMode)
Definition: column.cxx:3199
void CheckVectorizationState()
Definition: column.cxx:3140
void RegroupFormulaCells(std::vector< ScAddress > *pGroupPos=nullptr)
Regroup formula cells for the entire column.
Definition: column3.cxx:3674
ScFormulaCell * SetFormulaCell(SCROW nRow, ScFormulaCell *pCell, sc::StartListeningType eListenType=sc::SingleCellListening, bool bInheritNumFormatIfNeeded=true)
Takes ownership of pCell.
Definition: column3.cxx:2420
void UpdateDrawObjectsForRow(std::vector< SdrObject * > &pObjects, SCCOL nTargetCol, SCROW nTargetRow)
Definition: column.cxx:1844
void UpdateInsertTabOnlyCells(sc::RefUpdateInsertTabContext &rCxt)
Definition: column.cxx:3057
void DeleteSelection(InsertDeleteFlags nDelFlag, const ScMarkData &rMark, bool bBroadcast)
Definition: column.cxx:454
bool TestCopyScenarioTo(const ScColumn &rDestCol) const
Definition: column.cxx:1753
void SetAllFormulasDirty(const sc::SetFormulaDirtyContext &rCxt)
Definition: column.cxx:3147
void BroadcastCells(const std::vector< SCROW > &rRows, SfxHintId nHint)
Definition: column3.cxx:80
void UpdateDrawObjects(std::vector< std::vector< SdrObject * > > &pObjects, SCROW nRowStart, SCROW nRowEnd)
Definition: column.cxx:1830
void CopyToColumn(sc::CopyToDocContext &rCxt, SCROW nRow1, SCROW nRow2, InsertDeleteFlags nFlags, bool bMarked, ScColumn &rColumn, const ScMarkData *pMarkData=nullptr, bool bAsLink=false, bool bGlobalNamesToLocal=false) const
Definition: column.cxx:1592
void BroadcastRecalcOnRefMove()
Definition: column.cxx:3285
void InitBlockPosition(sc::ColumnBlockPosition &rBlockPos)
Definition: column3.cxx:1122
void UpdateDeleteTab(sc::RefUpdateDeleteTabContext &rCxt)
Definition: column.cxx:3065
std::vector< sc::FormulaGroupEntry > GetFormulaGroupEntries()
Get all non-grouped formula cells and formula cell groups in the whole column.
Definition: column.cxx:2448
void UpdateInsertTabAbs(SCTAB nNewPos)
Definition: column.cxx:3079
SCROW ApplySelectionCache(SfxItemPoolCache *pCache, const ScMarkData &rMark, ScEditDataArray *pDataArray, bool *const pIsChanged)
Definition: column.cxx:377
void Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument &rDoc, bool bEmptyAttrArray)
Definition: column.cxx:101
SvtScriptType GetRangeScriptType(sc::CellTextAttrStoreType::iterator &itPos, SCROW nRow1, SCROW nRow2, const sc::CellStoreType::iterator &itr)
Get combined script types of the specified range.
Definition: column2.cxx:2289
BroadcastMode
Broadcast mode for SetDirty(SCROW,SCROW,BroadcastMode).
Definition: column.hxx:242
@ BROADCAST_DATA_POSITIONS
broadcast existing cells with position => does AreaBroadcast
Definition: column.hxx:244
@ BROADCAST_BROADCASTERS
broadcast only existing cell broadcasters => no AreaBroadcast of range!
Definition: column.hxx:245
@ BROADCAST_NONE
no broadcasting
Definition: column.hxx:243
void DuplicateSparklines(SCROW nStartRow, size_t nDataSize, ScColumn &rDestCol, sc::ColumnBlockPosition &rDestBlockPos, SCROW nRowOffsetDest=0) const
Definition: column2.cxx:2122
sc::CellNoteStoreType maCellNotes
Definition: column.hxx:190
const ScStyleSheet * GetSelectionStyle(const ScMarkData &rMark, bool &rFound) const
Definition: column.cxx:554
void EndListeningFormulaCells(sc::EndListeningContext &rCxt, SCROW nRow1, SCROW nRow2, SCROW *pStartRow, SCROW *pEndRow)
Definition: column4.cxx:1604
bool UpdateReferenceOnCopy(sc::RefUpdateContext &rCxt, ScDocument *pUndoDoc=nullptr)
Definition: column.cxx:2359
bool CompileErrorCells(sc::CompileFormulaContext &rCxt, FormulaError nErrCode)
Definition: column.cxx:3312
void CompileXML(sc::CompileFormulaContext &rCxt, ScProgress &rProgress)
Definition: column.cxx:3305
void FreeAll()
Definition: column3.cxx:237
sc::MatrixEdge GetBlockMatrixEdges(SCROW nRow1, SCROW nRow2, sc::MatrixEdge nMask, bool bNoMatrixAtAll) const
Definition: column.cxx:111
SCCOL GetCol() const
Definition: column.hxx:255
void CalcAfterLoad(sc::CompileFormulaContext &rCxt, bool bStartListening)
Definition: column.cxx:3319
void SetNumberFormat(SCROW nRow, sal_uInt32 nNumberFormat)
Definition: column2.cxx:3257
void SetTableOpDirty(const ScRange &)
Definition: column.cxx:3240
void CopyScenarioTo(ScColumn &rDestCol) const
Definition: column.cxx:1727
void ApplyAttr(SCROW nRow, const SfxPoolItem &rAttr)
Definition: column.cxx:620
void ResetChanged(SCROW nStartRow, SCROW nEndRow)
Definition: column.cxx:3325
bool HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW &rFirst)
Definition: column.cxx:3331
void MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn &rCol)
Definition: column.cxx:1897
bool HasSelectionMatrixFragment(const ScMarkData &rMark, const ScRangeList &rRangeList) const
Definition: column.cxx:192
void ApplySelectionLineStyle(const ScMarkData &rMark, const ::editeng::SvxBorderLine *pLine, bool bColorOnly)
Definition: column.cxx:537
bool IsEmptyData() const
Definition: column2.cxx:1252
void CompileAll(sc::CompileFormulaContext &rCxt)
Definition: column.cxx:3299
size_t mnBlkCountFormula
Definition: column.hxx:201
SCROW SearchStyle(SCROW nRow, const ScStyleSheet *pSearchStyle, bool bUp, bool bInSelection, const ScMarkData &rMark) const
May return -1 if not found.
Definition: column.cxx:3346
void SetTabNo(SCTAB nNewTab)
Definition: column.cxx:3104
void MergeSelectionPattern(ScMergePatternState &rState, const ScMarkData &rMark, bool bDeep) const
Definition: column.cxx:320
void UndoToColumn(sc::CopyToDocContext &rCxt, SCROW nRow1, SCROW nRow2, InsertDeleteFlags nFlags, bool bMarked, ScColumn &rColumn) const
Definition: column.cxx:1662
void ApplyStyle(SCROW nRow, const ScStyleSheet *rStyle)
Definition: column.cxx:516
void UpdateCompile(bool bForceIfNameInUse=false)
Definition: column.cxx:3098
bool HasAttribSelection(const ScMarkData &rMark, HasAttrFlags nMask) const
Definition: column.cxx:300
sc::CellStoreType maCells
Definition: column.hxx:196
ScRefCellValue GetCellValue(SCROW nRow) const
Definition: column.cxx:638
void CopyUpdated(const ScColumn *pPosCol, ScColumn &rDestCol) const
Definition: column.cxx:1675
void MarkScenarioIn(ScMarkData &rDestMark) const
Definition: column.cxx:1770
void InsertRow(SCROW nStartRow, SCSIZE nSize)
Definition: column.cxx:765
void CopyStaticToDocument(SCROW nRow1, SCROW nRow2, const SvNumberFormatterMergeMap &rMap, ScColumn &rDestCol)
Definition: column.cxx:964
void CopyScenarioFrom(const ScColumn &rSrcCol)
Definition: column.cxx:1698
void CopyToClip(sc::CopyToClipContext &rCxt, SCROW nRow1, SCROW nRow2, ScColumn &rColumn) const
Definition: column.cxx:945
void CopyCellNotesToDocument(SCROW nRow1, SCROW nRow2, ScColumn &rDestCol, bool bCloneCaption=true, SCROW nRowOffsetDest=0) const
Definition: column2.cxx:1918
bool IsDrawObjectsEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
Definition: column.cxx:1857
void UpdateTranspose(const ScRange &rSource, const ScAddress &rDest, ScDocument *pUndoDoc)
Definition: column.cxx:3033
void CalcAll()
Definition: column.cxx:3293
sc::CellTextAttrStoreType & GetCellAttrStore()
Definition: column.hxx:258
void UpdateGrow(const ScRange &rArea, SCCOL nGrowX, SCROW nGrowY)
Definition: column.cxx:3040
const ScStyleSheet * GetAreaStyle(bool &rFound, SCROW nRow1, SCROW nRow2) const
Definition: column.cxx:593
void UpdateInsertTab(sc::RefUpdateInsertTabContext &rCxt)
Definition: column.cxx:3046
void ChangeSelectionIndent(bool bIncrement, const ScMarkData &rMark)
Definition: column.cxx:421
void SwapCol(ScColumn &rCol)
Definition: column.cxx:1867
void ApplyPatternIfNumberformatIncompatible(const ScRange &rRange, const ScPatternAttr &rPattern, SvNumFormatType nNewType)
Definition: column.cxx:490
sc::CellStoreType & GetCellStore()
Definition: column.hxx:256
bool UpdateReference(sc::RefUpdateContext &rCxt, ScDocument *pUndoDoc)
Update reference addresses in formula cell in response to mass cell movement.
Definition: column.cxx:2384
void DeleteArea(SCROW nStartRow, SCROW nEndRow, InsertDeleteFlags nDelFlag, bool bBroadcast=true, sc::ColumnSpanSet *pBroadcastSpans=nullptr)
Definition: column3.cxx:1062
void ApplySelectionStyle(const ScStyleSheet &rStyle, const ScMarkData &rMark)
Definition: column.cxx:524
bool IsFormulaDirty(SCROW nRow) const
Definition: column.cxx:3125
void SetDirtyFromClip(SCROW nRow1, SCROW nRow2, sc::ColumnSpanSet &rBroadcastSpans)
Definition: column.cxx:3155
void CopyCellToDocument(SCROW nSrcRow, SCROW nDestRow, ScColumn &rDestCol)
Definition: column.cxx:1089
static void JoinNewFormulaCell(const sc::CellStoreType::position_type &aPos, ScFormulaCell &rCell)
Definition: column3.cxx:361
void ClearSelectionItems(const sal_uInt16 *pWhich, const ScMarkData &rMark)
Definition: column.cxx:449
bool BroadcastBroadcasters(SCROW nRow1, SCROW nRow2, SfxHintId nHint)
Broadcast single broadcasters in range, without explicitly setting anything dirty,...
Definition: column.cxx:3192
void SetDirtyIfPostponed()
Definition: column.cxx:3277
sc::BroadcasterStoreType maBroadcasters
Definition: column.hxx:193
void UpdateMoveTab(sc::RefUpdateMoveTabContext &rCxt, SCTAB nTabNo)
Definition: column.cxx:3087
const sc::CellTextAttr * GetCellTextAttr(SCROW nRow) const
Definition: column.cxx:692
void FindRangeNamesInUse(SCROW nRow1, SCROW nRow2, sc::UpdatedRangeNames &rIndexes) const
Definition: column.cxx:3113
ScColumn(ScSheetLimits const &)
Definition: column.cxx:82
ScDocument & GetDoc() const
Definition: column.hxx:127
sal_uInt32 GetNumberFormat(const ScInterpreterContext &rContext, SCROW nRow) const
Definition: column.hxx:967
sc::SparklineStoreType maSparklines
Definition: column.hxx:199
void SetDirtyAfterLoad()
Definition: column.cxx:3250
bool SearchStyleRange(SCROW &rRow, SCROW &rEndRow, const ScStyleSheet *pSearchStyle, bool bUp, bool bInSelection, const ScMarkData &rMark) const
Definition: column.cxx:3364
bool IsInFormulaTree(const ScFormulaCell *pCell) const
void TrackFormulas(SfxHintId nHintId=SfxHintId::ScDataChanged)
Definition: documen7.cxx:530
bool IsUndo() const
Definition: document.hxx:1591
SC_DLLPUBLIC ScFormulaCell * SetFormulaCell(const ScAddress &rPos, ScFormulaCell *pCell)
Set formula cell, and transfer its ownership to the document.
Definition: documen2.cxx:1108
SC_DLLPUBLIC ScPatternAttr * GetDefPattern() const
Definition: document.cxx:6164
bool ValidRow(SCROW nRow) const
Definition: document.hxx:899
bool SetFormulaCells(const ScAddress &rPos, std::vector< ScFormulaCell * > &rCells)
Definition: documen2.cxx:1119
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6169
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:892
SC_DLLPUBLIC ScFieldEditEngine & GetEditEngine()
Definition: documen2.cxx:477
ScInterpreterContext & GetNonThreadedContext() const
Definition: document.hxx:616
SC_DLLPUBLIC bool GetAutoCalc() const
Definition: document.hxx:1411
TableContainer maTabs
Definition: document.hxx:377
SC_DLLPUBLIC ScDrawLayer * GetDrawLayer()
Definition: document.hxx:1082
SC_DLLPUBLIC formula::FormulaGrammar::Grammar GetGrammar() const
Definition: document.hxx:1008
SC_DLLPUBLIC svl::SharedStringPool & GetSharedStringPool()
Definition: documen2.cxx:586
bool IsExpandRefs() const
Definition: document.hxx:2450
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:461
SC_DLLPUBLIC const ScFormulaCell * GetFormulaCell(const ScAddress &rPos) const
Definition: document.cxx:3765
void PutInFormulaTree(ScFormulaCell *pCell)
Definition: documen7.cxx:271
SC_DLLPUBLIC const SfxPoolItem * GetAttr(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich) const
Definition: document.cxx:4777
void AreaBroadcast(const ScHint &rHint)
only area, no cell broadcast
Definition: documen7.cxx:203
bool HasObjectsAnchoredInRange(const ScRange &rRange)
Definition: drwlayer.cxx:2513
void MoveObject(SdrObject *pObj, const ScAddress &rNewPosition)
Definition: drwlayer.cxx:2561
static std::unique_ptr< EditTextObject > Clone(const EditTextObject &rSrc, ScDocument &rDestDoc)
Definition: editutil.cxx:189
static SC_DLLPUBLIC OUString GetString(const EditTextObject &rEditText, const ScDocument *pDoc)
Retrieves string with paragraphs delimited by new lines (' ').
Definition: editutil.cxx:119
void GetMatColsRows(SCCOL &nCols, SCROW &nRows) const
bool IsShared() const
SCROW GetSharedLength() const
ScMatrixMode GetMatrixFlag() const
void SetErrCode(FormulaError n)
void SetNeedNumberFormat(bool bVal)
void UpdateTranspose(const ScRange &rSource, const ScAddress &rDest, ScDocument *pUndoDoc)
void CompileXML(sc::CompileFormulaContext &rCxt, ScProgress &rProgress)
bool IsPostponedDirty() const
void SetCompile(bool bVal)
RelNameRef HasRelNameReference() const
bool IsSharedTop() const
sc::MatrixEdge GetMatrixEdge(const ScDocument &rDoc, ScAddress &rOrgPos) const
void UpdateCompile(bool bForceIfNameInUse)
double GetValue()
void UpdateDeleteTab(const sc::RefUpdateDeleteTabContext &rCxt)
void UpdateInsertTab(const sc::RefUpdateInsertTabContext &rCxt)
bool UpdateReference(const sc::RefUpdateContext &rCxt, ScDocument *pUndoDoc=nullptr, const ScAddress *pUndoCellPos=nullptr)
void CalcAfterLoad(sc::CompileFormulaContext &rCxt, bool bStartListening)
void SetChanged(bool b)
bool GetDirty() const
const svl::SharedString & GetString()
FormulaError GetErrCode()
void UpdateInsertTabAbs(SCTAB nTable)
bool NeedsNumberFormat() const
bool UpdateReferenceOnShift(const sc::RefUpdateContext &rCxt, ScDocument *pUndoDoc, const ScAddress *pUndoCellPos)
Update reference in response to cell insertion or deletion.
void SetDirtyAfterLoad()
void UpdateGrow(const ScRange &rArea, SCCOL nGrowX, SCROW nGrowY)
FormulaError GetRawError() const
void SetDirty(bool bDirtyFlag=true)
void FindRangeNamesInUse(sc::UpdatedRangeNames &rIndexes) const
ScFormulaCellGroupRef CreateCellGroup(SCROW nLen, bool bInvariant)
Turn a non-grouped cell into the top of a grouped cell.
bool UpdatePosOnShift(const sc::RefUpdateContext &rCxt)
Shift the position of formula cell as part of reference update.
void Compile(const OUString &rFormula, bool bNoListening, const formula::FormulaGrammar::Grammar)
ScTokenArray * GetCode()
bool IsMultilineResult()
Determines whether or not the result string contains more than one paragraph.
bool UpdateReferenceOnMove(const sc::RefUpdateContext &rCxt, ScDocument *pUndoDoc, const ScAddress *pUndoCellPos)
Update reference in response to cell move.
ScAddress aPos
bool Interpret(SCROW nStartOffset=-1, SCROW nEndOffset=-1)
void UpdateMoveTab(const sc::RefUpdateMoveTabContext &rCxt, SCTAB nTabNo)
OUString GetFormula(const formula::FormulaGrammar::Grammar=formula::FormulaGrammar::GRAM_DEFAULT, const ScInterpreterContext *pContext=nullptr) const
void CompileTokenArray(bool bNoListening=false)
@ NONE
no relative reference from named expression
void SetAddressRow(SCROW nRow)
Definition: brdcst.hxx:37
This is a rather odd datastructure.
Definition: markarr.hxx:44
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:43
bool IsAllMarked(const ScRange &rRange) const
Definition: markdata.cxx:565
const ScRange & GetMarkArea() const
Definition: markdata.hxx:83
bool IsMultiMarked() const
Definition: markdata.hxx:81
void SetMultiMarkArea(const ScRange &rRange, bool bMark=true, bool bSetupMulti=false)
Definition: markdata.cxx:107
const ScMultiSel & GetMultiSelData() const
Definition: markdata.hxx:106
bool IsMarked() const
Definition: markdata.hxx:80
ScMarkArray GetMarkArray(SCCOL nCol) const
Definition: markdata.hxx:107
bool Next(SCROW &rTop, SCROW &rBottom)
Definition: markmulti.cxx:455
bool HasMarks(SCCOL nCol) const
Definition: markmulti.cxx:65
const ScStyleSheet * GetStyleSheet() const
Definition: patattr.hxx:128
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
void UpdateCaptionPos(const ScAddress &rPos)
Updates caption position according to position of the passed cell.
Definition: postit.cxx:638
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
size_t size() const
Definition: rangelst.hxx:89
ScAddress aEnd
Definition: address.hxx:498
bool Contains(const ScAddress &) const
is Address& fully in Range?
Definition: address.hxx:718
ScAddress aStart
Definition: address.hxx:497
void CheckExpandReferenceBounds(const sc::RefUpdateContext &rCxt, const ScAddress &rPos, SCROW nGroupLen, std::vector< SCROW > &rBounds) const
Definition: token.cxx:4813
ScTokenArray CloneValue() const
True copy!
Definition: token.cxx:1989
sc::RefUpdateResult AdjustReferenceOnShift(const sc::RefUpdateContext &rCxt, const ScAddress &rOldPos)
Adjust all references in response to shifting of cells during cell insertion and deletion.
Definition: token.cxx:3130
void CheckRelativeReferenceBounds(const sc::RefUpdateContext &rCxt, const ScAddress &rPos, SCROW nGroupLen, std::vector< SCROW > &rBounds) const
Definition: token.cxx:4742
virtual void CheckToken(const formula::FormulaToken &r) override
Definition: token.cxx:1355
std::unique_ptr< ScTokenArray > Clone() const
Definition: token.cxx:1931
void ResetVectorState()
Definition: token.cxx:1800
bool IsFormulaVectorDisabled() const
Definition: token.cxx:1807
sc::RefUpdateResult AdjustReferenceOnMove(const sc::RefUpdateContext &rCxt, const ScAddress &rOldPos, const ScAddress &rNewPos)
Definition: token.cxx:3361
void ClearTabDeleted(const ScAddress &rPos, SCTAB nStartTab, SCTAB nEndTab)
Clear sheet deleted flag from internal reference tokens if the sheet index falls within specified ran...
Definition: token.cxx:4602
const SfxSetItem & ApplyTo(const SfxSetItem &rSetItem)
const T & Put(std::unique_ptr< T > xItem, sal_uInt16 nWhich=0)
void Remove(const SfxPoolItem &)
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
SvNumFormatType GetType(sal_uInt32 nFIndex) const
static bool IsCompatible(SvNumFormatType eOldType, SvNumFormatType eNewType)
void Broadcast(const SfxHint &rHint)
void updateTableFields(int nTab)
bool IsRecalcModeNormal() const
sal_uInt16 GetLen() const
void SetCodeError(FormulaError n)
FormulaToken * FirstToken() const
bool IsRecalcModeOnRefMove() const
Temporarily switch on/off auto calculation mode.
Definition: scopetools.hxx:27
ColumnBlockPosition * getBlockPosition(SCTAB nTab, SCCOL nCol)
Definition: clipcontext.cxx:32
void set(SCTAB nTab, SCCOL nCol)
Definition: columnset.cxx:15
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)
bool isKeepScenarioFlags() const
bool isStartListening() const
Wrapper for ScDocument::EnableDelayStartListeningFormulaCells()
Definition: scopetools.hxx:85
static void groupFormulaCells(const Iter &itBeg, const Iter &itEnd)
Group formula cells stored in the passed container.
static void unshareFormulaCell(const CellStoreType::position_type &aPos, ScFormulaCell &rCell)
Turn a shared formula cell into a non-shared one, and split it off from the adjacent formula cell gro...
static bool joinFormulaCellAbove(const CellStoreType::position_type &aPos)
Merge with an existing formula group (if any) located immediately above if the cell at specified posi...
static bool splitFormulaCellGroup(const CellStoreType::position_type &aPos, sc::EndListeningContext *pCxt)
Split existing shared formula range at specified position.
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
void getRows(std::vector< SCROW > &rRows) const
void set(SCROW nRow1, SCROW nRow2, bool bVal)
Keep track of all named expressions that have been updated during reference update.
SharedString intern(const OUString &rStr)
const OUString & getString() const
bool isEmpty() const
bool isValid() const
sal_Int32 mnCol
EmbeddedObjectRef * pObject
FormulaError
@ URM_COPY
Definition: global.hxx:302
@ URM_MOVE
Definition: global.hxx:303
@ URM_INSDEL
Definition: global.hxx:301
InsertDeleteFlags
Definition: global.hxx:149
@ NOTE
Strings (and string results if InsertDeleteFlags::FORMULA is not set).
@ NOCAPTIONS
Sparklines in a cell.
@ SPECIAL_BOOLEAN
Internal use only (copy from clip): do not delete existing cell contents when pasting notes.
@ STRING
Dates, times, datetime values.
@ ADDNOTES
Internal use only (undo etc.): do not copy/delete caption objects of cell notes.
@ DATETIME
Numeric values (and numeric results if InsertDeleteFlags::FORMULA is not set).
@ ATTRIB
Internal use only (d&d undo): do not delete caption objects of cell notes.
@ FORMULA
Cell notes.
@ STYLES
Hard cell attributes.
HasAttrFlags
Definition: global.hxx:184
ScCloneFlags
Definition: global.hxx:250
@ NamesToLocal
If set, global named expressions will be converted to sheet-local named expressions.
SfxHintId
Mode eMode
void * p
sal_Int64 n
SvtScriptType
sal_uInt16 nPos
aStr
int i
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 >)
CAUTION! The following defines must be in the same namespace as the respective type.
StoreT::const_iterator ParseBlock(const typename StoreT::const_iterator &itPos, const StoreT &rStore, Func &rFunc, typename StoreT::size_type nStart, typename StoreT::size_type nEnd)
Generic algorithm to parse blocks of multi_type_vector either partially or fully.
const mdds::mtv::element_t element_type_celltextattr
Definition: mtvelements.hxx:46
const mdds::mtv::element_t element_type_edittext
Definition: mtvelements.hxx:49
CellStoreType::iterator ProcessFormula(const CellStoreType::iterator &it, CellStoreType &rStore, SCROW nRow1, SCROW nRow2, std::function< void(size_t, ScFormulaCell *)> aFuncElem)
Process formula cells found within specified row range.
Definition: mtvcellfunc.cxx:12
MatrixEdge
Definition: types.hxx:65
const mdds::mtv::element_t element_type_formula
Definition: mtvelements.hxx:50
StoreT::iterator ProcessBlock(const typename StoreT::iterator &itPos, StoreT &rStore, Func &rFunc, typename StoreT::size_type nStart, typename StoreT::size_type nEnd)
Non-const variant of the above function.
BroadcasterStoreType::iterator ProcessBroadcaster(const BroadcasterStoreType::iterator &it, BroadcasterStoreType &rStore, SCROW nRow1, SCROW nRow2, FuncElem &rFuncElem)
void ParseFormula(const CellStoreType &rStore, Func &rFunc)
Definition: mtvcellfunc.hxx:63
mdds::mtv::soa::multi_type_vector< CellFunc, CellStoreTrait > CellStoreType
const mdds::mtv::element_t element_type_numeric
Mapped standard element types (for convenience).
Definition: mtvelements.hxx:56
void ProcessFormulaEditText(CellStoreType &rStore, Func &rFunc)
std::pair< CellStoreType::const_iterator, size_t > FindFormulaEditText(const CellStoreType &rStore, SCROW nRow1, SCROW nRow2, Func &rFunc)
StartListeningType
Definition: types.hxx:124
@ SingleCellListening
Definition: types.hxx:126
@ NoListening
Definition: types.hxx:127
void ProcessNote(CellNoteStoreType &rStore, Func &rFunc)
const mdds::mtv::element_t element_type_string
Definition: mtvelements.hxx:48
mdds::mtv::soa::multi_type_vector< CTAttrFunc > CellTextAttrStoreType
const mdds::mtv::element_t element_type_empty
Definition: mtvelements.hxx:57
const SvxPageUsage aArr[]
ocFalse
ocTrue
QPRO_FUNC_TYPE nType
Definition: qproform.cxx:398
constexpr TypedWhichId< ScMergeFlagAttr > ATTR_MERGE_FLAG(145)
constexpr TypedWhichId< SfxUInt32Item > ATTR_VALUE_FORMAT(146)
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
Single reference (one address) into the sheet.
Definition: refdata.hxx:30
void InitAddress(const ScAddress &rAdr)
InitAddress: InitFlags and set address.
Definition: refdata.cxx:27
void SetFlag3D(bool bVal)
Definition: refdata.hxx:89
CellTextAttrStoreType::const_iterator miCellTextAttrPos
CellStoreType::const_iterator miCellPos
Store position data for column array storage.
CellTextAttrStoreType::iterator miCellTextAttrPos
BroadcasterStoreType::iterator miBroadcasterPos
CellStoreType::iterator miCellPos
ScFormulaCell * mpCell
ScFormulaCell ** mpCells
Context for reference update during shifting, moving or copying of cell ranges.
ColumnBlockPosition * getBlockPosition(SCTAB nTab, SCCOL nCol)
SCROW mnRowDelta
Amount and direction of movement in the row direction.
UpdateRefMode meMode
update mode - insert/delete, copy, or move.
SCCOL mnColDelta
Amount and direction of movement in the column direction.
SCTAB mnTabDelta
Amount and direction of movement in the sheet direction.
ScRange maRange
Range of cells that are about to be moved for insert/delete/move modes.
bool mbReferenceModified
This flag indicates whether any reference in the token array has been modified.
bool mbValueChanged
When this flag is true, the result of the formula needs to be re-calculated either because it contain...
bool mbNameModified
When this flag is true, it indicates that the token array contains a range name that's been updated.
bool mbClearTabDeletedFlag
When true, go through all reference tokens and clears "sheet deleted" flag if its corresponding index...
@ Left
Definition: tphfedit.hxx:40
@ Right
Definition: tphfedit.hxx:42
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
sal_Int32 nLength
SvNumFormatType
std::unordered_map< sal_uInt32, sal_uInt32 > SvNumberFormatterMergeMap