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