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