1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <scitems.hxx>
22 #include <formulacell.hxx>
24 #include <document.hxx>
26 #include <attarray.hxx>
27 #include <patattr.hxx>
28 #include <compiler.hxx>
30 #include <markdata.hxx>
32 #include <cellvalue.hxx>
33 #include <tokenarray.hxx>
34 #include <clipcontext.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>
48 #include <svl/numformat.hxx>
49 #include <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>
61 using ::editeng::SvxBorderLine
;
62 using namespace formula
;
66 bool IsAmbiguousScriptNonZero( SvtScriptType nScript
)
68 //TODO: move to a header file
69 return ( nScript
!= SvtScriptType::LATIN
&&
70 nScript
!= SvtScriptType::ASIAN
&&
71 nScript
!= SvtScriptType::COMPLEX
&&
72 nScript
!= SvtScriptType::NONE
);
77 ScNeededSizeOptions::ScNeededSizeOptions() :
78 aPattern(), bFormula(false), bSkipMerged(true), bGetFont(true), bTotalSize(false)
82 ScColumn::ScColumn(ScSheetLimits
const & rSheetLimits
) :
83 maCellTextAttrs(rSheetLimits
.GetMaxRowCount()),
84 maCellNotes(sc::CellStoreEvent(this)),
85 maBroadcasters(rSheetLimits
.GetMaxRowCount()),
86 maCells(sc::CellStoreEvent(this)),
87 maSparklines(rSheetLimits
.GetMaxRowCount()),
89 mnBlkCountCellNotes(0),
92 mbEmptyBroadcastersPending( false )
94 maCellNotes
.resize(rSheetLimits
.GetMaxRowCount());
95 maCells
.resize(rSheetLimits
.GetMaxRowCount());
98 ScColumn::~ScColumn() COVERITY_NOEXCEPT_FALSE
103 void ScColumn::Init(SCCOL nNewCol
, SCTAB nNewTab
, ScDocument
& rDoc
, bool bEmptyAttrArray
)
107 if ( bEmptyAttrArray
)
108 InitAttrArray(new ScAttrArray( nCol
, nTab
, rDoc
, nullptr ));
110 InitAttrArray(new ScAttrArray( nCol
, nTab
, rDoc
, &rDoc
.maTabs
[nTab
]->aDefaultColData
.AttrArray()));
113 sc::MatrixEdge
ScColumn::GetBlockMatrixEdges( SCROW nRow1
, SCROW nRow2
, sc::MatrixEdge nMask
,
114 bool bNoMatrixAtAll
) const
118 if (!GetDoc().ValidRow(nRow1
) || !GetDoc().ValidRow(nRow2
) || nRow1
> nRow2
)
119 return MatrixEdge::Nothing
;
121 ScAddress
aOrigin(ScAddress::INITIALIZE_INVALID
);
125 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nRow1
);
126 if (aPos
.first
->type
!= sc::element_type_formula
)
127 return MatrixEdge::Nothing
;
129 const ScFormulaCell
* pCell
= sc::formula_block::at(*aPos
.first
->data
, aPos
.second
);
130 if (pCell
->GetMatrixFlag() == ScMatrixMode::NONE
)
131 return MatrixEdge::Nothing
;
133 return pCell
->GetMatrixEdge(GetDoc(), aOrigin
);
137 MatrixEdge nEdges
= MatrixEdge::Nothing
;
139 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nRow1
);
140 sc::CellStoreType::const_iterator it
= aPos
.first
;
141 size_t nOffset
= aPos
.second
;
143 for (;it
!= maCells
.end() && nRow
<= nRow2
; ++it
, nOffset
= 0)
145 if (it
->type
!= sc::element_type_formula
)
148 nRow
+= it
->size
- nOffset
;
152 size_t nRowsToRead
= nRow2
- nRow
+ 1;
153 size_t nEnd
= std::min(it
->size
, nOffset
+nRowsToRead
); // last row + 1
154 sc::formula_block::const_iterator itCell
= sc::formula_block::begin(*it
->data
);
155 std::advance(itCell
, nOffset
);
156 for (size_t i
= nOffset
; i
< nEnd
; ++itCell
, ++i
)
158 // Loop inside the formula block.
159 const ScFormulaCell
* pCell
= *itCell
;
160 if (pCell
->GetMatrixFlag() == ScMatrixMode::NONE
)
163 nEdges
= pCell
->GetMatrixEdge(GetDoc(), aOrigin
);
164 if (nEdges
== MatrixEdge::Nothing
)
167 // A 1x1 matrix array formula is OK even for no matrix at all.
169 && (nEdges
!= (MatrixEdge::Top
| MatrixEdge::Left
| MatrixEdge::Bottom
| MatrixEdge::Right
)))
170 return MatrixEdge::Inside
; // per convention Inside
172 if (nEdges
& MatrixEdge::Top
)
173 bOpen
= true; // top edge opens, keep on looking
175 return nEdges
| MatrixEdge::Open
; // there's something that wasn't opened
176 else if (nEdges
& MatrixEdge::Inside
)
177 return nEdges
; // inside
178 if (((nMask
& MatrixEdge::Right
) && (nEdges
& MatrixEdge::Left
) && !(nEdges
& MatrixEdge::Right
)) ||
179 ((nMask
& MatrixEdge::Left
) && (nEdges
& MatrixEdge::Right
) && !(nEdges
& MatrixEdge::Left
)))
180 return nEdges
; // only left/right edge
182 if (nEdges
& MatrixEdge::Bottom
)
183 bOpen
= false; // bottom edge closes
186 nRow
+= nEnd
- nOffset
;
189 nEdges
|= MatrixEdge::Open
; // not closed, matrix continues
194 bool ScColumn::HasSelectionMatrixFragment(const ScMarkData
& rMark
, const ScRangeList
& rRangeList
) const
198 if (!rMark
.IsMultiMarked())
201 ScAddress
aOrigin(ScAddress::INITIALIZE_INVALID
);
202 ScAddress aCurOrigin
= aOrigin
;
205 for (size_t i
= 0, n
= rRangeList
.size(); i
< n
; ++i
)
207 const ScRange
& r
= rRangeList
[i
];
208 if (nTab
< r
.aStart
.Tab() || r
.aEnd
.Tab() < nTab
)
211 if (nCol
< r
.aStart
.Col() || r
.aEnd
.Col() < nCol
)
214 SCROW nTop
= r
.aStart
.Row(), nBottom
= r
.aEnd
.Row();
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
;
220 for (;it
!= maCells
.end() && nRow
<= nBottom
; ++it
, nOffset
= 0)
222 if (it
->type
!= sc::element_type_formula
)
225 nRow
+= it
->size
- nOffset
;
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
)
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.
242 MatrixEdge nEdges
= pCell
->GetMatrixEdge(GetDoc(), aOrigin
);
243 if (nEdges
== MatrixEdge::Nothing
)
248 if (nEdges
& MatrixEdge::Top
)
249 bOpen
= true; // top edge opens, keep on looking
251 return true; // there's something that wasn't opened
252 else if (nEdges
& MatrixEdge::Inside
)
253 bFound
= true; // inside, all selected?
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?
259 if (nEdges
& MatrixEdge::Bottom
)
260 bOpen
= false; // bottom edge closes
264 // Check if the matrix is inside the selection in its entirety.
266 // TODO: It's more efficient to skip the matrix range if
267 // it's within selection, to avoid checking it again and
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
);
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
))
287 bFound
= false; // done already
301 bool ScColumn::HasAttribSelection( const ScMarkData
& rMark
, HasAttrFlags nMask
) const
308 if (rMark
.IsMultiMarked())
310 ScMultiSelIter
aMultiIter( rMark
.GetMultiSelData(), nCol
);
311 while (aMultiIter
.Next( nTop
, nBottom
) && !bFound
)
313 if (pAttrArray
->HasAttrib( nTop
, nBottom
, nMask
))
321 void ScColumn::MergeSelectionPattern( ScMergePatternState
& rState
, const ScMarkData
& rMark
, bool bDeep
) const
326 if ( rMark
.IsMultiMarked() )
328 const ScMultiSel
& rMultiSel
= rMark
.GetMultiSelData();
329 if ( rMultiSel
.HasMarks( nCol
) )
331 ScMultiSelIter
aMultiIter( rMultiSel
, nCol
);
332 while (aMultiIter
.Next( nTop
, nBottom
))
333 pAttrArray
->MergePatternArea( nTop
, nBottom
, rState
, bDeep
);
338 const ScPatternAttr
* ScColumnData::GetMostUsedPattern( SCROW nStartRow
, SCROW nEndRow
) const
340 ::std::map
< const ScPatternAttr
*, size_t > aAttrMap
;
341 const ScPatternAttr
* pMaxPattern
= nullptr;
342 size_t nMaxCount
= 0;
344 ScAttrIterator
aAttrIter( pAttrArray
.get(), nStartRow
, nEndRow
, &GetDoc().getCellAttributeHelper().getDefaultCellAttribute() );
345 const ScPatternAttr
* pPattern
;
346 SCROW nAttrRow1
= 0, nAttrRow2
= 0;
348 while( (pPattern
= aAttrIter
.Next( nAttrRow1
, nAttrRow2
)) != nullptr )
350 size_t& rnCount
= aAttrMap
[ pPattern
];
351 rnCount
+= (nAttrRow2
- nAttrRow1
+ 1);
352 if( rnCount
> nMaxCount
)
354 pMaxPattern
= pPattern
;
362 sal_uInt32
ScColumnData::GetNumberFormat( SCROW nStartRow
, SCROW nEndRow
) const
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
)
369 nStartRow
= nPatEndRow
+ 1;
370 pPattern
= pAttrArray
->GetPatternRange(nPatStartRow
, nPatEndRow
, nStartRow
);
371 sal_uInt32 nTmpFormat
= pPattern
->GetNumberFormat(GetDoc().GetFormatTable());
372 if (nFormat
!= nTmpFormat
)
378 void ScColumnData::ApplySelectionCache(ScItemPoolCache
& rCache
, SCROW nStartRow
, SCROW nEndRow
,
379 ScEditDataArray
* pDataArray
, bool* pIsChanged
)
381 pAttrArray
->ApplyCacheArea(nStartRow
, nEndRow
, rCache
, pDataArray
, pIsChanged
);
384 void ScColumnData::ChangeSelectionIndent(bool bIncrement
, SCROW nStartRow
, SCROW nEndRow
)
386 pAttrArray
->ChangeIndent(nStartRow
, nEndRow
, bIncrement
);
389 void ScColumnData::ClearSelectionItems(const sal_uInt16
* pWhich
, SCROW nStartRow
, SCROW nEndRow
)
394 pAttrArray
->ClearItems(nStartRow
, nEndRow
, pWhich
);
397 void ScColumn::DeleteSelection( InsertDeleteFlags nDelFlag
, const ScMarkData
& rMark
, bool bBroadcast
)
402 if ( rMark
.IsMultiMarked() )
404 ScMultiSelIter
aMultiIter( rMark
.GetMultiSelData(), nCol
);
405 while (aMultiIter
.Next( nTop
, nBottom
))
406 DeleteArea(nTop
, nBottom
, nDelFlag
, bBroadcast
);
410 void ScColumn::ApplyPattern( SCROW nRow
, const ScPatternAttr
& rPatAttr
)
412 const SfxItemSet
* pSet
= &rPatAttr
.GetItemSet();
413 ScItemPoolCache
aCache( GetDoc().getCellAttributeHelper(), *pSet
);
415 const CellAttributeHolder
aPattern(pAttrArray
->GetPattern( nRow
));
417 // true = keep old content
419 const CellAttributeHolder
& rNewPattern
= aCache
.ApplyTo( aPattern
);
421 if (!CellAttributeHolder::areSame(&rNewPattern
, &aPattern
))
422 pAttrArray
->SetPattern( nRow
, rNewPattern
);
425 void ScColumnData::ApplyPatternArea( SCROW nStartRow
, SCROW nEndRow
, const ScPatternAttr
& rPatAttr
,
426 ScEditDataArray
* pDataArray
, bool* const pIsChanged
)
428 const SfxItemSet
* pSet
= &rPatAttr
.GetItemSet();
429 ScItemPoolCache
aCache( GetDoc().getCellAttributeHelper(), *pSet
);
430 pAttrArray
->ApplyCacheArea( nStartRow
, nEndRow
, aCache
, pDataArray
, pIsChanged
);
433 void ScColumn::ApplyPatternIfNumberformatIncompatible( const ScRange
& rRange
,
434 const ScPatternAttr
& rPattern
, SvNumFormatType nNewType
)
436 const SfxItemSet
* pSet
= &rPattern
.GetItemSet();
437 ScItemPoolCache
aCache( GetDoc().getCellAttributeHelper(), *pSet
);
438 SvNumberFormatter
* pFormatter
= GetDoc().GetFormatTable();
439 SCROW nEndRow
= rRange
.aEnd
.Row();
440 for ( SCROW nRow
= rRange
.aStart
.Row(); nRow
<= nEndRow
; nRow
++ )
443 const ScPatternAttr
* pPattern
= pAttrArray
->GetPatternRange(
444 nRow1
, nRow2
, nRow
);
445 sal_uInt32 nFormat
= pPattern
->GetNumberFormat( pFormatter
);
446 SvNumFormatType nOldType
= pFormatter
->GetType( nFormat
);
447 if ( nOldType
== nNewType
|| SvNumberFormatter::IsCompatible( nOldType
, nNewType
) )
451 SCROW nNewRow1
= std::max( nRow1
, nRow
);
452 SCROW nNewRow2
= std::min( nRow2
, nEndRow
);
453 pAttrArray
->ApplyCacheArea( nNewRow1
, nNewRow2
, aCache
);
459 void ScColumn::ApplyStyle( SCROW nRow
, const ScStyleSheet
* rStyle
)
461 const ScPatternAttr
* pPattern
= pAttrArray
->GetPattern(nRow
);
462 ScPatternAttr
* pNewPattern(new ScPatternAttr(*pPattern
));
463 pNewPattern
->SetStyleSheet(const_cast<ScStyleSheet
*>(rStyle
));
464 pAttrArray
->SetPattern(nRow
, CellAttributeHolder(pNewPattern
, true));
467 void ScColumnData::ApplySelectionStyle(const ScStyleSheet
& rStyle
, SCROW nTop
, SCROW nBottom
)
469 pAttrArray
->ApplyStyleArea(nTop
, nBottom
, rStyle
);
472 void ScColumn::ApplySelectionLineStyle( const ScMarkData
& rMark
,
473 const SvxBorderLine
* pLine
, bool bColorOnly
)
475 if ( bColorOnly
&& !pLine
)
481 if (rMark
.IsMultiMarked())
483 ScMultiSelIter
aMultiIter( rMark
.GetMultiSelData(), nCol
);
484 while (aMultiIter
.Next( nTop
, nBottom
))
485 pAttrArray
->ApplyLineStyleArea(nTop
, nBottom
, pLine
, bColorOnly
);
489 const ScStyleSheet
* ScColumn::GetSelectionStyle( const ScMarkData
& rMark
, bool& rFound
) const
492 if (!rMark
.IsMultiMarked())
494 OSL_FAIL("No selection in ScColumn::GetSelectionStyle");
500 const ScStyleSheet
* pStyle
= nullptr;
501 const ScStyleSheet
* pNewStyle
;
503 ScDocument
& rDocument
= GetDoc();
504 ScMultiSelIter
aMultiIter( rMark
.GetMultiSelData(), nCol
);
507 while (bEqual
&& aMultiIter
.Next( nTop
, nBottom
))
509 ScAttrIterator
aAttrIter( pAttrArray
.get(), nTop
, nBottom
, &rDocument
.getCellAttributeHelper().getDefaultCellAttribute() );
514 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nRow
, nDummy
);
517 pNewStyle
= pPattern
->GetStyleSheet();
519 if ( !pNewStyle
|| ( pStyle
&& pNewStyle
!= pStyle
) )
520 bEqual
= false; // difference
525 return bEqual
? pStyle
: nullptr;
528 const ScStyleSheet
* ScColumn::GetAreaStyle( bool& rFound
, SCROW nRow1
, SCROW nRow2
) const
534 const ScStyleSheet
* pStyle
= nullptr;
535 const ScStyleSheet
* pNewStyle
;
537 ScAttrIterator
aAttrIter( pAttrArray
.get(), nRow1
, nRow2
, &GetDoc().getCellAttributeHelper().getDefaultCellAttribute() );
542 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nRow
, nDummy
);
545 pNewStyle
= pPattern
->GetStyleSheet();
547 if ( !pNewStyle
|| ( pStyle
&& pNewStyle
!= pStyle
) )
548 bEqual
= false; // difference
552 return bEqual
? pStyle
: nullptr;
555 void ScColumn::ApplyAttr( SCROW nRow
, const SfxPoolItem
& rAttr
)
557 // in order to only create a new SetItem, we don't need SfxItemPoolCache.
558 //TODO: Warning: ScItemPoolCache seems to create too many Refs for the new SetItem ??
560 const ScPatternAttr
* pOldPattern(pAttrArray
->GetPattern(nRow
));
561 ScPatternAttr
* pNewPattern(new ScPatternAttr(*pOldPattern
));
562 pNewPattern
->GetItemSet().Put(rAttr
);
564 if (!ScPatternAttr::areSame( pNewPattern
, pOldPattern
))
565 pAttrArray
->SetPattern( nRow
, CellAttributeHolder(pNewPattern
, true) );
570 ScRefCellValue
ScColumn::GetCellValue( SCROW nRow
) const
572 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nRow
);
573 if (aPos
.first
== maCells
.end())
574 return ScRefCellValue();
576 return GetCellValue(aPos
.first
, aPos
.second
);
579 ScRefCellValue
ScColumn::GetCellValue( sc::ColumnBlockPosition
& rBlockPos
, SCROW nRow
)
581 std::pair
<sc::CellStoreType::iterator
,size_t> aPos
= maCells
.position(rBlockPos
.miCellPos
, nRow
);
582 if (aPos
.first
== maCells
.end())
583 return ScRefCellValue();
585 rBlockPos
.miCellPos
= aPos
.first
; // Store this for next call.
586 return GetCellValue(aPos
.first
, aPos
.second
);
589 ScRefCellValue
ScColumn::GetCellValue( sc::ColumnBlockConstPosition
& rBlockPos
, SCROW nRow
) const
591 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(rBlockPos
.miCellPos
, nRow
);
592 if (aPos
.first
== maCells
.end())
593 return ScRefCellValue();
595 rBlockPos
.miCellPos
= aPos
.first
; // Store this for next call.
596 return GetCellValue(aPos
.first
, aPos
.second
);
599 ScRefCellValue
ScColumn::GetCellValue( const sc::CellStoreType::const_iterator
& itPos
, size_t nOffset
)
603 case sc::element_type_numeric
:
605 return ScRefCellValue(sc::numeric_block::at(*itPos
->data
, nOffset
));
606 case sc::element_type_string
:
608 return ScRefCellValue(&sc::string_block::at(*itPos
->data
, nOffset
));
609 case sc::element_type_edittext
:
611 return ScRefCellValue(sc::edittext_block::at(*itPos
->data
, nOffset
));
612 case sc::element_type_formula
:
614 return ScRefCellValue(sc::formula_block::at(*itPos
->data
, nOffset
));
616 return ScRefCellValue(); // empty cell
620 const sc::CellTextAttr
* ScColumn::GetCellTextAttr( SCROW nRow
) const
622 sc::ColumnBlockConstPosition aBlockPos
;
623 aBlockPos
.miCellTextAttrPos
= maCellTextAttrs
.begin();
624 return GetCellTextAttr(aBlockPos
, nRow
);
627 const sc::CellTextAttr
* ScColumn::GetCellTextAttr( sc::ColumnBlockConstPosition
& rBlockPos
, SCROW nRow
) const
629 sc::CellTextAttrStoreType::const_position_type aPos
= maCellTextAttrs
.position(rBlockPos
.miCellTextAttrPos
, nRow
);
630 if (aPos
.first
== maCellTextAttrs
.end())
633 rBlockPos
.miCellTextAttrPos
= aPos
.first
;
635 if (aPos
.first
->type
!= sc::element_type_celltextattr
)
638 return &sc::celltextattr_block::at(*aPos
.first
->data
, aPos
.second
);
641 bool ScColumn::TestInsertCol( SCROW nStartRow
, SCROW nEndRow
) const
643 if (IsEmptyData() && IsEmptyAttr())
646 // Return false if we have any non-empty cells between nStartRow and nEndRow inclusive.
647 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nStartRow
);
648 sc::CellStoreType::const_iterator it
= aPos
.first
;
649 if (it
->type
!= sc::element_type_empty
)
652 // Get the length of the remaining empty segment.
653 size_t nLen
= it
->size
- aPos
.second
;
654 SCROW nNextNonEmptyRow
= nStartRow
+ nLen
;
655 if (nNextNonEmptyRow
<= nEndRow
)
658 // AttrArray only looks for merged cells
660 return pAttrArray
== nullptr || pAttrArray
->TestInsertCol(nStartRow
, nEndRow
);
663 bool ScColumn::TestInsertRow( SCROW nStartRow
, SCSIZE nSize
) const
665 // AttrArray only looks for merged cells
667 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nStartRow
);
668 sc::CellStoreType::const_iterator it
= aPos
.first
;
669 if (it
->type
== sc::element_type_empty
&& maCells
.block_size() == 1)
670 // The entire cell array is empty.
671 return pAttrArray
->TestInsertRow(nSize
);
674 // See if there would be any non-empty cell that gets pushed out.
676 // Find the position of the last non-empty cell below nStartRow.
677 size_t nLastNonEmptyRow
= GetDoc().MaxRow();
678 sc::CellStoreType::const_reverse_iterator it
= maCells
.rbegin();
679 if (it
->type
== sc::element_type_empty
)
680 nLastNonEmptyRow
-= it
->size
;
682 if (nLastNonEmptyRow
< o3tl::make_unsigned(nStartRow
))
683 // No cells would get pushed out.
684 return pAttrArray
->TestInsertRow(nSize
);
686 if (nLastNonEmptyRow
+ nSize
> o3tl::make_unsigned(GetDoc().MaxRow()))
687 // At least one cell would get pushed out. Not good.
690 return pAttrArray
->TestInsertRow(nSize
);
693 void ScColumn::InsertRow( SCROW nStartRow
, SCSIZE nSize
)
695 pAttrArray
->InsertRow( nStartRow
, nSize
);
697 maCellNotes
.insert_empty(nStartRow
, nSize
);
698 maCellNotes
.resize(GetDoc().GetMaxRowCount());
700 maSparklines
.insert_empty(nStartRow
, nSize
);
701 maSparklines
.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
703 maBroadcasters
.insert_empty(nStartRow
, nSize
);
704 maBroadcasters
.resize(GetDoc().GetMaxRowCount());
706 maCellTextAttrs
.insert_empty(nStartRow
, nSize
);
707 maCellTextAttrs
.resize(GetDoc().GetMaxRowCount());
709 maCells
.insert_empty(nStartRow
, nSize
);
710 maCells
.resize(GetDoc().GetMaxRowCount());
712 CellStorageModified();
714 // We *probably* don't need to broadcast here since the parent call seems
715 // to take care of it.
720 class CopyToClipHandler
722 const ScDocument
& mrSrcDoc
;
723 const ScColumn
& mrSrcCol
;
725 sc::ColumnBlockPosition maDestPos
;
726 sc::ColumnBlockPosition
* mpDestPos
;
728 void setDefaultAttrsToDest(size_t nRow
, size_t nSize
)
730 std::vector
<sc::CellTextAttr
> aAttrs(nSize
); // default values
731 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set(
732 maDestPos
.miCellTextAttrPos
, nRow
, aAttrs
.begin(), aAttrs
.end());
736 CopyToClipHandler(const ScDocument
& rSrcDoc
, const ScColumn
& rSrcCol
, ScColumn
& rDestCol
, sc::ColumnBlockPosition
* pDestPos
) :
737 mrSrcDoc(rSrcDoc
), mrSrcCol(rSrcCol
), mrDestCol(rDestCol
), mpDestPos(pDestPos
)
740 maDestPos
= *mpDestPos
;
742 mrDestCol
.InitBlockPosition(maDestPos
);
748 *mpDestPos
= maDestPos
;
751 void operator() (const sc::CellStoreType::value_type
& aNode
, size_t nOffset
, size_t nDataSize
)
753 size_t nTopRow
= aNode
.position
+ nOffset
;
759 case sc::element_type_numeric
:
761 sc::numeric_block::const_iterator it
= sc::numeric_block::begin(*aNode
.data
);
762 std::advance(it
, nOffset
);
763 sc::numeric_block::const_iterator itEnd
= it
;
764 std::advance(itEnd
, nDataSize
);
765 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nTopRow
, it
, itEnd
);
768 case sc::element_type_string
:
770 sc::string_block::const_iterator it
= sc::string_block::begin(*aNode
.data
);
771 std::advance(it
, nOffset
);
772 sc::string_block::const_iterator itEnd
= it
;
773 std::advance(itEnd
, nDataSize
);
774 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nTopRow
, it
, itEnd
);
778 case sc::element_type_edittext
:
780 sc::edittext_block::const_iterator it
= sc::edittext_block::begin(*aNode
.data
);
781 std::advance(it
, nOffset
);
782 sc::edittext_block::const_iterator itEnd
= it
;
783 std::advance(itEnd
, nDataSize
);
785 std::vector
<EditTextObject
*> aCloned
;
786 aCloned
.reserve(nDataSize
);
787 for (; it
!= itEnd
; ++it
)
788 aCloned
.push_back(ScEditUtil::Clone(**it
, mrDestCol
.GetDoc()).release());
790 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(
791 maDestPos
.miCellPos
, nTopRow
, aCloned
.begin(), aCloned
.end());
794 case sc::element_type_formula
:
796 sc::formula_block::const_iterator it
= sc::formula_block::begin(*aNode
.data
);
797 std::advance(it
, nOffset
);
798 sc::formula_block::const_iterator itEnd
= it
;
799 std::advance(itEnd
, nDataSize
);
801 std::vector
<ScFormulaCell
*> aCloned
;
802 aCloned
.reserve(nDataSize
);
803 ScAddress
aDestPos(mrDestCol
.GetCol(), nTopRow
, mrDestCol
.GetTab());
804 for (; it
!= itEnd
; ++it
, aDestPos
.IncRow())
806 const ScFormulaCell
& rOld
= **it
;
807 if (rOld
.GetDirty() && mrSrcCol
.GetDoc().GetAutoCalc())
808 const_cast<ScFormulaCell
&>(rOld
).Interpret();
810 aCloned
.push_back(new ScFormulaCell(rOld
, mrDestCol
.GetDoc(), aDestPos
));
813 // Group the cloned formula cells.
814 if (!aCloned
.empty())
815 sc::SharedFormulaUtil::groupFormulaCells(aCloned
.begin(), aCloned
.end());
817 sc::CellStoreType
& rDestCells
= mrDestCol
.GetCellStore();
818 maDestPos
.miCellPos
= rDestCells
.set(
819 maDestPos
.miCellPos
, nTopRow
, aCloned
.begin(), aCloned
.end());
821 // Merge adjacent formula cell groups (if applicable).
822 sc::CellStoreType::position_type aPos
=
823 rDestCells
.position(maDestPos
.miCellPos
, nTopRow
);
824 maDestPos
.miCellPos
= aPos
.first
;
825 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
826 size_t nLastRow
= nTopRow
+ nDataSize
;
827 if (nLastRow
< o3tl::make_unsigned(mrSrcDoc
.MaxRow()))
829 aPos
= rDestCells
.position(maDestPos
.miCellPos
, nLastRow
+1);
830 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
839 setDefaultAttrsToDest(nTopRow
, nDataSize
);
841 mrSrcCol
.DuplicateNotes(nTopRow
, nDataSize
, mrDestCol
, maDestPos
, false);
842 mrSrcCol
.DuplicateSparklines(nTopRow
, nDataSize
, mrDestCol
, maDestPos
);
846 class CopyTextAttrToClipHandler
848 sc::CellTextAttrStoreType
& mrDestAttrs
;
849 sc::CellTextAttrStoreType::iterator miPos
;
852 explicit CopyTextAttrToClipHandler( sc::CellTextAttrStoreType
& rAttrs
) :
853 mrDestAttrs(rAttrs
), miPos(mrDestAttrs
.begin()) {}
855 void operator() ( const sc::CellTextAttrStoreType::value_type
& aNode
, size_t nOffset
, size_t nDataSize
)
857 if (aNode
.type
!= sc::element_type_celltextattr
)
860 sc::celltextattr_block::const_iterator it
= sc::celltextattr_block::begin(*aNode
.data
);
861 std::advance(it
, nOffset
);
862 sc::celltextattr_block::const_iterator itEnd
= it
;
863 std::advance(itEnd
, nDataSize
);
865 size_t nPos
= aNode
.position
+ nOffset
;
866 miPos
= mrDestAttrs
.set(miPos
, nPos
, it
, itEnd
);
873 void ScColumn::CopyToClip(
874 sc::CopyToClipContext
& rCxt
, SCROW nRow1
, SCROW nRow2
, ScColumn
& rColumn
) const
876 if (!rCxt
.isCopyChartRanges()) // No need to copy attributes for chart ranges
877 pAttrArray
->CopyArea( nRow1
, nRow2
, 0, *rColumn
.pAttrArray
,
878 rCxt
.isKeepScenarioFlags() ? (ScMF::All
& ~ScMF::Scenario
) : ScMF::All
);
881 CopyToClipHandler
aFunc(GetDoc(), *this, rColumn
, rCxt
.getBlockPosition(rColumn
.nTab
, rColumn
.nCol
));
882 sc::ParseBlock(maCells
.begin(), maCells
, aFunc
, nRow1
, nRow2
);
885 if (!rCxt
.isCopyChartRanges()) // No need to copy attributes for chart ranges
887 CopyTextAttrToClipHandler
aFunc(rColumn
.maCellTextAttrs
);
888 sc::ParseBlock(maCellTextAttrs
.begin(), maCellTextAttrs
, aFunc
, nRow1
, nRow2
);
891 rColumn
.CellStorageModified();
894 void ScColumn::CopyStaticToDocument(
895 SCROW nRow1
, SCROW nRow2
, const SvNumberFormatterMergeMap
& rMap
, ScColumn
& rDestCol
)
900 sc::ColumnBlockPosition aDestPos
;
901 CopyCellTextAttrsToDocument(nRow1
, nRow2
, rDestCol
);
902 CopyCellNotesToDocument(nRow1
, nRow2
, rDestCol
);
904 // First, clear the destination column for the specified row range.
905 rDestCol
.maCells
.set_empty(nRow1
, nRow2
);
907 aDestPos
.miCellPos
= rDestCol
.maCells
.begin();
909 ScDocument
& rDocument
= GetDoc();
910 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nRow1
);
911 sc::CellStoreType::const_iterator it
= aPos
.first
;
912 size_t nOffset
= aPos
.second
;
913 size_t nDataSize
= 0;
914 size_t nCurRow
= nRow1
;
916 for (; it
!= maCells
.end() && nCurRow
<= o3tl::make_unsigned(nRow2
); ++it
, nOffset
= 0, nCurRow
+= nDataSize
)
918 bool bLastBlock
= false;
919 nDataSize
= it
->size
- nOffset
;
920 if (nCurRow
+ nDataSize
- 1 > o3tl::make_unsigned(nRow2
))
922 // Truncate the block to copy to clipboard.
923 nDataSize
= nRow2
- nCurRow
+ 1;
929 case sc::element_type_numeric
:
931 sc::numeric_block::const_iterator itData
= sc::numeric_block::begin(*it
->data
);
932 std::advance(itData
, nOffset
);
933 sc::numeric_block::const_iterator itDataEnd
= itData
;
934 std::advance(itDataEnd
, nDataSize
);
935 aDestPos
.miCellPos
= rDestCol
.maCells
.set(aDestPos
.miCellPos
, nCurRow
, itData
, itDataEnd
);
938 case sc::element_type_string
:
940 sc::string_block::const_iterator itData
= sc::string_block::begin(*it
->data
);
941 std::advance(itData
, nOffset
);
942 sc::string_block::const_iterator itDataEnd
= itData
;
943 std::advance(itDataEnd
, nDataSize
);
944 aDestPos
.miCellPos
= rDestCol
.maCells
.set(aDestPos
.miCellPos
, nCurRow
, itData
, itDataEnd
);
947 case sc::element_type_edittext
:
949 sc::edittext_block::const_iterator itData
= sc::edittext_block::begin(*it
->data
);
950 std::advance(itData
, nOffset
);
951 sc::edittext_block::const_iterator itDataEnd
= itData
;
952 std::advance(itDataEnd
, nDataSize
);
954 // Convert to simple strings.
955 std::vector
<svl::SharedString
> aConverted
;
956 aConverted
.reserve(nDataSize
);
957 for (; itData
!= itDataEnd
; ++itData
)
959 const EditTextObject
& rObj
= **itData
;
960 svl::SharedString aSS
= rDocument
.GetSharedStringPool().intern(ScEditUtil::GetString(rObj
, &rDocument
));
961 aConverted
.push_back(aSS
);
963 aDestPos
.miCellPos
= rDestCol
.maCells
.set(aDestPos
.miCellPos
, nCurRow
, aConverted
.begin(), aConverted
.end());
966 case sc::element_type_formula
:
968 sc::formula_block::const_iterator itData
= sc::formula_block::begin(*it
->data
);
969 std::advance(itData
, nOffset
);
970 sc::formula_block::const_iterator itDataEnd
= itData
;
971 std::advance(itDataEnd
, nDataSize
);
973 // Interpret and convert to raw values.
974 for (SCROW i
= 0; itData
!= itDataEnd
; ++itData
, ++i
)
976 SCROW nRow
= nCurRow
+ i
;
978 ScFormulaCell
& rFC
= **itData
;
979 if (rFC
.GetDirty() && rDocument
.GetAutoCalc())
982 if (rFC
.GetErrCode() != FormulaError::NONE
)
983 // Skip cells with error.
987 aDestPos
.miCellPos
= rDestCol
.maCells
.set(aDestPos
.miCellPos
, nRow
, rFC
.GetValue());
990 svl::SharedString aSS
= rFC
.GetString();
992 aDestPos
.miCellPos
= rDestCol
.maCells
.set(aDestPos
.miCellPos
, nRow
, aSS
);
1005 // Don't forget to copy the number formats over. Charts may reference them.
1006 for (SCROW nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
1008 sal_uInt32 nNumFmt
= GetNumberFormat(rDocument
.GetNonThreadedContext(), nRow
);
1009 SvNumberFormatterMergeMap::const_iterator itNum
= rMap
.find(nNumFmt
);
1010 if (itNum
!= rMap
.end())
1011 nNumFmt
= itNum
->second
;
1013 rDestCol
.SetNumberFormat(nRow
, nNumFmt
);
1016 rDestCol
.CellStorageModified();
1019 void ScColumn::CopyCellToDocument( SCROW nSrcRow
, SCROW nDestRow
, ScColumn
& rDestCol
)
1021 ScDocument
& rDocument
= GetDoc();
1022 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nSrcRow
);
1023 sc::CellStoreType::const_iterator it
= aPos
.first
;
1027 case sc::element_type_numeric
:
1028 rDestCol
.maCells
.set(nDestRow
, sc::numeric_block::at(*it
->data
, aPos
.second
));
1030 case sc::element_type_string
:
1031 rDestCol
.maCells
.set(nDestRow
, sc::string_block::at(*it
->data
, aPos
.second
));
1033 case sc::element_type_edittext
:
1035 EditTextObject
* p
= sc::edittext_block::at(*it
->data
, aPos
.second
);
1036 if (&rDocument
== &rDestCol
.GetDoc())
1037 rDestCol
.maCells
.set(nDestRow
, p
->Clone().release());
1039 rDestCol
.maCells
.set(nDestRow
, ScEditUtil::Clone(*p
, rDestCol
.GetDoc()).release());
1042 case sc::element_type_formula
:
1044 ScFormulaCell
* p
= sc::formula_block::at(*it
->data
, aPos
.second
);
1045 if (p
->GetDirty() && rDocument
.GetAutoCalc())
1048 ScAddress aDestPos
= p
->aPos
;
1049 aDestPos
.SetRow(nDestRow
);
1050 ScFormulaCell
* pNew
= new ScFormulaCell(*p
, rDestCol
.GetDoc(), aDestPos
);
1051 rDestCol
.SetFormulaCell(nDestRow
, pNew
);
1054 case sc::element_type_empty
:
1057 rDestCol
.maCells
.set_empty(nDestRow
, nDestRow
);
1063 rDestCol
.maCellTextAttrs
.set(nDestRow
, maCellTextAttrs
.get
<sc::CellTextAttr
>(nSrcRow
));
1064 ScPostIt
* pNote
= maCellNotes
.get
<ScPostIt
*>(nSrcRow
);
1067 pNote
= pNote
->Clone(ScAddress(nCol
, nSrcRow
, nTab
),
1069 ScAddress(rDestCol
.nCol
, nDestRow
, rDestCol
.nTab
),
1071 rDestCol
.maCellNotes
.set(nDestRow
, pNote
);
1072 pNote
->UpdateCaptionPos(ScAddress(rDestCol
.nCol
, nDestRow
, rDestCol
.nTab
));
1075 rDestCol
.maCellNotes
.set_empty(nDestRow
, nDestRow
);
1079 rDestCol
.maCellTextAttrs
.set_empty(nDestRow
, nDestRow
);
1080 rDestCol
.maCellNotes
.set_empty(nDestRow
, nDestRow
);
1083 rDestCol
.CellStorageModified();
1088 bool canCopyValue(const ScDocument
& rDoc
, const ScAddress
& rPos
, InsertDeleteFlags nFlags
)
1090 sal_uInt32 nNumIndex
= rDoc
.GetAttr(rPos
, ATTR_VALUE_FORMAT
)->GetValue();
1091 SvNumFormatType nType
= rDoc
.GetFormatTable()->GetType(nNumIndex
);
1092 if ((nType
== SvNumFormatType::DATE
) || (nType
== SvNumFormatType::TIME
) || (nType
== SvNumFormatType::DATETIME
))
1093 return ((nFlags
& InsertDeleteFlags::DATETIME
) != InsertDeleteFlags::NONE
);
1095 return (nFlags
& InsertDeleteFlags::VALUE
) != InsertDeleteFlags::NONE
;
1098 class CopyAsLinkHandler
1100 const ScColumn
& mrSrcCol
;
1101 ScColumn
& mrDestCol
;
1102 sc::ColumnBlockPosition maDestPos
;
1103 sc::ColumnBlockPosition
* mpDestPos
;
1104 InsertDeleteFlags mnCopyFlags
;
1106 sc::StartListeningType meListenType
;
1108 void setDefaultAttrToDest(size_t nRow
)
1110 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set(
1111 maDestPos
.miCellTextAttrPos
, nRow
, sc::CellTextAttr());
1114 void setDefaultAttrsToDest(size_t nRow
, size_t nSize
)
1116 std::vector
<sc::CellTextAttr
> aAttrs(nSize
); // default values
1117 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set(
1118 maDestPos
.miCellTextAttrPos
, nRow
, aAttrs
.begin(), aAttrs
.end());
1121 ScFormulaCell
* createRefCell(size_t nRow
)
1123 ScSingleRefData aRef
;
1124 aRef
.InitAddress(ScAddress(mrSrcCol
.GetCol(), nRow
, mrSrcCol
.GetTab())); // Absolute reference.
1125 aRef
.SetFlag3D(true);
1127 ScTokenArray
aArr(mrDestCol
.GetDoc());
1128 aArr
.AddSingleReference(aRef
);
1129 return new ScFormulaCell(mrDestCol
.GetDoc(), ScAddress(mrDestCol
.GetCol(), nRow
, mrDestCol
.GetTab()), aArr
);
1132 void createRefBlock(const sc::CellStoreType::value_type
& aNode
, size_t nOffset
, size_t nDataSize
)
1134 size_t nTopRow
= aNode
.position
+ nOffset
;
1136 for (size_t i
= 0; i
< nDataSize
; ++i
)
1138 SCROW nRow
= nTopRow
+ i
;
1139 mrDestCol
.SetFormulaCell(maDestPos
, nRow
, createRefCell(nRow
), meListenType
);
1142 setDefaultAttrsToDest(nTopRow
, nDataSize
);
1146 CopyAsLinkHandler(const ScColumn
& rSrcCol
, ScColumn
& rDestCol
, sc::ColumnBlockPosition
* pDestPos
, InsertDeleteFlags nCopyFlags
) :
1148 mrDestCol(rDestCol
),
1149 mpDestPos(pDestPos
),
1150 mnCopyFlags(nCopyFlags
),
1151 meListenType(sc::SingleCellListening
)
1154 maDestPos
= *mpDestPos
;
1157 ~CopyAsLinkHandler()
1161 // Similar to CopyByCloneHandler, don't copy a singular iterator.
1163 sc::ColumnBlockPosition aTempBlock
;
1164 mrDestCol
.InitBlockPosition(aTempBlock
);
1165 maDestPos
.miBroadcasterPos
= aTempBlock
.miBroadcasterPos
;
1168 *mpDestPos
= maDestPos
;
1172 void setStartListening( bool b
)
1174 meListenType
= b
? sc::SingleCellListening
: sc::NoListening
;
1177 void operator() (const sc::CellStoreType::value_type
& aNode
, size_t nOffset
, size_t nDataSize
)
1179 size_t nRow
= aNode
.position
+ nOffset
;
1181 if (mnCopyFlags
& (InsertDeleteFlags::NOTE
|InsertDeleteFlags::ADDNOTES
))
1183 bool bCloneCaption
= (mnCopyFlags
& InsertDeleteFlags::NOCAPTIONS
) == InsertDeleteFlags::NONE
;
1184 mrSrcCol
.DuplicateNotes(nRow
, nDataSize
, mrDestCol
, maDestPos
, bCloneCaption
);
1189 case sc::element_type_numeric
:
1191 if ((mnCopyFlags
& (InsertDeleteFlags::DATETIME
|InsertDeleteFlags::VALUE
)) == InsertDeleteFlags::NONE
)
1194 sc::numeric_block::const_iterator it
= sc::numeric_block::begin(*aNode
.data
);
1195 std::advance(it
, nOffset
);
1196 sc::numeric_block::const_iterator itEnd
= it
;
1197 std::advance(itEnd
, nDataSize
);
1199 ScAddress
aSrcPos(mrSrcCol
.GetCol(), nRow
, mrSrcCol
.GetTab());
1200 for (; it
!= itEnd
; ++it
, aSrcPos
.IncRow(), ++nRow
)
1202 if (!canCopyValue(mrSrcCol
.GetDoc(), aSrcPos
, mnCopyFlags
))
1205 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nRow
, createRefCell(nRow
));
1206 setDefaultAttrToDest(nRow
);
1210 case sc::element_type_string
:
1211 case sc::element_type_edittext
:
1213 if (!(mnCopyFlags
& InsertDeleteFlags::STRING
))
1216 createRefBlock(aNode
, nOffset
, nDataSize
);
1219 case sc::element_type_formula
:
1221 if (!(mnCopyFlags
& InsertDeleteFlags::FORMULA
))
1224 createRefBlock(aNode
, nOffset
, nDataSize
);
1233 class CopyByCloneHandler
1235 const ScColumn
& mrSrcCol
;
1236 ScColumn
& mrDestCol
;
1237 sc::ColumnBlockPosition maDestPos
;
1238 sc::ColumnBlockPosition
* mpDestPos
;
1239 svl::SharedStringPool
* mpSharedStringPool
;
1240 InsertDeleteFlags mnCopyFlags
;
1242 sc::StartListeningType meListenType
;
1243 ScCloneFlags mnFormulaCellCloneFlags
;
1245 void setDefaultAttrToDest(size_t nRow
)
1247 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set(
1248 maDestPos
.miCellTextAttrPos
, nRow
, sc::CellTextAttr());
1251 void setDefaultAttrsToDest(size_t nRow
, size_t nSize
)
1253 std::vector
<sc::CellTextAttr
> aAttrs(nSize
); // default values
1254 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set(
1255 maDestPos
.miCellTextAttrPos
, nRow
, aAttrs
.begin(), aAttrs
.end());
1258 void cloneFormulaCell(size_t nRow
, ScFormulaCell
& rSrcCell
)
1260 ScAddress
aDestPos(mrDestCol
.GetCol(), nRow
, mrDestCol
.GetTab());
1262 bool bCloneValue
= (mnCopyFlags
& InsertDeleteFlags::VALUE
) != InsertDeleteFlags::NONE
;
1263 bool bCloneDateTime
= (mnCopyFlags
& InsertDeleteFlags::DATETIME
) != InsertDeleteFlags::NONE
;
1264 bool bCloneString
= (mnCopyFlags
& InsertDeleteFlags::STRING
) != InsertDeleteFlags::NONE
;
1265 bool bCloneSpecialBoolean
= (mnCopyFlags
& InsertDeleteFlags::SPECIAL_BOOLEAN
) != InsertDeleteFlags::NONE
;
1266 bool bCloneFormula
= (mnCopyFlags
& InsertDeleteFlags::FORMULA
) != InsertDeleteFlags::NONE
;
1268 bool bForceFormula
= false;
1270 if (bCloneSpecialBoolean
)
1272 // See if the formula consists of =TRUE() or =FALSE().
1273 const ScTokenArray
* pCode
= rSrcCell
.GetCode();
1274 if (pCode
&& pCode
->GetLen() == 1)
1276 const formula::FormulaToken
* p
= pCode
->FirstToken();
1277 if (p
->GetOpCode() == ocTrue
|| p
->GetOpCode() == ocFalse
)
1278 // This is a boolean formula.
1279 bForceFormula
= true;
1283 if (bForceFormula
|| bCloneFormula
)
1285 // Clone as formula cell.
1286 ScFormulaCell
* pCell
= new ScFormulaCell(rSrcCell
, mrDestCol
.GetDoc(), aDestPos
, mnFormulaCellCloneFlags
);
1287 pCell
->SetDirtyVar();
1288 mrDestCol
.SetFormulaCell(maDestPos
, nRow
, pCell
, meListenType
, rSrcCell
.NeedsNumberFormat());
1289 setDefaultAttrToDest(nRow
);
1293 if (mrDestCol
.GetDoc().IsUndo())
1298 FormulaError nErr
= rSrcCell
.GetErrCode();
1299 if (nErr
!= FormulaError::NONE
)
1301 // error codes are cloned with values
1302 ScFormulaCell
* pErrCell
= new ScFormulaCell(mrDestCol
.GetDoc(), aDestPos
);
1303 pErrCell
->SetErrCode(nErr
);
1304 mrDestCol
.SetFormulaCell(maDestPos
, nRow
, pErrCell
, meListenType
);
1305 setDefaultAttrToDest(nRow
);
1310 if (bCloneValue
|| bCloneDateTime
)
1312 if (rSrcCell
.IsValue())
1314 if (canCopyValue(mrSrcCol
.GetDoc(), ScAddress(mrSrcCol
.GetCol(), nRow
, mrSrcCol
.GetTab()), mnCopyFlags
))
1316 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(
1317 maDestPos
.miCellPos
, nRow
, rSrcCell
.GetValue());
1318 setDefaultAttrToDest(nRow
);
1328 svl::SharedString aStr
= rSrcCell
.GetString();
1330 // Don't create empty string cells.
1333 if (rSrcCell
.IsMultilineResult())
1335 // Clone as an edit text object.
1336 EditEngine
& rEngine
= mrDestCol
.GetDoc().GetEditEngine();
1337 rEngine
.SetText(aStr
.getString());
1338 maDestPos
.miCellPos
=
1339 mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nRow
, rEngine
.CreateTextObject().release());
1343 maDestPos
.miCellPos
=
1344 mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nRow
, aStr
);
1347 setDefaultAttrToDest(nRow
);
1351 CopyByCloneHandler(const ScColumn
& rSrcCol
, ScColumn
& rDestCol
, sc::ColumnBlockPosition
* pDestPos
,
1352 InsertDeleteFlags nCopyFlags
, svl::SharedStringPool
* pSharedStringPool
, bool bGlobalNamesToLocal
) :
1354 mrDestCol(rDestCol
),
1355 mpDestPos(pDestPos
),
1356 mpSharedStringPool(pSharedStringPool
),
1357 mnCopyFlags(nCopyFlags
),
1358 meListenType(sc::SingleCellListening
),
1359 mnFormulaCellCloneFlags(bGlobalNamesToLocal
? ScCloneFlags::NamesToLocal
: ScCloneFlags::Default
)
1362 maDestPos
= *mpDestPos
;
1365 ~CopyByCloneHandler()
1370 // If broadcasters were setup in the same column,
1371 // maDestPos.miBroadcasterPos doesn't match
1372 // mrDestCol.maBroadcasters because it is never passed anywhere.
1373 // Assign a corresponding iterator before copying all over.
1374 // Otherwise this may result in wrongly copying a singular
1378 /* XXX Using a temporary ColumnBlockPosition just for
1379 * initializing from ScColumn::maBroadcasters.begin() is ugly,
1380 * on the other hand we don't want to expose
1381 * ScColumn::maBroadcasters to the outer world and have a
1383 sc::ColumnBlockPosition aTempBlock
;
1384 mrDestCol
.InitBlockPosition(aTempBlock
);
1385 maDestPos
.miBroadcasterPos
= aTempBlock
.miBroadcasterPos
;
1388 *mpDestPos
= maDestPos
;
1391 void setStartListening( bool b
)
1393 meListenType
= b
? sc::SingleCellListening
: sc::NoListening
;
1396 void operator() (const sc::CellStoreType::value_type
& aNode
, size_t nOffset
, size_t nDataSize
)
1398 size_t nRow
= aNode
.position
+ nOffset
;
1400 if (mnCopyFlags
& (InsertDeleteFlags::NOTE
|InsertDeleteFlags::ADDNOTES
))
1402 bool bCloneCaption
= (mnCopyFlags
& InsertDeleteFlags::NOCAPTIONS
) == InsertDeleteFlags::NONE
;
1403 mrSrcCol
.DuplicateNotes(nRow
, nDataSize
, mrDestCol
, maDestPos
, bCloneCaption
);
1408 case sc::element_type_numeric
:
1410 if ((mnCopyFlags
& (InsertDeleteFlags::DATETIME
|InsertDeleteFlags::VALUE
)) == InsertDeleteFlags::NONE
)
1413 sc::numeric_block::const_iterator it
= sc::numeric_block::begin(*aNode
.data
);
1414 std::advance(it
, nOffset
);
1415 sc::numeric_block::const_iterator itEnd
= it
;
1416 std::advance(itEnd
, nDataSize
);
1418 ScAddress
aSrcPos(mrSrcCol
.GetCol(), nRow
, mrSrcCol
.GetTab());
1419 for (; it
!= itEnd
; ++it
, aSrcPos
.IncRow(), ++nRow
)
1421 if (!canCopyValue(mrSrcCol
.GetDoc(), aSrcPos
, mnCopyFlags
))
1424 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nRow
, *it
);
1425 setDefaultAttrToDest(nRow
);
1429 case sc::element_type_string
:
1431 if (!(mnCopyFlags
& InsertDeleteFlags::STRING
))
1434 sc::string_block::const_iterator it
= sc::string_block::begin(*aNode
.data
);
1435 std::advance(it
, nOffset
);
1436 sc::string_block::const_iterator itEnd
= it
;
1437 std::advance(itEnd
, nDataSize
);
1439 for (; it
!= itEnd
; ++it
, ++nRow
)
1441 const svl::SharedString
& rStr
= *it
;
1444 // String cell with empty value is used to special-case cell value removal.
1445 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set_empty(
1446 maDestPos
.miCellPos
, nRow
, nRow
);
1447 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set_empty(
1448 maDestPos
.miCellTextAttrPos
, nRow
, nRow
);
1452 if (mpSharedStringPool
)
1454 // Re-intern the string if source is a different document.
1455 svl::SharedString aInterned
= mpSharedStringPool
->intern( rStr
.getString());
1456 maDestPos
.miCellPos
=
1457 mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nRow
, aInterned
);
1461 maDestPos
.miCellPos
=
1462 mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nRow
, rStr
);
1464 setDefaultAttrToDest(nRow
);
1469 case sc::element_type_edittext
:
1471 if (!(mnCopyFlags
& InsertDeleteFlags::STRING
))
1474 sc::edittext_block::const_iterator it
= sc::edittext_block::begin(*aNode
.data
);
1475 std::advance(it
, nOffset
);
1476 sc::edittext_block::const_iterator itEnd
= it
;
1477 std::advance(itEnd
, nDataSize
);
1479 std::vector
<EditTextObject
*> aCloned
;
1480 aCloned
.reserve(nDataSize
);
1481 for (; it
!= itEnd
; ++it
)
1482 aCloned
.push_back(ScEditUtil::Clone(**it
, mrDestCol
.GetDoc()).release());
1484 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(
1485 maDestPos
.miCellPos
, nRow
, aCloned
.begin(), aCloned
.end());
1487 setDefaultAttrsToDest(nRow
, nDataSize
);
1490 case sc::element_type_formula
:
1492 sc::formula_block::const_iterator it
= sc::formula_block::begin(*aNode
.data
);
1493 std::advance(it
, nOffset
);
1494 sc::formula_block::const_iterator itEnd
= it
;
1495 std::advance(itEnd
, nDataSize
);
1497 sc::DelayStartListeningFormulaCells
startDelay(mrDestCol
); // disabled
1498 if(nDataSize
> 1024 && (mnCopyFlags
& InsertDeleteFlags::FORMULA
) != InsertDeleteFlags::NONE
)
1500 // If the column to be replaced contains a long formula group (tdf#102364), there can
1501 // be so many listeners in a single vector that the quadratic cost of repeatedly removing
1502 // the first element becomes very high. Optimize this by removing them in one go.
1503 sc::EndListeningContext
context(mrDestCol
.GetDoc());
1504 mrDestCol
.EndListeningFormulaCells( context
, nRow
, nRow
+ nDataSize
- 1, nullptr, nullptr );
1505 // There can be a similar problem with starting to listen to cells repeatedly (tdf#133302).
1510 for (; it
!= itEnd
; ++it
, ++nRow
)
1511 cloneFormulaCell(nRow
, **it
);
1522 void ScColumn::CopyToColumn(
1523 sc::CopyToDocContext
& rCxt
,
1524 SCROW nRow1
, SCROW nRow2
, InsertDeleteFlags nFlags
, bool bMarked
, ScColumn
& rColumn
,
1525 const ScMarkData
* pMarkData
, bool bAsLink
, bool bGlobalNamesToLocal
) const
1530 if (pMarkData
&& pMarkData
->IsMultiMarked())
1532 ScMultiSelIter
aIter( pMarkData
->GetMultiSelData(), nCol
);
1534 while ( aIter
.Next( nStart
, nEnd
) && nStart
<= nRow2
)
1536 if ( nEnd
>= nRow1
)
1537 CopyToColumn(rCxt
, std::max(nRow1
,nStart
), std::min(nRow2
,nEnd
),
1538 nFlags
, false, rColumn
, pMarkData
, bAsLink
);
1543 OSL_FAIL("CopyToColumn: bMarked, but no mark");
1548 if ( (nFlags
& InsertDeleteFlags::ATTRIB
) != InsertDeleteFlags::NONE
)
1550 if ( (nFlags
& InsertDeleteFlags::STYLES
) != InsertDeleteFlags::STYLES
)
1551 { // keep the StyleSheets in the target document
1552 // e.g. DIF and RTF Clipboard-Import
1553 for ( SCROW nRow
= nRow1
; nRow
<= nRow2
; nRow
++ )
1555 const ScStyleSheet
* pStyle(rColumn
.pAttrArray
->GetPattern( nRow
)->GetStyleSheet());
1556 ScPatternAttr
* pNewPattern(new ScPatternAttr(*pAttrArray
->GetPattern(nRow
)));
1557 pNewPattern
->SetStyleSheet(const_cast<ScStyleSheet
*>(pStyle
));
1558 rColumn
.pAttrArray
->SetPattern(nRow
, CellAttributeHolder(pNewPattern
, true));
1562 pAttrArray
->CopyArea( nRow1
, nRow2
, 0, *rColumn
.pAttrArray
);
1565 if ((nFlags
& InsertDeleteFlags::CONTENTS
) == InsertDeleteFlags::NONE
)
1570 CopyAsLinkHandler
aFunc(*this, rColumn
, rCxt
.getBlockPosition(rColumn
.nTab
, rColumn
.nCol
), nFlags
);
1571 aFunc
.setStartListening(rCxt
.isStartListening());
1572 sc::ParseBlock(maCells
.begin(), maCells
, aFunc
, nRow1
, nRow2
);
1576 // Compare the ScDocumentPool* to determine if we are copying
1577 // within the same document. If not, re-intern shared strings.
1578 svl::SharedStringPool
* pSharedStringPool
=
1579 (GetDoc().GetPool() != rColumn
.GetDoc().GetPool()) ?
1580 &rColumn
.GetDoc().GetSharedStringPool() : nullptr;
1581 CopyByCloneHandler
aFunc(*this, rColumn
, rCxt
.getBlockPosition(rColumn
.nTab
, rColumn
.nCol
), nFlags
,
1582 pSharedStringPool
, bGlobalNamesToLocal
);
1583 aFunc
.setStartListening(rCxt
.isStartListening());
1584 sc::ParseBlock(maCells
.begin(), maCells
, aFunc
, nRow1
, nRow2
);
1587 rColumn
.CellStorageModified();
1590 void ScColumn::UndoToColumn(
1591 sc::CopyToDocContext
& rCxt
, SCROW nRow1
, SCROW nRow2
, InsertDeleteFlags nFlags
, bool bMarked
,
1592 ScColumn
& rColumn
) const
1595 CopyToColumn(rCxt
, 0, nRow1
-1, InsertDeleteFlags::FORMULA
, false, rColumn
);
1597 CopyToColumn(rCxt
, nRow1
, nRow2
, nFlags
, bMarked
, rColumn
); //TODO: bMarked ????
1599 if (nRow2
< GetDoc().MaxRow())
1600 CopyToColumn(rCxt
, nRow2
+1, GetDoc().MaxRow(), InsertDeleteFlags::FORMULA
, false, rColumn
);
1603 void ScColumn::CopyUpdated( const ScColumn
* pPosCol
, ScColumn
& rDestCol
) const
1605 // Copy cells from this column to the destination column only for those
1606 // rows that are present in the position column (pPosCol).
1608 // First, mark all the non-empty cell ranges from the position column.
1609 sc::SingleColumnSpanSet
aRangeSet(GetDoc().GetSheetLimits());
1611 aRangeSet
.scan(*pPosCol
);
1613 // Now, copy cells from this column to the destination column for those
1614 // marked row ranges.
1615 sc::SingleColumnSpanSet::SpansType aRanges
;
1616 aRangeSet
.getSpans(aRanges
);
1618 CopyToClipHandler
aFunc(GetDoc(), *this, rDestCol
, nullptr);
1619 sc::CellStoreType::const_iterator itPos
= maCells
.begin();
1620 for (const auto& rRange
: aRanges
)
1621 itPos
= sc::ParseBlock(itPos
, maCells
, aFunc
, rRange
.mnRow1
, rRange
.mnRow2
);
1623 rDestCol
.CellStorageModified();
1626 void ScColumn::CopyScenarioFrom( const ScColumn
& rSrcCol
)
1628 // This is the scenario table, the data is copied into it
1629 ScDocument
& rDocument
= GetDoc();
1630 ScAttrIterator
aAttrIter( pAttrArray
.get(), 0, GetDoc().MaxRow(), &rDocument
.getCellAttributeHelper().getDefaultCellAttribute() );
1631 SCROW nStart
= -1, nEnd
= -1;
1632 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1635 if ( pPattern
->GetItem( ATTR_MERGE_FLAG
).IsScenario() )
1637 DeleteArea( nStart
, nEnd
, InsertDeleteFlags::CONTENTS
);
1638 sc::CopyToDocContext
aCxt(rDocument
);
1640 CopyToColumn(aCxt
, nStart
, nEnd
, InsertDeleteFlags::CONTENTS
, false, *this);
1642 // UpdateUsed not needed, already done in TestCopyScenario (obsolete comment ?)
1644 sc::RefUpdateContext
aRefCxt(rDocument
);
1645 aRefCxt
.meMode
= URM_COPY
;
1646 aRefCxt
.maRange
= ScRange(nCol
, nStart
, nTab
, nCol
, nEnd
, nTab
);
1647 aRefCxt
.mnTabDelta
= nTab
- rSrcCol
.nTab
;
1648 UpdateReferenceOnCopy(aRefCxt
);
1651 pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1655 void ScColumn::CopyScenarioTo( ScColumn
& rDestCol
) const
1657 // This is the scenario table, the data is copied to the other
1658 ScDocument
& rDocument
= GetDoc();
1659 ScAttrIterator
aAttrIter( pAttrArray
.get(), 0, GetDoc().MaxRow(), &rDocument
.getCellAttributeHelper().getDefaultCellAttribute() );
1660 SCROW nStart
= -1, nEnd
= -1;
1661 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1664 if ( pPattern
->GetItem( ATTR_MERGE_FLAG
).IsScenario() )
1666 rDestCol
.DeleteArea( nStart
, nEnd
, InsertDeleteFlags::CONTENTS
);
1667 sc::CopyToDocContext
aCxt(rDestCol
.GetDoc());
1668 CopyToColumn(aCxt
, nStart
, nEnd
, InsertDeleteFlags::CONTENTS
, false, rDestCol
);
1670 sc::RefUpdateContext
aRefCxt(rDocument
);
1671 aRefCxt
.meMode
= URM_COPY
;
1672 aRefCxt
.maRange
= ScRange(rDestCol
.nCol
, nStart
, rDestCol
.nTab
, rDestCol
.nCol
, nEnd
, rDestCol
.nTab
);
1673 aRefCxt
.mnTabDelta
= rDestCol
.nTab
- nTab
;
1674 rDestCol
.UpdateReferenceOnCopy(aRefCxt
);
1675 rDestCol
.UpdateCompile();
1677 pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1681 bool ScColumn::TestCopyScenarioTo( const ScColumn
& rDestCol
) const
1684 ScAttrIterator
aAttrIter( pAttrArray
.get(), 0, GetDoc().MaxRow(), &GetDoc().getCellAttributeHelper().getDefaultCellAttribute() );
1685 SCROW nStart
= 0, nEnd
= 0;
1686 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1687 while (pPattern
&& bOk
)
1689 if ( pPattern
->GetItem( ATTR_MERGE_FLAG
).IsScenario() )
1690 if ( rDestCol
.pAttrArray
->HasAttrib( nStart
, nEnd
, HasAttrFlags::Protected
) )
1693 pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1698 void ScColumn::MarkScenarioIn( ScMarkData
& rDestMark
) const
1700 ScRange
aRange( nCol
, 0, nTab
);
1702 ScAttrIterator
aAttrIter( pAttrArray
.get(), 0, GetDoc().MaxRow(), &GetDoc().getCellAttributeHelper().getDefaultCellAttribute() );
1703 SCROW nStart
= -1, nEnd
= -1;
1704 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1707 if ( pPattern
->GetItem( ATTR_MERGE_FLAG
).IsScenario() )
1709 aRange
.aStart
.SetRow( nStart
);
1710 aRange
.aEnd
.SetRow( nEnd
);
1711 rDestMark
.SetMultiMarkArea( aRange
);
1714 pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1720 void resetColumnPosition(sc::CellStoreType
& rCells
, SCCOL nCol
)
1722 for (auto& rCellItem
: rCells
)
1724 if (rCellItem
.type
!= sc::element_type_formula
)
1727 sc::formula_block::iterator itCell
= sc::formula_block::begin(*rCellItem
.data
);
1728 sc::formula_block::iterator itCellEnd
= sc::formula_block::end(*rCellItem
.data
);
1729 for (; itCell
!= itCellEnd
; ++itCell
)
1731 ScFormulaCell
& rCell
= **itCell
;
1732 rCell
.aPos
.SetCol(nCol
);
1737 class NoteCaptionUpdater
1739 const ScDocument
& m_rDocument
;
1740 const ScAddress m_aAddress
; // 'incomplete' address consisting of tab, column
1741 bool m_bUpdateCaptionPos
; // false if we want to skip updating the caption pos, only useful in kit mode
1742 bool m_bAddressChanged
; // false if the cell anchor address is unchanged
1744 NoteCaptionUpdater(const ScDocument
& rDocument
, const ScAddress
& rPos
, bool bUpdateCaptionPos
, bool bAddressChanged
)
1745 : m_rDocument(rDocument
)
1747 , m_bUpdateCaptionPos(bUpdateCaptionPos
)
1748 , m_bAddressChanged(bAddressChanged
)
1752 void operator() ( size_t nRow
, ScPostIt
* p
)
1754 // Create a 'complete' address object
1755 ScAddress
aAddr(m_aAddress
);
1758 if (m_bUpdateCaptionPos
)
1759 p
->UpdateCaptionPos(aAddr
);
1761 // Notify our LOK clients
1762 if (m_bAddressChanged
)
1763 ScDocShell::LOKCommentNotify(LOKCommentNotificationType::Modify
, m_rDocument
, aAddr
, p
);
1769 void ScColumn::UpdateNoteCaptions( SCROW nRow1
, SCROW nRow2
, bool bAddressChanged
)
1771 ScAddress
aAddr(nCol
, 0, nTab
);
1772 NoteCaptionUpdater
aFunc(GetDoc(), aAddr
, true, bAddressChanged
);
1773 sc::ProcessNote(maCellNotes
.begin(), maCellNotes
, nRow1
, nRow2
, aFunc
);
1776 void ScColumn::CommentNotifyAddressChange( SCROW nRow1
, SCROW nRow2
)
1778 ScAddress
aAddr(nCol
, 0, nTab
);
1779 NoteCaptionUpdater
aFunc(GetDoc(), aAddr
, false, true);
1780 sc::ProcessNote(maCellNotes
.begin(), maCellNotes
, nRow1
, nRow2
, aFunc
);
1783 void ScColumn::UpdateDrawObjects(std::vector
<std::vector
<SdrObject
*>>& pObjects
, SCROW nRowStart
, SCROW nRowEnd
)
1785 assert(static_cast<int>(pObjects
.size()) >= nRowEnd
- nRowStart
+ 1);
1788 for (SCROW nCurrentRow
= nRowStart
; nCurrentRow
<= nRowEnd
; nCurrentRow
++, nObj
++)
1790 if (pObjects
[nObj
].empty())
1791 continue; // No draw objects in this row
1793 UpdateDrawObjectsForRow(pObjects
[nObj
], nCol
, nCurrentRow
);
1797 void ScColumn::UpdateDrawObjectsForRow( std::vector
<SdrObject
*>& pObjects
, SCCOL nTargetCol
, SCROW nTargetRow
)
1799 for (auto &pObject
: pObjects
)
1801 ScAddress
aNewAddress(nTargetCol
, nTargetRow
, nTab
);
1803 // Update draw object according to new anchor
1804 ScDrawLayer
* pDrawLayer
= GetDoc().GetDrawLayer();
1806 pDrawLayer
->MoveObject(pObject
, aNewAddress
);
1810 bool ScColumn::IsDrawObjectsEmptyBlock(SCROW nStartRow
, SCROW nEndRow
) const
1812 ScDrawLayer
* pDrawLayer
= GetDoc().GetDrawLayer();
1816 ScRange
aRange(nCol
, nStartRow
, nTab
, nCol
, nEndRow
, nTab
);
1817 return !pDrawLayer
->HasObjectsAnchoredInRange(aRange
);
1820 void ScColumn::SwapCol(ScColumn
& rCol
)
1822 maBroadcasters
.swap(rCol
.maBroadcasters
);
1823 maCells
.swap(rCol
.maCells
);
1824 maCellTextAttrs
.swap(rCol
.maCellTextAttrs
);
1825 maCellNotes
.swap(rCol
.maCellNotes
);
1826 maSparklines
.swap(rCol
.maSparklines
);
1828 // Swap all CellStoreEvent mdds event_func related.
1829 maCells
.event_handler().swap(rCol
.maCells
.event_handler());
1830 maCellNotes
.event_handler().swap(rCol
.maCellNotes
.event_handler());
1831 std::swap( mnBlkCountFormula
, rCol
.mnBlkCountFormula
);
1832 std::swap(mnBlkCountCellNotes
, rCol
.mnBlkCountCellNotes
);
1834 // notes update caption
1835 UpdateNoteCaptions(0, GetDoc().MaxRow());
1836 rCol
.UpdateNoteCaptions(0, GetDoc().MaxRow());
1838 std::swap(pAttrArray
, rCol
.pAttrArray
);
1840 // AttrArray needs to have the right column number
1841 pAttrArray
->SetCol(nCol
);
1842 rCol
.pAttrArray
->SetCol(rCol
.nCol
);
1844 // Reset column positions in formula cells.
1845 resetColumnPosition(maCells
, nCol
);
1846 resetColumnPosition(rCol
.maCells
, rCol
.nCol
);
1848 CellStorageModified();
1849 rCol
.CellStorageModified();
1852 void ScColumn::MoveTo(SCROW nStartRow
, SCROW nEndRow
, ScColumn
& rCol
)
1854 pAttrArray
->MoveTo(nStartRow
, nEndRow
, *rCol
.pAttrArray
);
1856 // Mark the non-empty cells within the specified range, for later broadcasting.
1857 sc::SingleColumnSpanSet
aNonEmpties(GetDoc().GetSheetLimits());
1858 aNonEmpties
.scan(*this, nStartRow
, nEndRow
);
1859 sc::SingleColumnSpanSet::SpansType aRanges
;
1860 aNonEmpties
.getSpans(aRanges
);
1862 // Split the formula grouping at the top and bottom boundaries.
1863 sc::CellStoreType::position_type aPos
= maCells
.position(nStartRow
);
1864 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos
, nullptr);
1865 if (GetDoc().ValidRow(nEndRow
+1))
1867 aPos
= maCells
.position(aPos
.first
, nEndRow
+1);
1868 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos
, nullptr);
1871 // Do the same with the destination column.
1872 aPos
= rCol
.maCells
.position(nStartRow
);
1873 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos
, nullptr);
1874 if (GetDoc().ValidRow(nEndRow
+1))
1876 aPos
= rCol
.maCells
.position(aPos
.first
, nEndRow
+1);
1877 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos
, nullptr);
1880 // Move the broadcasters to the destination column.
1881 maBroadcasters
.transfer(nStartRow
, nEndRow
, rCol
.maBroadcasters
, nStartRow
);
1882 maCells
.transfer(nStartRow
, nEndRow
, rCol
.maCells
, nStartRow
);
1883 maCellTextAttrs
.transfer(nStartRow
, nEndRow
, rCol
.maCellTextAttrs
, nStartRow
);
1885 // move the notes to the destination column
1886 maCellNotes
.transfer(nStartRow
, nEndRow
, rCol
.maCellNotes
, nStartRow
);
1887 UpdateNoteCaptions(0, GetDoc().MaxRow());
1889 // Re-group transferred formula cells.
1890 aPos
= rCol
.maCells
.position(nStartRow
);
1891 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
1892 if (GetDoc().ValidRow(nEndRow
+1))
1894 aPos
= rCol
.maCells
.position(aPos
.first
, nEndRow
+1);
1895 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
1898 CellStorageModified();
1899 rCol
.CellStorageModified();
1901 // Broadcast on moved ranges. Area-broadcast only.
1902 ScDocument
& rDocument
= GetDoc();
1903 ScHint
aHint(SfxHintId::ScDataChanged
, ScAddress(nCol
, 0, nTab
));
1904 for (const auto& rRange
: aRanges
)
1906 for (SCROW nRow
= rRange
.mnRow1
; nRow
<= rRange
.mnRow2
; ++nRow
)
1908 aHint
.SetAddressRow(nRow
);
1909 rDocument
.AreaBroadcast(aHint
);
1916 class SharedTopFormulaCellPicker
1919 SharedTopFormulaCellPicker() = default;
1920 SharedTopFormulaCellPicker(SharedTopFormulaCellPicker
const &) = default;
1921 SharedTopFormulaCellPicker(SharedTopFormulaCellPicker
&&) = default;
1922 SharedTopFormulaCellPicker
& operator =(SharedTopFormulaCellPicker
const &) = default;
1923 SharedTopFormulaCellPicker
& operator =(SharedTopFormulaCellPicker
&&) = default;
1925 virtual ~SharedTopFormulaCellPicker() {}
1927 void operator() ( sc::CellStoreType::value_type
& node
)
1929 if (node
.type
!= sc::element_type_formula
)
1932 size_t nTopRow
= node
.position
;
1934 sc::formula_block::iterator itBeg
= sc::formula_block::begin(*node
.data
);
1935 sc::formula_block::iterator itEnd
= sc::formula_block::end(*node
.data
);
1937 // Only pick shared formula cells that are the top cells of their
1938 // respective shared ranges.
1939 for (sc::formula_block::iterator it
= itBeg
; it
!= itEnd
; ++it
)
1941 ScFormulaCell
* pCell
= *it
;
1942 size_t nRow
= nTopRow
+ std::distance(itBeg
, it
);
1943 if (!pCell
->IsShared())
1945 processNonShared(pCell
, nRow
);
1949 if (pCell
->IsSharedTop())
1951 ScFormulaCell
** pp
= &(*it
);
1952 SCROW nCellLen
= pCell
->GetSharedLength();
1953 assert(nCellLen
> 0);
1954 processSharedTop(pp
, nRow
, nCellLen
);
1956 // Move to the last cell in the group, to get incremented to
1957 // the next cell in the next iteration.
1958 size_t nOffsetToLast
= nCellLen
- 1;
1959 std::advance(it
, nOffsetToLast
);
1964 virtual void processNonShared( ScFormulaCell
* /*pCell*/, size_t /*nRow*/ ) {}
1965 virtual void processSharedTop( ScFormulaCell
** /*ppCells*/, size_t /*nRow*/, size_t /*nLength*/ ) {}
1968 class UpdateRefOnCopy
1970 const sc::RefUpdateContext
& mrCxt
;
1971 ScDocument
* mpUndoDoc
;
1975 UpdateRefOnCopy(const sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
) :
1976 mrCxt(rCxt
), mpUndoDoc(pUndoDoc
), mbUpdated(false) {}
1978 bool isUpdated() const { return mbUpdated
; }
1980 void operator() (sc::CellStoreType::value_type
& node
, size_t nOffset
, size_t nDataSize
)
1982 if (node
.type
!= sc::element_type_formula
)
1985 sc::formula_block::iterator it
= sc::formula_block::begin(*node
.data
);
1986 std::advance(it
, nOffset
);
1987 sc::formula_block::iterator itEnd
= it
;
1988 std::advance(itEnd
, nDataSize
);
1990 for (; it
!= itEnd
; ++it
)
1992 ScFormulaCell
& rCell
= **it
;
1993 mbUpdated
|= rCell
.UpdateReference(mrCxt
, mpUndoDoc
);
1998 class UpdateRefOnNonCopy
2002 const sc::RefUpdateContext
* mpCxt
;
2003 ScDocument
* mpUndoDoc
;
2005 bool mbClipboardSource
;
2007 void recompileTokenArray( ScFormulaCell
& rTopCell
)
2009 // We need to re-compile the token array when a range name is
2010 // modified, to correctly reflect the new references in the
2012 ScCompiler
aComp(mpCxt
->mrDoc
, rTopCell
.aPos
, *rTopCell
.GetCode(), mpCxt
->mrDoc
.GetGrammar(),
2013 true, rTopCell
.GetMatrixFlag() != ScMatrixMode::NONE
);
2014 aComp
.CompileTokenArray();
2017 void updateRefOnShift( sc::FormulaGroupEntry
& rGroup
)
2019 if (!rGroup
.mbShared
)
2021 ScAddress
aUndoPos(mnCol
, rGroup
.mnRow
, mnTab
);
2022 mbUpdated
|= rGroup
.mpCell
->UpdateReferenceOnShift(*mpCxt
, mpUndoDoc
, &aUndoPos
);
2026 // Update references of a formula group.
2027 ScFormulaCell
** pp
= rGroup
.mpCells
;
2028 ScFormulaCell
** ppEnd
= pp
+ rGroup
.mnLength
;
2029 ScFormulaCell
* pTop
= *pp
;
2030 ScTokenArray
* pCode
= pTop
->GetCode();
2031 ScTokenArray
aOldCode(pCode
->CloneValue());
2032 ScAddress aOldPos
= pTop
->aPos
;
2034 // Run this before the position gets updated.
2035 sc::RefUpdateResult aRes
= pCode
->AdjustReferenceOnShift(*mpCxt
, aOldPos
);
2037 bool bGroupShifted
= false;
2038 if (pTop
->UpdatePosOnShift(*mpCxt
))
2040 ScAddress
aErrorPos( ScAddress::UNINITIALIZED
);
2041 // Update the positions of all formula cells.
2042 for (++pp
; pp
!= ppEnd
; ++pp
) // skip the top cell.
2044 ScFormulaCell
* pFC
= *pp
;
2045 if (!pFC
->aPos
.Move(mpCxt
->mnColDelta
, mpCxt
->mnRowDelta
, mpCxt
->mnTabDelta
,
2046 aErrorPos
, mpCxt
->mrDoc
))
2048 assert(!"can't move formula cell");
2052 if (pCode
->IsRecalcModeOnRefMove())
2053 aRes
.mbValueChanged
= true;
2055 // FormulaGroupAreaListener (contrary to ScBroadcastArea) is not
2056 // updated but needs to be re-setup, else at least its mpColumn
2057 // would indicate the old column to collect cells from. tdf#129396
2058 /* TODO: investigate if that could be short-cut to avoid all the
2059 * EndListeningTo() / StartListeningTo() overhead and is really
2060 * only necessary when shifting the column, not also when shifting
2062 bGroupShifted
= true;
2064 else if (aRes
.mbReferenceModified
&& pCode
->IsRecalcModeOnRefMove())
2066 // The cell itself hasn't shifted. But it may have ROW or COLUMN
2067 // referencing another cell that has.
2068 aRes
.mbValueChanged
= true;
2071 if (aRes
.mbNameModified
)
2072 recompileTokenArray(*pTop
);
2074 if (aRes
.mbReferenceModified
|| aRes
.mbNameModified
|| bGroupShifted
)
2076 sc::EndListeningContext
aEndCxt(mpCxt
->mrDoc
, &aOldCode
);
2077 aEndCxt
.setPositionDelta(
2078 ScAddress(-mpCxt
->mnColDelta
, -mpCxt
->mnRowDelta
, -mpCxt
->mnTabDelta
));
2080 for (pp
= rGroup
.mpCells
; pp
!= ppEnd
; ++pp
)
2082 ScFormulaCell
* p
= *pp
;
2083 p
->EndListeningTo(aEndCxt
);
2084 p
->SetNeedsListening(true);
2089 fillUndoDoc(aOldPos
, rGroup
.mnLength
, aOldCode
);
2092 if (aRes
.mbValueChanged
)
2094 for (pp
= rGroup
.mpCells
; pp
!= ppEnd
; ++pp
)
2096 ScFormulaCell
* p
= *pp
;
2097 p
->SetNeedsDirty(true);
2102 void updateRefOnMove( sc::FormulaGroupEntry
& rGroup
)
2104 if (!rGroup
.mbShared
)
2106 ScAddress
aUndoPos(mnCol
, rGroup
.mnRow
, mnTab
);
2107 mbUpdated
|= rGroup
.mpCell
->UpdateReferenceOnMove(*mpCxt
, mpUndoDoc
, &aUndoPos
);
2111 // Update references of a formula group.
2112 ScFormulaCell
** pp
= rGroup
.mpCells
;
2113 ScFormulaCell
** ppEnd
= pp
+ rGroup
.mnLength
;
2114 ScFormulaCell
* pTop
= *pp
;
2115 ScTokenArray
* pCode
= pTop
->GetCode();
2116 ScTokenArray
aOldCode(pCode
->CloneValue());
2118 ScAddress aPos
= pTop
->aPos
;
2119 ScAddress aOldPos
= aPos
;
2122 if (mpCxt
->maRange
.Contains(aPos
))
2126 // The cell is being moved or copied to a new position. The
2127 // position has already been updated prior to this call.
2128 // Determine its original position before the move which will be
2129 // used to adjust relative references later.
2132 aPos
.Col() - mpCxt
->mnColDelta
,
2133 aPos
.Row() - mpCxt
->mnRowDelta
,
2134 aPos
.Tab() - mpCxt
->mnTabDelta
);
2141 bool bRecalcOnMove
= pCode
->IsRecalcModeOnRefMove();
2143 bRecalcOnMove
= aPos
!= aOldPos
;
2145 sc::RefUpdateResult aRes
= pCode
->AdjustReferenceOnMove(*mpCxt
, aOldPos
, aPos
);
2147 if (!(aRes
.mbReferenceModified
|| aRes
.mbNameModified
|| bRecalcOnMove
))
2150 sc::AutoCalcSwitch
aACSwitch(mpCxt
->mrDoc
, false);
2152 if (aRes
.mbNameModified
)
2153 recompileTokenArray(*pTop
);
2155 // Perform end-listening, start-listening, and dirtying on all
2156 // formula cells in the group.
2158 // Make sure that the start and end listening contexts share the
2159 // same block position set, else an invalid iterator may ensue.
2160 const auto pPosSet
= std::make_shared
<sc::ColumnBlockPositionSet
>(mpCxt
->mrDoc
);
2161 sc::StartListeningContext
aStartCxt(mpCxt
->mrDoc
, pPosSet
);
2162 sc::EndListeningContext
aEndCxt(mpCxt
->mrDoc
, pPosSet
, &aOldCode
);
2164 aEndCxt
.setPositionDelta(
2165 ScAddress(-mpCxt
->mnColDelta
, -mpCxt
->mnRowDelta
, -mpCxt
->mnTabDelta
));
2167 for (; pp
!= ppEnd
; ++pp
)
2169 ScFormulaCell
* p
= *pp
;
2170 p
->EndListeningTo(aEndCxt
);
2171 p
->StartListeningTo(aStartCxt
);
2177 // Move from clipboard is Cut&Paste, then do not copy the original
2178 // positions' formula cells to the Undo document.
2179 if (!mbClipboardSource
|| !bCellMoved
)
2180 fillUndoDoc(aOldPos
, rGroup
.mnLength
, aOldCode
);
2183 void fillUndoDoc( const ScAddress
& rOldPos
, SCROW nLength
, const ScTokenArray
& rOldCode
)
2185 if (!mpUndoDoc
|| nLength
<= 0)
2188 // Insert the old formula group into the undo document.
2189 ScAddress aUndoPos
= rOldPos
;
2190 ScFormulaCell
* pFC
= new ScFormulaCell(*mpUndoDoc
, aUndoPos
, rOldCode
.Clone());
2194 mpUndoDoc
->SetFormulaCell(aUndoPos
, pFC
);
2198 std::vector
<ScFormulaCell
*> aCells
;
2199 aCells
.reserve(nLength
);
2200 ScFormulaCellGroupRef xGroup
= pFC
->CreateCellGroup(nLength
, false);
2201 aCells
.push_back(pFC
);
2203 for (SCROW i
= 1; i
< nLength
; ++i
, aUndoPos
.IncRow())
2205 pFC
= new ScFormulaCell(*mpUndoDoc
, aUndoPos
, xGroup
);
2206 aCells
.push_back(pFC
);
2209 if (!mpUndoDoc
->SetFormulaCells(rOldPos
, aCells
))
2210 // Insertion failed. Delete all formula cells.
2211 std::for_each(aCells
.begin(), aCells
.end(), std::default_delete
<ScFormulaCell
>());
2216 SCCOL nCol
, SCTAB nTab
, const sc::RefUpdateContext
* pCxt
,
2217 ScDocument
* pUndoDoc
) :
2218 mnCol(nCol
), mnTab(nTab
), mpCxt(pCxt
),
2219 mpUndoDoc(pUndoDoc
), mbUpdated(false),
2220 mbClipboardSource(pCxt
->mrDoc
.IsClipboardSource()){}
2222 void operator() ( sc::FormulaGroupEntry
& rGroup
)
2224 switch (mpCxt
->meMode
)
2227 updateRefOnShift(rGroup
);
2230 updateRefOnMove(rGroup
);
2236 if (rGroup
.mbShared
)
2238 ScAddress
aUndoPos(mnCol
, rGroup
.mnRow
, mnTab
);
2239 ScFormulaCell
** pp
= rGroup
.mpCells
;
2240 ScFormulaCell
** ppEnd
= pp
+ rGroup
.mnLength
;
2241 for (; pp
!= ppEnd
; ++pp
, aUndoPos
.IncRow())
2243 ScFormulaCell
* p
= *pp
;
2244 mbUpdated
|= p
->UpdateReference(*mpCxt
, mpUndoDoc
, &aUndoPos
);
2249 ScAddress
aUndoPos(mnCol
, rGroup
.mnRow
, mnTab
);
2250 mbUpdated
|= rGroup
.mpCell
->UpdateReference(*mpCxt
, mpUndoDoc
, &aUndoPos
);
2254 bool isUpdated() const { return mbUpdated
; }
2257 class UpdateRefGroupBoundChecker
: public SharedTopFormulaCellPicker
2259 const sc::RefUpdateContext
& mrCxt
;
2260 std::vector
<SCROW
>& mrBounds
;
2263 UpdateRefGroupBoundChecker(const sc::RefUpdateContext
& rCxt
, std::vector
<SCROW
>& rBounds
) :
2264 mrCxt(rCxt
), mrBounds(rBounds
) {}
2266 virtual void processSharedTop( ScFormulaCell
** ppCells
, size_t /*nRow*/, size_t /*nLength*/ ) override
2268 // Check its tokens and record its reference boundaries.
2269 ScFormulaCell
& rCell
= **ppCells
;
2270 const ScTokenArray
& rCode
= *rCell
.GetCode();
2271 rCode
.CheckRelativeReferenceBounds(
2272 mrCxt
, rCell
.aPos
, rCell
.GetSharedLength(), mrBounds
);
2276 class UpdateRefExpandGroupBoundChecker
: public SharedTopFormulaCellPicker
2278 const sc::RefUpdateContext
& mrCxt
;
2279 std::vector
<SCROW
>& mrBounds
;
2282 UpdateRefExpandGroupBoundChecker(const sc::RefUpdateContext
& rCxt
, std::vector
<SCROW
>& rBounds
) :
2283 mrCxt(rCxt
), mrBounds(rBounds
) {}
2285 virtual void processSharedTop( ScFormulaCell
** ppCells
, size_t /*nRow*/, size_t /*nLength*/ ) override
2287 // Check its tokens and record its reference boundaries.
2288 ScFormulaCell
& rCell
= **ppCells
;
2289 const ScTokenArray
& rCode
= *rCell
.GetCode();
2290 rCode
.CheckExpandReferenceBounds(
2291 mrCxt
, rCell
.aPos
, rCell
.GetSharedLength(), mrBounds
);
2295 class FormulaGroupPicker
: public SharedTopFormulaCellPicker
2297 std::vector
<sc::FormulaGroupEntry
>& mrGroups
;
2300 explicit FormulaGroupPicker( std::vector
<sc::FormulaGroupEntry
>& rGroups
) : mrGroups(rGroups
) {}
2302 virtual void processNonShared( ScFormulaCell
* pCell
, size_t nRow
) override
2304 mrGroups
.emplace_back(pCell
, nRow
);
2307 virtual void processSharedTop( ScFormulaCell
** ppCells
, size_t nRow
, size_t nLength
) override
2309 mrGroups
.emplace_back(ppCells
, nRow
, nLength
);
2315 bool ScColumn::UpdateReferenceOnCopy( sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
)
2317 // When copying, the range equals the destination range where cells
2318 // are pasted, and the dx, dy, dz refer to the distance from the
2321 UpdateRefOnCopy
aHandler(rCxt
, pUndoDoc
);
2322 sc::ColumnBlockPosition
* blockPos
= rCxt
.getBlockPosition(nTab
, nCol
);
2323 sc::CellStoreType::position_type aPos
= blockPos
2324 ? maCells
.position(blockPos
->miCellPos
, rCxt
.maRange
.aStart
.Row())
2325 : maCells
.position(rCxt
.maRange
.aStart
.Row());
2326 sc::ProcessBlock(aPos
.first
, maCells
, aHandler
, rCxt
.maRange
.aStart
.Row(), rCxt
.maRange
.aEnd
.Row());
2328 // The formula groups at the top and bottom boundaries are expected to
2329 // have been split prior to this call. Here, we only do the joining.
2330 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
2331 if (rCxt
.maRange
.aEnd
.Row() < GetDoc().MaxRow())
2333 aPos
= maCells
.position(aPos
.first
, rCxt
.maRange
.aEnd
.Row()+1);
2334 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
2337 return aHandler
.isUpdated();
2340 bool ScColumn::UpdateReference( sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
)
2342 if (IsEmptyData() || GetDoc().IsClipOrUndo())
2343 // Cells in this column are all empty, or clip or undo doc. No update needed.
2346 if (rCxt
.meMode
== URM_COPY
)
2347 return UpdateReferenceOnCopy(rCxt
, pUndoDoc
);
2349 std::vector
<SCROW
> aBounds
;
2351 bool bThisColShifted
= (rCxt
.maRange
.aStart
.Tab() <= nTab
&& nTab
<= rCxt
.maRange
.aEnd
.Tab() &&
2352 rCxt
.maRange
.aStart
.Col() <= nCol
&& nCol
<= rCxt
.maRange
.aEnd
.Col());
2353 if (bThisColShifted
)
2355 // Cells in this column is being shifted. Split formula grouping at
2356 // the top and bottom boundaries before they get shifted.
2357 // Also, for deleted rows split at the top of the deleted area to adapt
2358 // the affected group length.
2360 if (rCxt
.mnRowDelta
< 0)
2362 nSplitPos
= rCxt
.maRange
.aStart
.Row() + rCxt
.mnRowDelta
;
2363 if (GetDoc().ValidRow(nSplitPos
))
2364 aBounds
.push_back(nSplitPos
);
2366 nSplitPos
= rCxt
.maRange
.aStart
.Row();
2367 if (GetDoc().ValidRow(nSplitPos
))
2369 aBounds
.push_back(nSplitPos
);
2370 nSplitPos
= rCxt
.maRange
.aEnd
.Row() + 1;
2371 if (GetDoc().ValidRow(nSplitPos
))
2372 aBounds
.push_back(nSplitPos
);
2376 // Check the row positions at which the group must be split per relative
2379 UpdateRefGroupBoundChecker
aBoundChecker(rCxt
, aBounds
);
2380 std::for_each(maCells
.begin(), maCells
.end(), std::move(aBoundChecker
));
2383 // If expand reference edges is on, splitting groups may happen anywhere
2384 // where a reference points to an adjacent row of the insertion.
2385 if (rCxt
.mnRowDelta
> 0 && rCxt
.mrDoc
.IsExpandRefs())
2387 UpdateRefExpandGroupBoundChecker
aExpandChecker(rCxt
, aBounds
);
2388 std::for_each(maCells
.begin(), maCells
.end(), std::move(aExpandChecker
));
2391 // Do the actual splitting.
2392 const bool bSplit
= sc::SharedFormulaUtil::splitFormulaCellGroups(GetDoc(), maCells
, aBounds
);
2394 // Collect all formula groups.
2395 std::vector
<sc::FormulaGroupEntry
> aGroups
= GetFormulaGroupEntries();
2397 // Process all collected formula groups.
2398 UpdateRefOnNonCopy
aHandler(nCol
, nTab
, &rCxt
, pUndoDoc
);
2399 aHandler
= std::for_each(aGroups
.begin(), aGroups
.end(), aHandler
);
2400 if (bSplit
|| aHandler
.isUpdated())
2401 rCxt
.maRegroupCols
.set(nTab
, nCol
);
2403 return aHandler
.isUpdated();
2406 std::vector
<sc::FormulaGroupEntry
> ScColumn::GetFormulaGroupEntries()
2408 std::vector
<sc::FormulaGroupEntry
> aGroups
;
2409 std::for_each(maCells
.begin(), maCells
.end(), FormulaGroupPicker(aGroups
));
2415 class UpdateTransHandler
2418 sc::CellStoreType::iterator miPos
;
2421 ScDocument
* mpUndoDoc
;
2423 UpdateTransHandler(ScColumn
& rColumn
, const ScRange
& rSource
, const ScAddress
& rDest
, ScDocument
* pUndoDoc
) :
2425 miPos(rColumn
.GetCellStore().begin()),
2426 maSource(rSource
), maDest(rDest
), mpUndoDoc(pUndoDoc
) {}
2428 void operator() (size_t nRow
, ScFormulaCell
* pCell
)
2430 sc::CellStoreType::position_type aPos
= mrColumn
.GetCellStore().position(miPos
, nRow
);
2432 sc::SharedFormulaUtil::unshareFormulaCell(aPos
, *pCell
);
2433 pCell
->UpdateTranspose(maSource
, maDest
, mpUndoDoc
);
2434 ScColumn::JoinNewFormulaCell(aPos
, *pCell
);
2438 class UpdateGrowHandler
2441 sc::CellStoreType::iterator miPos
;
2446 UpdateGrowHandler(ScColumn
& rColumn
, const ScRange
& rArea
, SCCOL nGrowX
, SCROW nGrowY
) :
2448 miPos(rColumn
.GetCellStore().begin()),
2449 maArea(rArea
), mnGrowX(nGrowX
), mnGrowY(nGrowY
) {}
2451 void operator() (size_t nRow
, ScFormulaCell
* pCell
)
2453 sc::CellStoreType::position_type aPos
= mrColumn
.GetCellStore().position(miPos
, nRow
);
2455 sc::SharedFormulaUtil::unshareFormulaCell(aPos
, *pCell
);
2456 pCell
->UpdateGrow(maArea
, mnGrowX
, mnGrowY
);
2457 ScColumn::JoinNewFormulaCell(aPos
, *pCell
);
2461 class InsertTabUpdater
2463 sc::RefUpdateInsertTabContext
& mrCxt
;
2464 sc::CellTextAttrStoreType
& mrTextAttrs
;
2465 sc::CellTextAttrStoreType::iterator miAttrPos
;
2470 InsertTabUpdater(sc::RefUpdateInsertTabContext
& rCxt
, sc::CellTextAttrStoreType
& rTextAttrs
, SCTAB nTab
) :
2472 mrTextAttrs(rTextAttrs
),
2473 miAttrPos(rTextAttrs
.begin()),
2475 mbModified(false) {}
2477 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2479 pCell
->UpdateInsertTab(mrCxt
);
2483 void operator() (size_t nRow
, EditTextObject
* pCell
)
2485 editeng::FieldUpdater aUpdater
= pCell
->GetFieldUpdater();
2486 aUpdater
.updateTableFields(mnTab
);
2487 miAttrPos
= mrTextAttrs
.set(miAttrPos
, nRow
, sc::CellTextAttr());
2491 bool isModified() const { return mbModified
; }
2494 class DeleteTabUpdater
2496 sc::RefUpdateDeleteTabContext
& mrCxt
;
2497 sc::CellTextAttrStoreType
& mrTextAttrs
;
2498 sc::CellTextAttrStoreType::iterator miAttrPos
;
2502 DeleteTabUpdater(sc::RefUpdateDeleteTabContext
& rCxt
, sc::CellTextAttrStoreType
& rTextAttrs
, SCTAB nTab
) :
2504 mrTextAttrs(rTextAttrs
),
2505 miAttrPos(rTextAttrs
.begin()),
2507 mbModified(false) {}
2509 void operator() (size_t, ScFormulaCell
* pCell
)
2511 pCell
->UpdateDeleteTab(mrCxt
);
2515 void operator() (size_t nRow
, EditTextObject
* pCell
)
2517 editeng::FieldUpdater aUpdater
= pCell
->GetFieldUpdater();
2518 aUpdater
.updateTableFields(mnTab
);
2519 miAttrPos
= mrTextAttrs
.set(miAttrPos
, nRow
, sc::CellTextAttr());
2523 bool isModified() const { return mbModified
; }
2526 class InsertAbsTabUpdater
2528 sc::CellTextAttrStoreType
& mrTextAttrs
;
2529 sc::CellTextAttrStoreType::iterator miAttrPos
;
2534 InsertAbsTabUpdater(sc::CellTextAttrStoreType
& rTextAttrs
, SCTAB nTab
, SCTAB nNewPos
) :
2535 mrTextAttrs(rTextAttrs
),
2536 miAttrPos(rTextAttrs
.begin()),
2539 mbModified(false) {}
2541 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2543 pCell
->UpdateInsertTabAbs(mnNewPos
);
2547 void operator() (size_t nRow
, EditTextObject
* pCell
)
2549 editeng::FieldUpdater aUpdater
= pCell
->GetFieldUpdater();
2550 aUpdater
.updateTableFields(mnTab
);
2551 miAttrPos
= mrTextAttrs
.set(miAttrPos
, nRow
, sc::CellTextAttr());
2555 bool isModified() const { return mbModified
; }
2558 class MoveTabUpdater
2560 sc::RefUpdateMoveTabContext
& mrCxt
;
2561 sc::CellTextAttrStoreType
& mrTextAttrs
;
2562 sc::CellTextAttrStoreType::iterator miAttrPos
;
2566 MoveTabUpdater(sc::RefUpdateMoveTabContext
& rCxt
, sc::CellTextAttrStoreType
& rTextAttrs
, SCTAB nTab
) :
2568 mrTextAttrs(rTextAttrs
),
2569 miAttrPos(rTextAttrs
.begin()),
2571 mbModified(false) {}
2573 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2575 pCell
->UpdateMoveTab(mrCxt
, mnTab
);
2579 void operator() (size_t nRow
, EditTextObject
* pCell
)
2581 editeng::FieldUpdater aUpdater
= pCell
->GetFieldUpdater();
2582 aUpdater
.updateTableFields(mnTab
);
2583 miAttrPos
= mrTextAttrs
.set(miAttrPos
, nRow
, sc::CellTextAttr());
2587 bool isModified() const { return mbModified
; }
2590 class UpdateCompileHandler
2592 bool mbForceIfNameInUse
:1;
2594 explicit UpdateCompileHandler(bool bForceIfNameInUse
) :
2595 mbForceIfNameInUse(bForceIfNameInUse
) {}
2597 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2599 pCell
->UpdateCompile(mbForceIfNameInUse
);
2607 explicit TabNoSetter(SCTAB nTab
) : mnTab(nTab
) {}
2609 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2611 pCell
->aPos
.SetTab(mnTab
);
2615 class UsedRangeNameFinder
2617 sc::UpdatedRangeNames
& mrIndexes
;
2619 explicit UsedRangeNameFinder(sc::UpdatedRangeNames
& rIndexes
) : mrIndexes(rIndexes
) {}
2621 void operator() (size_t /*nRow*/, const ScFormulaCell
* pCell
)
2623 pCell
->FindRangeNamesInUse(mrIndexes
);
2627 class CheckVectorizationHandler
2630 CheckVectorizationHandler()
2633 void operator() (size_t /*nRow*/, ScFormulaCell
* p
)
2635 ScTokenArray
* pCode
= p
->GetCode();
2636 if (pCode
&& pCode
->IsFormulaVectorDisabled())
2638 pCode
->ResetVectorState();
2639 FormulaTokenArrayPlainIterator
aIter(*pCode
);
2640 FormulaToken
* pFT
= aIter
.First();
2643 pCode
->CheckToken(*pFT
);
2650 struct SetDirtyVarHandler
2652 void operator() (size_t /*nRow*/, ScFormulaCell
* p
)
2658 class SetDirtyHandler
2661 const sc::SetFormulaDirtyContext
& mrCxt
;
2663 SetDirtyHandler( ScDocument
& rDoc
, const sc::SetFormulaDirtyContext
& rCxt
) :
2664 mrDoc(rDoc
), mrCxt(rCxt
) {}
2666 void operator() (size_t /*nRow*/, ScFormulaCell
* p
)
2668 if (mrCxt
.mbClearTabDeletedFlag
)
2670 if (!p
->IsShared() || p
->IsSharedTop())
2672 ScTokenArray
* pCode
= p
->GetCode();
2673 pCode
->ClearTabDeleted(
2674 p
->aPos
, mrCxt
.mnTabDeletedStart
, mrCxt
.mnTabDeletedEnd
);
2679 if (!mrDoc
.IsInFormulaTree(p
))
2680 mrDoc
.PutInFormulaTree(p
);
2684 class SetDirtyOnRangeHandler
2686 sc::SingleColumnSpanSet maValueRanges
;
2689 explicit SetDirtyOnRangeHandler(ScColumn
& rColumn
)
2690 : maValueRanges(rColumn
.GetDoc().GetSheetLimits()),
2691 mrColumn(rColumn
) {}
2693 void operator() (size_t /*nRow*/, ScFormulaCell
* p
)
2698 void operator() (mdds::mtv::element_t type
, size_t nTopRow
, size_t nDataSize
)
2700 if (type
== sc::element_type_empty
)
2701 // Ignore empty blocks.
2704 // Non-formula cells.
2705 SCROW nRow1
= nTopRow
;
2706 SCROW nRow2
= nTopRow
+ nDataSize
- 1;
2707 maValueRanges
.set(nRow1
, nRow2
, true);
2712 std::vector
<SCROW
> aRows
;
2713 maValueRanges
.getRows(aRows
);
2714 mrColumn
.BroadcastCells(aRows
, SfxHintId::ScDataChanged
);
2717 void fillBroadcastSpans( sc::ColumnSpanSet
& rBroadcastSpans
) const
2719 SCCOL nCol
= mrColumn
.GetCol();
2720 SCTAB nTab
= mrColumn
.GetTab();
2721 sc::SingleColumnSpanSet::SpansType aSpans
;
2722 maValueRanges
.getSpans(aSpans
);
2724 for (const auto& rSpan
: aSpans
)
2725 rBroadcastSpans
.set(mrColumn
.GetDoc(), nTab
, nCol
, rSpan
.mnRow1
, rSpan
.mnRow2
, true);
2729 class SetTableOpDirtyOnRangeHandler
2731 sc::SingleColumnSpanSet maValueRanges
;
2734 explicit SetTableOpDirtyOnRangeHandler(ScColumn
& rColumn
)
2735 : maValueRanges(rColumn
.GetDoc().GetSheetLimits()),
2736 mrColumn(rColumn
) {}
2738 void operator() (size_t /*nRow*/, ScFormulaCell
* p
)
2740 p
->SetTableOpDirty();
2743 void operator() (mdds::mtv::element_t type
, size_t nTopRow
, size_t nDataSize
)
2745 if (type
== sc::element_type_empty
)
2746 // Ignore empty blocks.
2749 // Non-formula cells.
2750 SCROW nRow1
= nTopRow
;
2751 SCROW nRow2
= nTopRow
+ nDataSize
- 1;
2752 maValueRanges
.set(nRow1
, nRow2
, true);
2757 std::vector
<SCROW
> aRows
;
2758 maValueRanges
.getRows(aRows
);
2759 mrColumn
.BroadcastCells(aRows
, SfxHintId::ScTableOpDirty
);
2763 struct SetDirtyAfterLoadHandler
2765 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2768 // Simply set dirty and append to FormulaTree, without broadcasting,
2769 // which is a magnitude faster. This is used to calculate the entire
2770 // document, e.g. when loading alien file formats.
2771 pCell
->SetDirtyAfterLoad();
2773 /* This was used with the binary file format that stored results, where only
2774 * newly compiled and volatile functions and their dependents had to be
2775 * recalculated, which was faster then. Since that was moved to 'binfilter' to
2776 * convert to an XML file this isn't needed anymore, and not used for other
2777 * file formats. Kept for reference in case mechanism needs to be reactivated
2778 * for some file formats, we'd have to introduce a controlling parameter to
2779 * this method here then.
2782 // If the cell was already dirty because of CalcAfterLoad,
2783 // FormulaTracking has to take place.
2784 if (pCell
->GetDirty())
2790 struct SetDirtyIfPostponedHandler
2792 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2794 if (pCell
->IsPostponedDirty() || (pCell
->HasRelNameReference() != ScFormulaCell::RelNameRef::NONE
))
2799 struct CalcAllHandler
2801 #define DEBUG_SC_CHECK_FORMULATREE_CALCULATION 0
2802 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2804 #if DEBUG_SC_CHECK_FORMULATREE_CALCULATION
2805 // after F9 ctrl-F9: check the calculation for each FormulaTree
2806 double nOldVal
, nNewVal
;
2807 nOldVal
= pCell
->GetValue();
2810 #if DEBUG_SC_CHECK_FORMULATREE_CALCULATION
2811 if (pCell
->GetCode()->IsRecalcModeNormal())
2812 nNewVal
= pCell
->GetValue();
2814 nNewVal
= nOldVal
; // random(), jetzt() etc.
2816 assert(nOldVal
== nNewVal
);
2819 #undef DEBUG_SC_CHECK_FORMULATREE_CALCULATION
2822 class CompileAllHandler
2824 sc::CompileFormulaContext
& mrCxt
;
2826 explicit CompileAllHandler( sc::CompileFormulaContext
& rCxt
) : mrCxt(rCxt
) {}
2828 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2830 // for unconditional compilation
2831 // bCompile=true and pCode->nError=0
2832 pCell
->GetCode()->SetCodeError(FormulaError::NONE
);
2833 pCell
->SetCompile(true);
2834 pCell
->CompileTokenArray(mrCxt
);
2838 class CompileXMLHandler
2840 sc::CompileFormulaContext
& mrCxt
;
2841 ScProgress
& mrProgress
;
2842 const ScColumn
& mrCol
;
2844 CompileXMLHandler( sc::CompileFormulaContext
& rCxt
, ScProgress
& rProgress
, const ScColumn
& rCol
) :
2846 mrProgress(rProgress
),
2849 void operator() (size_t nRow
, ScFormulaCell
* pCell
)
2851 sal_uInt32 nFormat
= mrCol
.GetNumberFormat(mrCol
.GetDoc().GetNonThreadedContext(), nRow
);
2852 if( (nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
) != 0)
2853 // Non-default number format is set.
2854 pCell
->SetNeedNumberFormat(false);
2855 else if (pCell
->NeedsNumberFormat())
2856 pCell
->SetDirtyVar();
2858 if (pCell
->GetMatrixFlag() != ScMatrixMode::NONE
)
2859 pCell
->SetDirtyVar();
2861 pCell
->CompileXML(mrCxt
, mrProgress
);
2865 class CompileErrorCellsHandler
2867 sc::CompileFormulaContext
& mrCxt
;
2869 sc::CellStoreType::iterator miPos
;
2870 FormulaError mnErrCode
;
2873 CompileErrorCellsHandler( sc::CompileFormulaContext
& rCxt
, ScColumn
& rColumn
, FormulaError nErrCode
) :
2876 miPos(mrColumn
.GetCellStore().begin()),
2877 mnErrCode(nErrCode
),
2882 void operator() (size_t nRow
, ScFormulaCell
* pCell
)
2884 FormulaError nCurError
= pCell
->GetRawError();
2885 if (nCurError
== FormulaError::NONE
)
2886 // It's not an error cell. Skip it.
2889 if (mnErrCode
!= FormulaError::NONE
&& nCurError
!= mnErrCode
)
2890 // Error code is specified, and it doesn't match. Skip it.
2893 sc::CellStoreType::position_type aPos
= mrColumn
.GetCellStore().position(miPos
, nRow
);
2895 sc::SharedFormulaUtil::unshareFormulaCell(aPos
, *pCell
);
2896 pCell
->GetCode()->SetCodeError(FormulaError::NONE
);
2897 OUString aFormula
= pCell
->GetFormula(mrCxt
);
2898 pCell
->Compile(mrCxt
, aFormula
);
2899 ScColumn::JoinNewFormulaCell(aPos
, *pCell
);
2904 bool isCompiled() const { return mbCompiled
; }
2907 class CalcAfterLoadHandler
2909 sc::CompileFormulaContext
& mrCxt
;
2910 bool mbStartListening
;
2913 CalcAfterLoadHandler( sc::CompileFormulaContext
& rCxt
, bool bStartListening
) :
2914 mrCxt(rCxt
), mbStartListening(bStartListening
) {}
2916 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2918 pCell
->CalcAfterLoad(mrCxt
, mbStartListening
);
2922 struct ResetChangedHandler
2924 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2926 pCell
->SetChanged(false);
2931 * Ambiguous script type counts as edit cell.
2933 class FindEditCellsHandler
2936 sc::CellTextAttrStoreType::iterator miAttrPos
;
2937 sc::CellStoreType::iterator miCellPos
;
2940 explicit FindEditCellsHandler(ScColumn
& rCol
) :
2942 miAttrPos(rCol
.GetCellAttrStore().begin()),
2943 miCellPos(rCol
.GetCellStore().begin()) {}
2945 bool operator() (size_t, const EditTextObject
*)
2947 // This is definitely an edit text cell.
2951 bool operator() (size_t nRow
, const ScFormulaCell
* p
)
2953 // With a formula cell, it's considered an edit text cell when either
2954 // the result is multi-line or it has more than one script types.
2955 SvtScriptType nScriptType
= mrColumn
.GetRangeScriptType(miAttrPos
, nRow
, nRow
, miCellPos
);
2956 if (IsAmbiguousScriptNonZero(nScriptType
))
2959 return const_cast<ScFormulaCell
*>(p
)->IsMultilineResult();
2963 * Callback for a block of other types.
2965 std::pair
<size_t,bool> operator() (const sc::CellStoreType::value_type
& node
, size_t nOffset
, size_t nDataSize
)
2967 typedef std::pair
<size_t,bool> RetType
;
2969 if (node
.type
== sc::element_type_empty
)
2970 // Ignore empty blocks.
2971 return RetType(0, false);
2973 // Check the script type of a non-empty element and see if it has
2974 // multiple script types.
2975 for (size_t i
= 0; i
< nDataSize
; ++i
)
2977 SCROW nRow
= node
.position
+ i
+ nOffset
;
2978 SvtScriptType nScriptType
= mrColumn
.GetRangeScriptType(miAttrPos
, nRow
, nRow
, miCellPos
);
2979 if (IsAmbiguousScriptNonZero(nScriptType
))
2980 // Return the offset from the first row.
2981 return RetType(i
+nOffset
, true);
2984 // No edit text cell found.
2985 return RetType(0, false);
2991 void ScColumn::UpdateTranspose( const ScRange
& rSource
, const ScAddress
& rDest
,
2992 ScDocument
* pUndoDoc
)
2994 UpdateTransHandler
aFunc(*this, rSource
, rDest
, pUndoDoc
);
2995 sc::ProcessFormula(maCells
, aFunc
);
2998 void ScColumn::UpdateGrow( const ScRange
& rArea
, SCCOL nGrowX
, SCROW nGrowY
)
3000 UpdateGrowHandler
aFunc(*this, rArea
, nGrowX
, nGrowY
);
3001 sc::ProcessFormula(maCells
, aFunc
);
3004 void ScColumn::UpdateInsertTab( sc::RefUpdateInsertTabContext
& rCxt
)
3006 if (nTab
>= rCxt
.mnInsertPos
)
3008 nTab
+= rCxt
.mnSheets
;
3009 pAttrArray
->SetTab(nTab
);
3012 UpdateInsertTabOnlyCells(rCxt
);
3015 void ScColumn::UpdateInsertTabOnlyCells( sc::RefUpdateInsertTabContext
& rCxt
)
3017 InsertTabUpdater
aFunc(rCxt
, maCellTextAttrs
, nTab
);
3018 sc::ProcessFormulaEditText(maCells
, aFunc
);
3019 if (aFunc
.isModified())
3020 CellStorageModified();
3023 void ScColumn::UpdateDeleteTab( sc::RefUpdateDeleteTabContext
& rCxt
)
3025 if (nTab
> rCxt
.mnDeletePos
)
3027 nTab
-= rCxt
.mnSheets
;
3028 pAttrArray
->SetTab(nTab
);
3031 DeleteTabUpdater
aFunc(rCxt
, maCellTextAttrs
, nTab
);
3032 sc::ProcessFormulaEditText(maCells
, aFunc
);
3033 if (aFunc
.isModified())
3034 CellStorageModified();
3037 void ScColumn::UpdateInsertTabAbs(SCTAB nNewPos
)
3039 InsertAbsTabUpdater
aFunc(maCellTextAttrs
, nTab
, nNewPos
);
3040 sc::ProcessFormulaEditText(maCells
, aFunc
);
3041 if (aFunc
.isModified())
3042 CellStorageModified();
3045 void ScColumn::UpdateMoveTab( sc::RefUpdateMoveTabContext
& rCxt
, SCTAB nTabNo
)
3048 pAttrArray
->SetTab( nTabNo
);
3050 MoveTabUpdater
aFunc(rCxt
, maCellTextAttrs
, nTab
);
3051 sc::ProcessFormulaEditText(maCells
, aFunc
);
3052 if (aFunc
.isModified())
3053 CellStorageModified();
3056 void ScColumn::UpdateCompile( bool bForceIfNameInUse
)
3058 UpdateCompileHandler
aFunc(bForceIfNameInUse
);
3059 sc::ProcessFormula(maCells
, aFunc
);
3062 void ScColumn::SetTabNo(SCTAB nNewTab
)
3065 pAttrArray
->SetTab( nNewTab
);
3067 TabNoSetter
aFunc(nTab
);
3068 sc::ProcessFormula(maCells
, aFunc
);
3071 void ScColumn::FindRangeNamesInUse(SCROW nRow1
, SCROW nRow2
, sc::UpdatedRangeNames
& rIndexes
) const
3073 UsedRangeNameFinder
aFunc(rIndexes
);
3074 sc::ParseFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aFunc
);
3077 void ScColumn::SetDirtyVar()
3079 SetDirtyVarHandler aFunc
;
3080 sc::ProcessFormula(maCells
, aFunc
);
3083 bool ScColumn::IsFormulaDirty( SCROW nRow
) const
3085 if (!GetDoc().ValidRow(nRow
))
3088 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nRow
);
3089 sc::CellStoreType::const_iterator it
= aPos
.first
;
3090 if (it
->type
!= sc::element_type_formula
)
3091 // This is not a formula cell block.
3094 const ScFormulaCell
* p
= sc::formula_block::at(*it
->data
, aPos
.second
);
3095 return p
->GetDirty();
3098 void ScColumn::CheckVectorizationState()
3100 sc::AutoCalcSwitch
aSwitch(GetDoc(), false);
3101 CheckVectorizationHandler aFunc
;
3102 sc::ProcessFormula(maCells
, aFunc
);
3105 void ScColumn::SetAllFormulasDirty( const sc::SetFormulaDirtyContext
& rCxt
)
3107 // is only done documentwide, no FormulaTracking
3108 sc::AutoCalcSwitch
aSwitch(GetDoc(), false);
3109 SetDirtyHandler
aFunc(GetDoc(), rCxt
);
3110 sc::ProcessFormula(maCells
, aFunc
);
3113 void ScColumn::SetDirtyFromClip( SCROW nRow1
, SCROW nRow2
, sc::ColumnSpanSet
& rBroadcastSpans
)
3115 // Set all formula cells in the range dirty, and pick up all non-formula
3116 // cells for later broadcasting. We don't broadcast here.
3117 sc::AutoCalcSwitch
aSwitch(GetDoc(), false);
3119 SetDirtyOnRangeHandler
aHdl(*this);
3120 sc::ProcessFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aHdl
, aHdl
);
3121 aHdl
.fillBroadcastSpans(rBroadcastSpans
);
3126 class BroadcastBroadcastersHandler
3132 explicit BroadcastBroadcastersHandler( SfxHintId nHint
, SCTAB nTab
, SCCOL nCol
)
3133 : maHint(nHint
, ScAddress(nCol
, 0, nTab
))
3134 , mbBroadcasted(false)
3138 void operator() ( size_t nRow
, SvtBroadcaster
* pBroadcaster
)
3140 maHint
.SetAddressRow(nRow
);
3141 pBroadcaster
->Broadcast(maHint
);
3142 mbBroadcasted
= true;
3145 bool wasBroadcasted() { return mbBroadcasted
; }
3150 bool ScColumn::BroadcastBroadcasters( SCROW nRow1
, SCROW nRow2
, SfxHintId nHint
)
3152 BroadcastBroadcastersHandler
aBroadcasterHdl(nHint
, nTab
, nCol
);
3153 sc::ProcessBroadcaster(maBroadcasters
.begin(), maBroadcasters
, nRow1
, nRow2
, aBroadcasterHdl
);
3154 return aBroadcasterHdl
.wasBroadcasted();
3157 void ScColumn::SetDirty( SCROW nRow1
, SCROW nRow2
, BroadcastMode eMode
)
3159 // broadcasts everything within the range, with FormulaTracking
3160 sc::AutoCalcSwitch
aSwitch(GetDoc(), false);
3164 case BROADCAST_NONE
:
3166 // Handler only used with formula cells.
3167 SetDirtyOnRangeHandler
aHdl(*this);
3168 sc::ProcessFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aHdl
);
3171 case BROADCAST_DATA_POSITIONS
:
3173 // Handler used with both, formula and non-formula cells.
3174 SetDirtyOnRangeHandler
aHdl(*this);
3175 sc::ProcessFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aHdl
, aHdl
);
3179 case BROADCAST_BROADCASTERS
:
3181 // Handler only used with formula cells.
3182 SetDirtyOnRangeHandler
aHdl(*this);
3183 sc::ProcessFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aHdl
);
3184 // Broadcast all broadcasters in range.
3185 if (BroadcastBroadcasters( nRow1
, nRow2
, SfxHintId::ScDataChanged
))
3187 // SetDirtyOnRangeHandler implicitly tracks notified
3188 // formulas via ScDocument::Broadcast(), which
3189 // BroadcastBroadcastersHandler doesn't, so explicitly
3191 GetDoc().TrackFormulas();
3198 void ScColumn::SetTableOpDirty( const ScRange
& rRange
)
3200 sc::AutoCalcSwitch
aSwitch(GetDoc(), false);
3202 SCROW nRow1
= rRange
.aStart
.Row(), nRow2
= rRange
.aEnd
.Row();
3203 SetTableOpDirtyOnRangeHandler
aHdl(*this);
3204 sc::ProcessFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aHdl
, aHdl
);
3208 void ScColumn::SetDirtyAfterLoad()
3210 sc::AutoCalcSwitch
aSwitch(GetDoc(), false);
3211 SetDirtyAfterLoadHandler aFunc
;
3212 sc::ProcessFormula(maCells
, aFunc
);
3217 class RecalcOnRefMoveCollector
3219 std::vector
<SCROW
> maDirtyRows
;
3221 void operator() (size_t nRow
, ScFormulaCell
* pCell
)
3223 if (pCell
->GetDirty() && pCell
->GetCode()->IsRecalcModeOnRefMove())
3224 maDirtyRows
.push_back(nRow
);
3227 const std::vector
<SCROW
>& getDirtyRows() const
3235 void ScColumn::SetDirtyIfPostponed()
3237 sc::AutoCalcSwitch
aSwitch(GetDoc(), false);
3238 SetDirtyIfPostponedHandler aFunc
;
3239 ScBulkBroadcast
aBulkBroadcast( GetDoc().GetBASM(), SfxHintId::ScDataChanged
);
3240 sc::ProcessFormula(maCells
, aFunc
);
3243 void ScColumn::BroadcastRecalcOnRefMove()
3245 sc::AutoCalcSwitch
aSwitch(GetDoc(), false);
3246 RecalcOnRefMoveCollector aFunc
;
3247 sc::ProcessFormula(maCells
, aFunc
);
3248 BroadcastCells(aFunc
.getDirtyRows(), SfxHintId::ScDataChanged
);
3251 void ScColumn::CalcAll()
3253 CalcAllHandler aFunc
;
3254 sc::ProcessFormula(maCells
, aFunc
);
3257 void ScColumn::CompileAll( sc::CompileFormulaContext
& rCxt
)
3259 CompileAllHandler
aFunc(rCxt
);
3260 sc::ProcessFormula(maCells
, aFunc
);
3263 void ScColumn::CompileXML( sc::CompileFormulaContext
& rCxt
, ScProgress
& rProgress
)
3265 CompileXMLHandler
aFunc(rCxt
, rProgress
, *this);
3266 sc::ProcessFormula(maCells
, aFunc
);
3267 RegroupFormulaCells();
3270 bool ScColumn::CompileErrorCells( sc::CompileFormulaContext
& rCxt
, FormulaError nErrCode
)
3272 CompileErrorCellsHandler
aHdl(rCxt
, *this, nErrCode
);
3273 sc::ProcessFormula(maCells
, aHdl
);
3274 return aHdl
.isCompiled();
3277 void ScColumn::CalcAfterLoad( sc::CompileFormulaContext
& rCxt
, bool bStartListening
)
3279 CalcAfterLoadHandler
aFunc(rCxt
, bStartListening
);
3280 sc::ProcessFormula(maCells
, aFunc
);
3283 void ScColumn::ResetChanged( SCROW nStartRow
, SCROW nEndRow
)
3285 ResetChangedHandler aFunc
;
3286 sc::ProcessFormula(maCells
.begin(), maCells
, nStartRow
, nEndRow
, aFunc
);
3289 bool ScColumn::HasEditCells(SCROW nStartRow
, SCROW nEndRow
, SCROW
& rFirst
)
3291 // used in GetOptimalHeight - ambiguous script type counts as edit cell
3293 FindEditCellsHandler
aFunc(*this);
3294 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
=
3295 sc::FindFormulaEditText(maCells
, nStartRow
, nEndRow
, aFunc
);
3297 if (aPos
.first
== maCells
.end())
3300 rFirst
= aPos
.first
->position
+ aPos
.second
;
3304 SCROW
ScColumn::SearchStyle(
3305 SCROW nRow
, const ScStyleSheet
* pSearchStyle
, bool bUp
, bool bInSelection
,
3306 const ScMarkData
& rMark
) const
3310 if (rMark
.IsMultiMarked())
3312 ScMarkArray
aArray(rMark
.GetMarkArray(nCol
));
3313 return pAttrArray
->SearchStyle(nRow
, pSearchStyle
, bUp
, &aArray
);
3319 return pAttrArray
->SearchStyle( nRow
, pSearchStyle
, bUp
);
3322 bool ScColumn::SearchStyleRange(
3323 SCROW
& rRow
, SCROW
& rEndRow
, const ScStyleSheet
* pSearchStyle
, bool bUp
,
3324 bool bInSelection
, const ScMarkData
& rMark
) const
3328 if (rMark
.IsMultiMarked())
3330 ScMarkArray
aArray(rMark
.GetMarkArray(nCol
));
3331 return pAttrArray
->SearchStyleRange(
3332 rRow
, rEndRow
, pSearchStyle
, bUp
, &aArray
);
3338 return pAttrArray
->SearchStyleRange( rRow
, rEndRow
, pSearchStyle
, bUp
);
3341 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */