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