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"
23 #include "document.hxx"
24 #include "docpool.hxx"
25 #include "attarray.hxx"
26 #include "patattr.hxx"
27 #include "compiler.hxx"
29 #include "markdata.hxx"
30 #include "detfunc.hxx"
32 #include "globalnames.hxx"
33 #include "cellvalue.hxx"
34 #include "tokenarray.hxx"
35 #include "cellform.hxx"
36 #include "clipcontext.hxx"
38 #include "editutil.hxx"
39 #include "mtvcellfunc.hxx"
40 #include "columnspanset.hxx"
41 #include "scopetools.hxx"
42 #include "sharedformula.hxx"
43 #include "refupdatecontext.hxx"
44 #include <listenercontext.hxx>
45 #include <refhint.hxx>
46 #include <stlalgorithm.hxx>
47 #include <formulagroup.hxx>
49 #include <svl/poolcach.hxx>
50 #include <svl/zforlist.hxx>
51 #include <svl/sharedstringpool.hxx>
52 #include <editeng/scripttypeitem.hxx>
53 #include <editeng/fieldupdater.hxx>
54 #include <osl/diagnose.h>
59 #include <boost/checked_delete.hpp>
60 #include <boost/scoped_ptr.hpp>
62 using ::editeng::SvxBorderLine
;
63 using namespace formula
;
67 inline bool IsAmbiguousScriptNonZero( SvtScriptType nScript
)
69 //TODO: move to a header file
70 return ( nScript
!= SvtScriptType::LATIN
&&
71 nScript
!= SvtScriptType::ASIAN
&&
72 nScript
!= SvtScriptType::COMPLEX
&&
73 nScript
!= SvtScriptType::NONE
);
78 ScNeededSizeOptions::ScNeededSizeOptions() :
79 pPattern(NULL
), bFormula(false), bSkipMerged(true), bGetFont(true), bTotalSize(false)
83 ScColumn::ScColumn() :
84 maCellTextAttrs(MAXROWCOUNT
),
85 maCellNotes(MAXROWCOUNT
),
86 maBroadcasters(MAXROWCOUNT
),
102 void ScColumn::Init(SCCOL nNewCol
, SCTAB nNewTab
, ScDocument
* pDoc
)
107 pAttrArray
= new ScAttrArray( nCol
, nTab
, pDocument
);
110 SCsROW
ScColumn::GetNextUnprotected( SCROW nRow
, bool bUp
) const
112 return pAttrArray
->GetNextUnprotected(nRow
, bUp
);
115 sal_uInt16
ScColumn::GetBlockMatrixEdges( SCROW nRow1
, SCROW nRow2
, sal_uInt16 nMask
) const
119 if (!ValidRow(nRow1
) || !ValidRow(nRow2
) || nRow1
> nRow2
)
122 ScAddress
aOrigin(ScAddress::INITIALIZE_INVALID
);
126 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nRow1
);
127 if (aPos
.first
->type
!= sc::element_type_formula
)
130 const ScFormulaCell
* pCell
= sc::formula_block::at(*aPos
.first
->data
, aPos
.second
);
131 if (!pCell
->GetMatrixFlag())
134 return pCell
->GetMatrixEdge(aOrigin
);
138 sal_uInt16 nEdges
= 0;
140 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nRow1
);
141 sc::CellStoreType::const_iterator it
= aPos
.first
;
142 size_t nOffset
= aPos
.second
;
144 for (;it
!= maCells
.end() && nRow
<= nRow2
; ++it
, nOffset
= 0)
146 if (it
->type
!= sc::element_type_formula
)
149 nRow
+= it
->size
- nOffset
;
153 size_t nRowsToRead
= nRow2
- nRow
+ 1;
154 size_t nEnd
= std::min(it
->size
, nOffset
+nRowsToRead
); // last row + 1
155 sc::formula_block::const_iterator itCell
= sc::formula_block::begin(*it
->data
);
156 std::advance(itCell
, nOffset
);
157 for (size_t i
= nOffset
; i
< nEnd
; ++itCell
, ++i
)
159 // Loop inside the formula block.
160 const ScFormulaCell
* pCell
= *itCell
;
161 if (!pCell
->GetMatrixFlag())
164 nEdges
= pCell
->GetMatrixEdge(aOrigin
);
168 if (nEdges
& MatrixEdgeTop
)
169 bOpen
= true; // top edge opens, keep on looking
171 return nEdges
| MatrixEdgeOpen
; // there's something that wasn't opened
172 else if (nEdges
& MatrixEdgeInside
)
173 return nEdges
; // inside
174 // (nMask & 16 and (4 and not 16)) or
175 // (nMask & 4 and (16 and not 4))
176 if (((nMask
& MatrixEdgeRight
) && (nEdges
& MatrixEdgeLeft
) && !(nEdges
& MatrixEdgeRight
)) ||
177 ((nMask
& MatrixEdgeLeft
) && (nEdges
& MatrixEdgeRight
) && !(nEdges
& MatrixEdgeLeft
)))
178 return nEdges
; // only left/right edge
180 if (nEdges
& MatrixEdgeBottom
)
181 bOpen
= false; // bottom edge closes
187 nEdges
|= MatrixEdgeOpen
; // not closed, matrix continues
192 bool ScColumn::HasSelectionMatrixFragment(const ScMarkData
& rMark
) const
196 if (!rMark
.IsMultiMarked())
199 ScAddress
aOrigin(ScAddress::INITIALIZE_INVALID
);
200 ScAddress aCurOrigin
= aOrigin
;
203 ScRangeList aRanges
= rMark
.GetMarkedRanges();
204 for (size_t i
= 0, n
= aRanges
.size(); i
< n
; ++i
)
206 const ScRange
& r
= *aRanges
[i
];
207 if (nTab
< r
.aStart
.Tab() || r
.aEnd
.Tab() < nTab
)
210 if (nCol
< r
.aStart
.Col() || r
.aEnd
.Col() < nCol
)
213 SCROW nTop
= r
.aStart
.Row(), nBottom
= r
.aEnd
.Row();
215 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nRow
);
216 sc::CellStoreType::const_iterator it
= aPos
.first
;
217 size_t nOffset
= aPos
.second
;
219 for (;it
!= maCells
.end() && nRow
<= nBottom
; ++it
, nOffset
= 0)
221 if (it
->type
!= sc::element_type_formula
)
224 nRow
+= it
->size
- nOffset
;
228 // This is a formula cell block.
229 size_t nRowsToRead
= nBottom
- nRow
+ 1;
230 size_t nEnd
= std::min(it
->size
, nRowsToRead
);
231 sc::formula_block::const_iterator itCell
= sc::formula_block::begin(*it
->data
);
232 std::advance(itCell
, nOffset
);
233 for (size_t j
= nOffset
; j
< nEnd
; ++itCell
, ++j
)
235 // Loop inside the formula block.
236 const ScFormulaCell
* pCell
= *itCell
;
237 if (!pCell
->GetMatrixFlag())
238 // cell is not a part of a matrix.
241 sal_uInt16 nEdges
= pCell
->GetMatrixEdge(aOrigin
);
247 if (nEdges
& MatrixEdgeTop
)
248 bOpen
= true; // top edge opens, keep on looking
250 return true; // there's something that wasn't opened
251 else if (nEdges
& MatrixEdgeInside
)
252 bFound
= true; // inside, all selected?
254 if ((((nEdges
& MatrixEdgeLeft
) | MatrixEdgeRight
) ^ ((nEdges
& MatrixEdgeRight
) | MatrixEdgeLeft
)))
255 // either left or right, but not both.
256 bFound
= true; // only left/right edge, all selected?
258 if (nEdges
& MatrixEdgeBottom
)
259 bOpen
= false; // bottom edge closes
263 // Check if the matrix is inside the selection in its entirety.
265 // TODO: It's more efficient to skip the matrix range if
266 // it's within selection, to avoid checking it again and
269 if (aCurOrigin
!= aOrigin
)
270 { // new matrix to check?
271 aCurOrigin
= aOrigin
;
272 const ScFormulaCell
* pFCell
;
273 if (pCell
->GetMatrixFlag() == MM_REFERENCE
)
274 pFCell
= pDocument
->GetFormulaCell(aOrigin
);
280 pFCell
->GetMatColsRows(nC
, nR
);
281 ScRange
aRange(aOrigin
, ScAddress(aOrigin
.Col()+nC
-1, aOrigin
.Row()+nR
-1, aOrigin
.Tab()));
282 if (rMark
.IsAllMarked(aRange
))
286 bFound
= false; // done already
303 bool ScColumn::HasAttrib( SCROW nRow1
, SCROW nRow2
, sal_uInt16 nMask
) const
305 return pAttrArray
->HasAttrib( nRow1
, nRow2
, nMask
);
308 bool ScColumn::HasAttribSelection( const ScMarkData
& rMark
, sal_uInt16 nMask
) const
315 if (rMark
.IsMultiMarked())
317 ScMarkArrayIter
aMarkIter( rMark
.GetArray()+nCol
);
318 while (aMarkIter
.Next( nTop
, nBottom
) && !bFound
)
320 if (pAttrArray
->HasAttrib( nTop
, nBottom
, nMask
))
328 bool ScColumn::ExtendMerge( SCCOL nThisCol
, SCROW nStartRow
, SCROW nEndRow
,
329 SCCOL
& rPaintCol
, SCROW
& rPaintRow
,
332 return pAttrArray
->ExtendMerge( nThisCol
, nStartRow
, nEndRow
, rPaintCol
, rPaintRow
, bRefresh
);
335 void ScColumn::MergeSelectionPattern( ScMergePatternState
& rState
, const ScMarkData
& rMark
, bool bDeep
) const
340 if ( rMark
.IsMultiMarked() )
342 const ScMarkArray
* pArray
= rMark
.GetArray() + nCol
;
343 if ( pArray
->HasMarks() )
345 ScMarkArrayIter
aMarkIter( pArray
);
346 while (aMarkIter
.Next( nTop
, nBottom
))
347 pAttrArray
->MergePatternArea( nTop
, nBottom
, rState
, bDeep
);
352 void ScColumn::MergePatternArea( ScMergePatternState
& rState
, SCROW nRow1
, SCROW nRow2
, bool bDeep
) const
354 pAttrArray
->MergePatternArea( nRow1
, nRow2
, rState
, bDeep
);
357 void ScColumn::MergeBlockFrame( SvxBoxItem
* pLineOuter
, SvxBoxInfoItem
* pLineInner
,
359 SCROW nStartRow
, SCROW nEndRow
, bool bLeft
, SCCOL nDistRight
) const
361 pAttrArray
->MergeBlockFrame( pLineOuter
, pLineInner
, rFlags
, nStartRow
, nEndRow
, bLeft
, nDistRight
);
364 void ScColumn::ApplyBlockFrame( const SvxBoxItem
* pLineOuter
, const SvxBoxInfoItem
* pLineInner
,
365 SCROW nStartRow
, SCROW nEndRow
, bool bLeft
, SCCOL nDistRight
)
367 pAttrArray
->ApplyBlockFrame( pLineOuter
, pLineInner
, nStartRow
, nEndRow
, bLeft
, nDistRight
);
370 const ScPatternAttr
* ScColumn::GetPattern( SCROW nRow
) const
372 return pAttrArray
->GetPattern( nRow
);
375 const SfxPoolItem
* ScColumn::GetAttr( SCROW nRow
, sal_uInt16 nWhich
) const
377 return &pAttrArray
->GetPattern( nRow
)->GetItemSet().Get(nWhich
);
380 const ScPatternAttr
* ScColumn::GetMostUsedPattern( SCROW nStartRow
, SCROW nEndRow
) const
382 ::std::map
< const ScPatternAttr
*, size_t > aAttrMap
;
383 const ScPatternAttr
* pMaxPattern
= 0;
384 size_t nMaxCount
= 0;
386 ScAttrIterator
aAttrIter( pAttrArray
, nStartRow
, nEndRow
);
387 const ScPatternAttr
* pPattern
;
388 SCROW nAttrRow1
= 0, nAttrRow2
= 0;
390 while( (pPattern
= aAttrIter
.Next( nAttrRow1
, nAttrRow2
)) != 0 )
392 size_t& rnCount
= aAttrMap
[ pPattern
];
393 rnCount
+= (nAttrRow2
- nAttrRow1
+ 1);
394 if( rnCount
> nMaxCount
)
396 pMaxPattern
= pPattern
;
404 sal_uInt32
ScColumn::GetNumberFormat( SCROW nStartRow
, SCROW nEndRow
) const
406 SCROW nPatStartRow
, nPatEndRow
;
407 const ScPatternAttr
* pPattern
= pAttrArray
->GetPatternRange(nPatStartRow
, nPatEndRow
, nStartRow
);
408 sal_uInt32 nFormat
= pPattern
->GetNumberFormat(pDocument
->GetFormatTable());
409 while (nEndRow
> nPatEndRow
)
411 nStartRow
= nPatEndRow
+ 1;
412 pPattern
= pAttrArray
->GetPatternRange(nPatStartRow
, nPatEndRow
, nStartRow
);
413 sal_uInt32 nTmpFormat
= pPattern
->GetNumberFormat(pDocument
->GetFormatTable());
414 if (nFormat
!= nTmpFormat
)
420 sal_uInt32
ScColumn::GetNumberFormat( SCROW nRow
) const
422 return pAttrArray
->GetPattern( nRow
)->GetNumberFormat( pDocument
->GetFormatTable() );
425 SCsROW
ScColumn::ApplySelectionCache( SfxItemPoolCache
* pCache
, const ScMarkData
& rMark
, ScEditDataArray
* pDataArray
)
431 if ( rMark
.IsMultiMarked() )
433 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
434 while (aMarkIter
.Next( nTop
, nBottom
))
436 pAttrArray
->ApplyCacheArea( nTop
, nBottom
, pCache
, pDataArray
);
443 else if (nTop
==0 && nBottom
==MAXROW
)
449 void ScColumn::ChangeSelectionIndent( bool bIncrement
, const ScMarkData
& rMark
)
454 if ( pAttrArray
&& rMark
.IsMultiMarked() )
456 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
457 while (aMarkIter
.Next( nTop
, nBottom
))
458 pAttrArray
->ChangeIndent(nTop
, nBottom
, bIncrement
);
462 void ScColumn::ClearSelectionItems( const sal_uInt16
* pWhich
,const ScMarkData
& rMark
)
467 if ( pAttrArray
&& rMark
.IsMultiMarked() )
469 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
470 while (aMarkIter
.Next( nTop
, nBottom
))
471 pAttrArray
->ClearItems(nTop
, nBottom
, pWhich
);
475 void ScColumn::DeleteSelection( InsertDeleteFlags nDelFlag
, const ScMarkData
& rMark
, bool bBroadcast
)
480 if ( rMark
.IsMultiMarked() )
482 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
483 while (aMarkIter
.Next( nTop
, nBottom
))
484 DeleteArea(nTop
, nBottom
, nDelFlag
, bBroadcast
);
488 void ScColumn::ApplyPattern( SCROW nRow
, const ScPatternAttr
& rPatAttr
)
490 const SfxItemSet
* pSet
= &rPatAttr
.GetItemSet();
491 SfxItemPoolCache
aCache( pDocument
->GetPool(), pSet
);
493 const ScPatternAttr
* pPattern
= pAttrArray
->GetPattern( nRow
);
495 // true = keep old content
497 const ScPatternAttr
* pNewPattern
= static_cast<const ScPatternAttr
*>( &aCache
.ApplyTo( *pPattern
, true ) );
498 ScDocumentPool::CheckRef( *pPattern
);
499 ScDocumentPool::CheckRef( *pNewPattern
);
501 if (pNewPattern
!= pPattern
)
502 pAttrArray
->SetPattern( nRow
, pNewPattern
);
505 void ScColumn::ApplyPatternArea( SCROW nStartRow
, SCROW nEndRow
, const ScPatternAttr
& rPatAttr
,
506 ScEditDataArray
* pDataArray
)
508 const SfxItemSet
* pSet
= &rPatAttr
.GetItemSet();
509 SfxItemPoolCache
aCache( pDocument
->GetPool(), pSet
);
510 pAttrArray
->ApplyCacheArea( nStartRow
, nEndRow
, &aCache
, pDataArray
);
513 void ScColumn::ApplyPatternIfNumberformatIncompatible( const ScRange
& rRange
,
514 const ScPatternAttr
& rPattern
, short nNewType
)
516 const SfxItemSet
* pSet
= &rPattern
.GetItemSet();
517 SfxItemPoolCache
aCache( pDocument
->GetPool(), pSet
);
518 SvNumberFormatter
* pFormatter
= pDocument
->GetFormatTable();
519 SCROW nEndRow
= rRange
.aEnd
.Row();
520 for ( SCROW nRow
= rRange
.aStart
.Row(); nRow
<= nEndRow
; nRow
++ )
523 const ScPatternAttr
* pPattern
= pAttrArray
->GetPatternRange(
524 nRow1
, nRow2
, nRow
);
525 sal_uInt32 nFormat
= pPattern
->GetNumberFormat( pFormatter
);
526 short nOldType
= pFormatter
->GetType( nFormat
);
527 if ( nOldType
== nNewType
|| pFormatter
->IsCompatible( nOldType
, nNewType
) )
531 SCROW nNewRow1
= std::max( nRow1
, nRow
);
532 SCROW nNewRow2
= std::min( nRow2
, nEndRow
);
533 pAttrArray
->ApplyCacheArea( nNewRow1
, nNewRow2
, &aCache
);
539 void ScColumn::AddCondFormat( SCROW nStartRow
, SCROW nEndRow
, sal_uInt32 nIndex
)
541 pAttrArray
->AddCondFormat( nStartRow
, nEndRow
, nIndex
);
544 void ScColumn::RemoveCondFormat( SCROW nStartRow
, SCROW nEndRow
, sal_uInt32 nIndex
)
546 pAttrArray
->RemoveCondFormat( nStartRow
, nEndRow
, nIndex
);
549 void ScColumn::ApplyStyle( SCROW nRow
, const ScStyleSheet
& rStyle
)
551 const ScPatternAttr
* pPattern
= pAttrArray
->GetPattern(nRow
);
552 boost::scoped_ptr
<ScPatternAttr
> pNewPattern(new ScPatternAttr(*pPattern
));
555 pNewPattern
->SetStyleSheet(const_cast<ScStyleSheet
*>(&rStyle
));
556 pAttrArray
->SetPattern(nRow
, pNewPattern
.get(), true);
560 void ScColumn::ApplyStyleArea( SCROW nStartRow
, SCROW nEndRow
, const ScStyleSheet
& rStyle
)
562 pAttrArray
->ApplyStyleArea(nStartRow
, nEndRow
, const_cast<ScStyleSheet
*>(&rStyle
));
565 void ScColumn::ApplySelectionStyle(const ScStyleSheet
& rStyle
, const ScMarkData
& rMark
)
570 if ( rMark
.IsMultiMarked() )
572 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
573 while (aMarkIter
.Next( nTop
, nBottom
))
574 pAttrArray
->ApplyStyleArea(nTop
, nBottom
, const_cast<ScStyleSheet
*>(&rStyle
));
578 void ScColumn::ApplySelectionLineStyle( const ScMarkData
& rMark
,
579 const SvxBorderLine
* pLine
, bool bColorOnly
)
581 if ( bColorOnly
&& !pLine
)
587 if (rMark
.IsMultiMarked())
589 ScMarkArrayIter
aMarkIter( rMark
.GetArray()+nCol
);
590 while (aMarkIter
.Next( nTop
, nBottom
))
591 pAttrArray
->ApplyLineStyleArea(nTop
, nBottom
, pLine
, bColorOnly
);
595 const ScStyleSheet
* ScColumn::GetStyle( SCROW nRow
) const
597 return pAttrArray
->GetPattern( nRow
)->GetStyleSheet();
600 const ScStyleSheet
* ScColumn::GetSelectionStyle( const ScMarkData
& rMark
, bool& rFound
) const
603 if (!rMark
.IsMultiMarked())
605 OSL_FAIL("No selection in ScColumn::GetSelectionStyle");
611 const ScStyleSheet
* pStyle
= NULL
;
612 const ScStyleSheet
* pNewStyle
;
614 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
617 while (bEqual
&& aMarkIter
.Next( nTop
, nBottom
))
619 ScAttrIterator
aAttrIter( pAttrArray
, nTop
, nBottom
);
622 const ScPatternAttr
* pPattern
;
623 while (bEqual
&& ( pPattern
= aAttrIter
.Next( nRow
, nDummy
) ) != NULL
)
625 pNewStyle
= pPattern
->GetStyleSheet();
627 if ( !pNewStyle
|| ( pStyle
&& pNewStyle
!= pStyle
) )
628 bEqual
= false; // difference
633 return bEqual
? pStyle
: NULL
;
636 const ScStyleSheet
* ScColumn::GetAreaStyle( bool& rFound
, SCROW nRow1
, SCROW nRow2
) const
642 const ScStyleSheet
* pStyle
= NULL
;
643 const ScStyleSheet
* pNewStyle
;
645 ScAttrIterator
aAttrIter( pAttrArray
, nRow1
, nRow2
);
648 const ScPatternAttr
* pPattern
;
649 while (bEqual
&& ( pPattern
= aAttrIter
.Next( nRow
, nDummy
) ) != NULL
)
651 pNewStyle
= pPattern
->GetStyleSheet();
653 if ( !pNewStyle
|| ( pStyle
&& pNewStyle
!= pStyle
) )
654 bEqual
= false; // difference
658 return bEqual
? pStyle
: NULL
;
661 void ScColumn::FindStyleSheet( const SfxStyleSheetBase
* pStyleSheet
, ScFlatBoolRowSegments
& rUsedRows
, bool bReset
)
663 pAttrArray
->FindStyleSheet( pStyleSheet
, rUsedRows
, bReset
);
666 bool ScColumn::IsStyleSheetUsed( const ScStyleSheet
& rStyle
, bool bGatherAllStyles
) const
668 return pAttrArray
->IsStyleSheetUsed( rStyle
, bGatherAllStyles
);
671 bool ScColumn::ApplyFlags( SCROW nStartRow
, SCROW nEndRow
, sal_Int16 nFlags
)
673 return pAttrArray
->ApplyFlags( nStartRow
, nEndRow
, nFlags
);
676 bool ScColumn::RemoveFlags( SCROW nStartRow
, SCROW nEndRow
, sal_Int16 nFlags
)
678 return pAttrArray
->RemoveFlags( nStartRow
, nEndRow
, nFlags
);
681 void ScColumn::ClearItems( SCROW nStartRow
, SCROW nEndRow
, const sal_uInt16
* pWhich
)
683 pAttrArray
->ClearItems( nStartRow
, nEndRow
, pWhich
);
686 void ScColumn::SetPattern( SCROW nRow
, const ScPatternAttr
& rPatAttr
, bool bPutToPool
)
688 pAttrArray
->SetPattern( nRow
, &rPatAttr
, bPutToPool
);
691 void ScColumn::SetPatternArea( SCROW nStartRow
, SCROW nEndRow
,
692 const ScPatternAttr
& rPatAttr
, bool bPutToPool
)
694 pAttrArray
->SetPatternArea( nStartRow
, nEndRow
, &rPatAttr
, bPutToPool
);
697 void ScColumn::ApplyAttr( SCROW nRow
, const SfxPoolItem
& rAttr
)
699 // in order to only create a new SetItem, we don't need SfxItemPoolCache.
700 //TODO: Warning: SfxItemPoolCache seems to create to many Refs for the new SetItem ??
702 ScDocumentPool
* pDocPool
= pDocument
->GetPool();
704 const ScPatternAttr
* pOldPattern
= pAttrArray
->GetPattern( nRow
);
705 boost::scoped_ptr
<ScPatternAttr
> pTemp(new ScPatternAttr(*pOldPattern
));
706 pTemp
->GetItemSet().Put(rAttr
);
707 const ScPatternAttr
* pNewPattern
= static_cast<const ScPatternAttr
*>( &pDocPool
->Put( *pTemp
) );
709 if ( pNewPattern
!= pOldPattern
)
710 pAttrArray
->SetPattern( nRow
, pNewPattern
);
712 pDocPool
->Remove( *pNewPattern
); // free up resources
715 ScRefCellValue
ScColumn::GetCellValue( SCROW nRow
) const
717 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nRow
);
718 if (aPos
.first
== maCells
.end())
719 return ScRefCellValue();
721 return GetCellValue(aPos
.first
, aPos
.second
);
724 ScRefCellValue
ScColumn::GetCellValue( sc::ColumnBlockConstPosition
& rBlockPos
, SCROW nRow
) const
726 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(rBlockPos
.miCellPos
, nRow
);
727 if (aPos
.first
== maCells
.end())
728 return ScRefCellValue();
730 rBlockPos
.miCellPos
= aPos
.first
; // Store this for next call.
731 return GetCellValue(aPos
.first
, aPos
.second
);
734 ScRefCellValue
ScColumn::GetCellValue( const sc::CellStoreType::const_iterator
& itPos
, size_t nOffset
)
736 ScRefCellValue aVal
; // Defaults to empty cell.
739 case sc::element_type_numeric
:
741 aVal
.mfValue
= sc::numeric_block::at(*itPos
->data
, nOffset
);
742 aVal
.meType
= CELLTYPE_VALUE
;
744 case sc::element_type_string
:
746 aVal
.mpString
= &sc::string_block::at(*itPos
->data
, nOffset
);
747 aVal
.meType
= CELLTYPE_STRING
;
749 case sc::element_type_edittext
:
751 aVal
.mpEditText
= sc::edittext_block::at(*itPos
->data
, nOffset
);
752 aVal
.meType
= CELLTYPE_EDIT
;
754 case sc::element_type_formula
:
756 aVal
.mpFormula
= sc::formula_block::at(*itPos
->data
, nOffset
);
757 aVal
.meType
= CELLTYPE_FORMULA
;
766 const sc::CellTextAttr
* ScColumn::GetCellTextAttr( SCROW nRow
) const
768 sc::ColumnBlockConstPosition aBlockPos
;
769 aBlockPos
.miCellTextAttrPos
= maCellTextAttrs
.begin();
770 return GetCellTextAttr(aBlockPos
, nRow
);
773 const sc::CellTextAttr
* ScColumn::GetCellTextAttr( sc::ColumnBlockConstPosition
& rBlockPos
, SCROW nRow
) const
775 sc::CellTextAttrStoreType::const_position_type aPos
= maCellTextAttrs
.position(rBlockPos
.miCellTextAttrPos
, nRow
);
776 if (aPos
.first
== maCellTextAttrs
.end())
779 rBlockPos
.miCellTextAttrPos
= aPos
.first
;
781 if (aPos
.first
->type
!= sc::element_type_celltextattr
)
784 return &sc::celltextattr_block::at(*aPos
.first
->data
, aPos
.second
);
787 bool ScColumn::TestInsertCol( SCROW nStartRow
, SCROW nEndRow
) const
792 // Return false if we have any non-empty cells between nStartRow and nEndRow inclusive.
793 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nStartRow
);
794 sc::CellStoreType::const_iterator it
= aPos
.first
;
795 if (it
->type
!= sc::element_type_empty
)
798 // Get the length of the remaining empty segment.
799 size_t nLen
= it
->size
- aPos
.second
;
800 SCROW nNextNonEmptyRow
= nStartRow
+ nLen
;
801 if (nNextNonEmptyRow
<= nEndRow
)
804 // AttrArray only looks for merged cells
806 return pAttrArray
== nullptr || pAttrArray
->TestInsertCol(nStartRow
, nEndRow
);
809 bool ScColumn::TestInsertRow( SCROW nStartRow
, SCSIZE nSize
) const
811 // AttrArray only looks for merged cells
813 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nStartRow
);
814 sc::CellStoreType::const_iterator it
= aPos
.first
;
815 if (it
->type
== sc::element_type_empty
&& maCells
.block_size() == 1)
816 // The entire cell array is empty.
817 return pAttrArray
->TestInsertRow(nSize
);
820 // See if there would be any non-empty cell that gets pushed out.
822 // Find the position of the last non-empty cell below nStartRow.
823 size_t nLastNonEmptyRow
= MAXROW
;
824 sc::CellStoreType::const_reverse_iterator it
= maCells
.rbegin();
825 if (it
->type
== sc::element_type_empty
)
826 nLastNonEmptyRow
-= it
->size
;
828 if (nLastNonEmptyRow
< static_cast<size_t>(nStartRow
))
829 // No cells would get pushed out.
830 return pAttrArray
->TestInsertRow(nSize
);
832 if (nLastNonEmptyRow
+ nSize
> static_cast<size_t>(MAXROW
))
833 // At least one cell would get pushed out. Not good.
836 return pAttrArray
->TestInsertRow(nSize
);
839 void ScColumn::InsertRow( SCROW nStartRow
, SCSIZE nSize
)
841 pAttrArray
->InsertRow( nStartRow
, nSize
);
843 maCellNotes
.insert_empty(nStartRow
, nSize
);
844 maCellNotes
.resize(MAXROWCOUNT
);
846 maBroadcasters
.insert_empty(nStartRow
, nSize
);
847 maBroadcasters
.resize(MAXROWCOUNT
);
849 maCellTextAttrs
.insert_empty(nStartRow
, nSize
);
850 maCellTextAttrs
.resize(MAXROWCOUNT
);
852 maCells
.insert_empty(nStartRow
, nSize
);
853 maCells
.resize(MAXROWCOUNT
);
855 CellStorageModified();
857 // We *probably* don't need to broadcast here since the parent call seems
858 // to take care of it.
863 class CopyToClipHandler
865 const ScColumn
& mrSrcCol
;
867 sc::ColumnBlockPosition maDestPos
;
868 sc::ColumnBlockPosition
* mpDestPos
;
871 void setDefaultAttrsToDest(size_t nRow
, size_t nSize
)
873 std::vector
<sc::CellTextAttr
> aAttrs(nSize
); // default values
874 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set(
875 maDestPos
.miCellTextAttrPos
, nRow
, aAttrs
.begin(), aAttrs
.end());
878 void duplicateNotes(SCROW nStartRow
, size_t nDataSize
)
880 mrSrcCol
.DuplicateNotes(nStartRow
, nDataSize
, mrDestCol
, maDestPos
, false);
884 CopyToClipHandler(const ScColumn
& rSrcCol
, ScColumn
& rDestCol
, sc::ColumnBlockPosition
* pDestPos
, bool bCopyNotes
) :
885 mrSrcCol(rSrcCol
), mrDestCol(rDestCol
), mpDestPos(pDestPos
), mbCopyNotes(bCopyNotes
)
888 maDestPos
= *mpDestPos
;
890 mrDestCol
.InitBlockPosition(maDestPos
);
896 *mpDestPos
= maDestPos
;
899 void operator() (const sc::CellStoreType::value_type
& aNode
, size_t nOffset
, size_t nDataSize
)
901 size_t nTopRow
= aNode
.position
+ nOffset
;
907 case sc::element_type_numeric
:
909 sc::numeric_block::const_iterator it
= sc::numeric_block::begin(*aNode
.data
);
910 std::advance(it
, nOffset
);
911 sc::numeric_block::const_iterator itEnd
= it
;
912 std::advance(itEnd
, nDataSize
);
913 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nTopRow
, it
, itEnd
);
916 case sc::element_type_string
:
918 sc::string_block::const_iterator it
= sc::string_block::begin(*aNode
.data
);
919 std::advance(it
, nOffset
);
920 sc::string_block::const_iterator itEnd
= it
;
921 std::advance(itEnd
, nDataSize
);
922 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nTopRow
, it
, itEnd
);
926 case sc::element_type_edittext
:
928 sc::edittext_block::const_iterator it
= sc::edittext_block::begin(*aNode
.data
);
929 std::advance(it
, nOffset
);
930 sc::edittext_block::const_iterator itEnd
= it
;
931 std::advance(itEnd
, nDataSize
);
933 std::vector
<EditTextObject
*> aCloned
;
934 aCloned
.reserve(nDataSize
);
935 for (; it
!= itEnd
; ++it
)
936 aCloned
.push_back(ScEditUtil::Clone(**it
, mrDestCol
.GetDoc()));
938 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(
939 maDestPos
.miCellPos
, nTopRow
, aCloned
.begin(), aCloned
.end());
942 case sc::element_type_formula
:
944 sc::formula_block::const_iterator it
= sc::formula_block::begin(*aNode
.data
);
945 std::advance(it
, nOffset
);
946 sc::formula_block::const_iterator itEnd
= it
;
947 std::advance(itEnd
, nDataSize
);
949 std::vector
<ScFormulaCell
*> aCloned
;
950 aCloned
.reserve(nDataSize
);
951 ScAddress
aDestPos(mrDestCol
.GetCol(), nTopRow
, mrDestCol
.GetTab());
952 for (; it
!= itEnd
; ++it
, aDestPos
.IncRow())
954 const ScFormulaCell
& rOld
= **it
;
955 if (rOld
.GetDirty() && mrSrcCol
.GetDoc().GetAutoCalc())
956 const_cast<ScFormulaCell
&>(rOld
).Interpret();
958 aCloned
.push_back(new ScFormulaCell(rOld
, mrDestCol
.GetDoc(), aDestPos
));
961 // Group the cloned formula cells.
962 if (!aCloned
.empty())
963 sc::SharedFormulaUtil::groupFormulaCells(aCloned
.begin(), aCloned
.end());
965 sc::CellStoreType
& rDestCells
= mrDestCol
.GetCellStore();
966 maDestPos
.miCellPos
= rDestCells
.set(
967 maDestPos
.miCellPos
, nTopRow
, aCloned
.begin(), aCloned
.end());
969 // Merge adjacent formula cell groups (if applicable).
970 sc::CellStoreType::position_type aPos
=
971 rDestCells
.position(maDestPos
.miCellPos
, nTopRow
);
972 maDestPos
.miCellPos
= aPos
.first
;
973 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
974 size_t nLastRow
= nTopRow
+ nDataSize
;
975 if (nLastRow
< static_cast<size_t>(MAXROW
))
977 aPos
= rDestCells
.position(maDestPos
.miCellPos
, nLastRow
+1);
978 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
987 setDefaultAttrsToDest(nTopRow
, nDataSize
);
990 duplicateNotes(nTopRow
, nDataSize
);
994 class CopyTextAttrToClipHandler
996 sc::CellTextAttrStoreType
& mrDestAttrs
;
997 sc::CellTextAttrStoreType::iterator miPos
;
1000 CopyTextAttrToClipHandler( sc::CellTextAttrStoreType
& rAttrs
) :
1001 mrDestAttrs(rAttrs
), miPos(mrDestAttrs
.begin()) {}
1003 void operator() ( const sc::CellTextAttrStoreType::value_type
& aNode
, size_t nOffset
, size_t nDataSize
)
1005 if (aNode
.type
!= sc::element_type_celltextattr
)
1008 sc::celltextattr_block::const_iterator it
= sc::celltextattr_block::begin(*aNode
.data
);
1009 std::advance(it
, nOffset
);
1010 sc::celltextattr_block::const_iterator itEnd
= it
;
1011 std::advance(itEnd
, nDataSize
);
1013 size_t nPos
= aNode
.position
+ nOffset
;
1014 miPos
= mrDestAttrs
.set(miPos
, nPos
, it
, itEnd
);
1021 void ScColumn::CopyToClip(
1022 sc::CopyToClipContext
& rCxt
, SCROW nRow1
, SCROW nRow2
, ScColumn
& rColumn
) const
1024 pAttrArray
->CopyArea( nRow1
, nRow2
, 0, *rColumn
.pAttrArray
,
1025 rCxt
.isKeepScenarioFlags() ? (SC_MF_ALL
& ~SC_MF_SCENARIO
) : SC_MF_ALL
);
1028 CopyToClipHandler
aFunc(*this, rColumn
, rCxt
.getBlockPosition(rColumn
.nTab
, rColumn
.nCol
), rCxt
.isCloneNotes());
1029 sc::ParseBlock(maCells
.begin(), maCells
, aFunc
, nRow1
, nRow2
);
1033 CopyTextAttrToClipHandler
aFunc(rColumn
.maCellTextAttrs
);
1034 sc::ParseBlock(maCellTextAttrs
.begin(), maCellTextAttrs
, aFunc
, nRow1
, nRow2
);
1037 rColumn
.CellStorageModified();
1040 void ScColumn::CopyStaticToDocument(
1041 SCROW nRow1
, SCROW nRow2
, const SvNumberFormatterMergeMap
& rMap
, ScColumn
& rDestCol
)
1046 sc::ColumnBlockPosition aDestPos
;
1047 CopyCellTextAttrsToDocument(nRow1
, nRow2
, rDestCol
);
1048 CopyCellNotesToDocument(nRow1
, nRow2
, rDestCol
);
1050 // First, clear the destination column for the specified row range.
1051 rDestCol
.maCells
.set_empty(nRow1
, nRow2
);
1053 aDestPos
.miCellPos
= rDestCol
.maCells
.begin();
1055 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nRow1
);
1056 sc::CellStoreType::const_iterator it
= aPos
.first
;
1057 size_t nOffset
= aPos
.second
;
1058 size_t nDataSize
= 0;
1059 size_t nCurRow
= nRow1
;
1061 for (; it
!= maCells
.end() && nCurRow
<= static_cast<size_t>(nRow2
); ++it
, nOffset
= 0, nCurRow
+= nDataSize
)
1063 bool bLastBlock
= false;
1064 nDataSize
= it
->size
- nOffset
;
1065 if (nCurRow
+ nDataSize
- 1 > static_cast<size_t>(nRow2
))
1067 // Truncate the block to copy to clipboard.
1068 nDataSize
= nRow2
- nCurRow
+ 1;
1074 case sc::element_type_numeric
:
1076 sc::numeric_block::const_iterator itData
= sc::numeric_block::begin(*it
->data
);
1077 std::advance(itData
, nOffset
);
1078 sc::numeric_block::const_iterator itDataEnd
= itData
;
1079 std::advance(itDataEnd
, nDataSize
);
1080 aDestPos
.miCellPos
= rDestCol
.maCells
.set(aDestPos
.miCellPos
, nCurRow
, itData
, itDataEnd
);
1083 case sc::element_type_string
:
1085 sc::string_block::const_iterator itData
= sc::string_block::begin(*it
->data
);
1086 std::advance(itData
, nOffset
);
1087 sc::string_block::const_iterator itDataEnd
= itData
;
1088 std::advance(itDataEnd
, nDataSize
);
1089 aDestPos
.miCellPos
= rDestCol
.maCells
.set(aDestPos
.miCellPos
, nCurRow
, itData
, itDataEnd
);
1092 case sc::element_type_edittext
:
1094 sc::edittext_block::const_iterator itData
= sc::edittext_block::begin(*it
->data
);
1095 std::advance(itData
, nOffset
);
1096 sc::edittext_block::const_iterator itDataEnd
= itData
;
1097 std::advance(itDataEnd
, nDataSize
);
1099 // Convert to simple strings.
1100 std::vector
<svl::SharedString
> aConverted
;
1101 aConverted
.reserve(nDataSize
);
1102 for (; itData
!= itDataEnd
; ++itData
)
1104 const EditTextObject
& rObj
= **itData
;
1105 svl::SharedString aSS
= pDocument
->GetSharedStringPool().intern(ScEditUtil::GetString(rObj
, pDocument
));
1106 aConverted
.push_back(aSS
);
1108 aDestPos
.miCellPos
= rDestCol
.maCells
.set(aDestPos
.miCellPos
, nCurRow
, aConverted
.begin(), aConverted
.end());
1111 case sc::element_type_formula
:
1113 sc::formula_block::const_iterator itData
= sc::formula_block::begin(*it
->data
);
1114 std::advance(itData
, nOffset
);
1115 sc::formula_block::const_iterator itDataEnd
= itData
;
1116 std::advance(itDataEnd
, nDataSize
);
1118 // Interpret and convert to raw values.
1119 for (SCROW i
= 0; itData
!= itDataEnd
; ++itData
, ++i
)
1121 SCROW nRow
= nCurRow
+ i
;
1123 ScFormulaCell
& rFC
= const_cast<ScFormulaCell
&>(**itData
);
1124 if (rFC
.GetDirty() && pDocument
->GetAutoCalc())
1127 if (rFC
.GetErrCode())
1128 // Skip cells with error.
1132 aDestPos
.miCellPos
= rDestCol
.maCells
.set(aDestPos
.miCellPos
, nRow
, rFC
.GetValue());
1135 svl::SharedString aSS
= rFC
.GetString();
1137 aDestPos
.miCellPos
= rDestCol
.maCells
.set(aDestPos
.miCellPos
, nRow
, aSS
);
1150 // Dont' forget to copy the number formats over. Charts may reference them.
1151 for (SCROW nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
1153 sal_uInt32 nNumFmt
= GetNumberFormat(nRow
);
1154 SvNumberFormatterMergeMap::const_iterator itNum
= rMap
.find(nNumFmt
);
1155 if (itNum
!= rMap
.end())
1156 nNumFmt
= itNum
->second
;
1158 rDestCol
.SetNumberFormat(nRow
, nNumFmt
);
1161 rDestCol
.CellStorageModified();
1164 void ScColumn::CopyCellToDocument( SCROW nSrcRow
, SCROW nDestRow
, ScColumn
& rDestCol
)
1166 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nSrcRow
);
1167 sc::CellStoreType::const_iterator it
= aPos
.first
;
1171 case sc::element_type_numeric
:
1172 rDestCol
.maCells
.set(nDestRow
, sc::numeric_block::at(*it
->data
, aPos
.second
));
1174 case sc::element_type_string
:
1175 rDestCol
.maCells
.set(nDestRow
, sc::string_block::at(*it
->data
, aPos
.second
));
1177 case sc::element_type_edittext
:
1179 EditTextObject
* p
= sc::edittext_block::at(*it
->data
, aPos
.second
);
1180 if (pDocument
== rDestCol
.pDocument
)
1181 rDestCol
.maCells
.set(nDestRow
, p
->Clone());
1183 rDestCol
.maCells
.set(nDestRow
, ScEditUtil::Clone(*p
, *rDestCol
.pDocument
));
1186 case sc::element_type_formula
:
1188 ScFormulaCell
* p
= sc::formula_block::at(*it
->data
, aPos
.second
);
1189 if (p
->GetDirty() && pDocument
->GetAutoCalc())
1192 ScAddress aDestPos
= p
->aPos
;
1193 aDestPos
.SetRow(nDestRow
);
1194 ScFormulaCell
* pNew
= new ScFormulaCell(*p
, *rDestCol
.pDocument
, aDestPos
);
1195 rDestCol
.SetFormulaCell(nDestRow
, pNew
);
1198 case sc::element_type_empty
:
1201 rDestCol
.maCells
.set_empty(nDestRow
, nDestRow
);
1207 rDestCol
.maCellTextAttrs
.set(nDestRow
, maCellTextAttrs
.get
<sc::CellTextAttr
>(nSrcRow
));
1208 ScPostIt
* pNote
= maCellNotes
.get
<ScPostIt
*>(nSrcRow
);
1209 rDestCol
.maCellNotes
.set(nDestRow
, pNote
);
1211 pNote
->UpdateCaptionPos(ScAddress(rDestCol
.nCol
, nDestRow
, rDestCol
.nTab
));
1215 rDestCol
.maCellTextAttrs
.set_empty(nDestRow
, nDestRow
);
1216 rDestCol
.maCellNotes
.set_empty(nDestRow
, nDestRow
);
1219 rDestCol
.CellStorageModified();
1224 bool canCopyValue(const ScDocument
& rDoc
, const ScAddress
& rPos
, InsertDeleteFlags nFlags
)
1226 sal_uInt32 nNumIndex
= static_cast<const SfxUInt32Item
*>(rDoc
.GetAttr(rPos
, ATTR_VALUE_FORMAT
))->GetValue();
1227 short nType
= rDoc
.GetFormatTable()->GetType(nNumIndex
);
1228 if ((nType
== css::util::NumberFormat::DATE
) || (nType
== css::util::NumberFormat::TIME
) || (nType
== css::util::NumberFormat::DATETIME
))
1229 return ((nFlags
& IDF_DATETIME
) != IDF_NONE
);
1231 return (nFlags
& IDF_VALUE
) != IDF_NONE
;
1234 class CopyAsLinkHandler
1236 const ScColumn
& mrSrcCol
;
1237 ScColumn
& mrDestCol
;
1238 sc::ColumnBlockPosition maDestPos
;
1239 sc::ColumnBlockPosition
* mpDestPos
;
1240 InsertDeleteFlags mnCopyFlags
;
1242 sc::StartListeningType meListenType
;
1244 void setDefaultAttrToDest(size_t nRow
)
1246 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set(
1247 maDestPos
.miCellTextAttrPos
, nRow
, sc::CellTextAttr());
1250 void setDefaultAttrsToDest(size_t nRow
, size_t nSize
)
1252 std::vector
<sc::CellTextAttr
> aAttrs(nSize
); // default values
1253 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set(
1254 maDestPos
.miCellTextAttrPos
, nRow
, aAttrs
.begin(), aAttrs
.end());
1257 ScFormulaCell
* createRefCell(size_t nRow
)
1259 ScSingleRefData aRef
;
1260 aRef
.InitAddress(ScAddress(mrSrcCol
.GetCol(), nRow
, mrSrcCol
.GetTab())); // Absolute reference.
1261 aRef
.SetFlag3D(true);
1264 aArr
.AddSingleReference(aRef
);
1265 return new ScFormulaCell(&mrDestCol
.GetDoc(), ScAddress(mrDestCol
.GetCol(), nRow
, mrDestCol
.GetTab()), aArr
);
1268 void createRefBlock(const sc::CellStoreType::value_type
& aNode
, size_t nOffset
, size_t nDataSize
)
1270 size_t nTopRow
= aNode
.position
+ nOffset
;
1272 for (size_t i
= 0; i
< nDataSize
; ++i
)
1274 SCROW nRow
= nTopRow
+ i
;
1275 mrDestCol
.SetFormulaCell(maDestPos
, nRow
, createRefCell(nRow
), meListenType
);
1278 setDefaultAttrsToDest(nTopRow
, nDataSize
);
1281 void duplicateNotes(SCROW nStartRow
, size_t nDataSize
, bool bCloneCaption
)
1283 mrSrcCol
.DuplicateNotes(nStartRow
, nDataSize
, mrDestCol
, maDestPos
, bCloneCaption
);
1287 CopyAsLinkHandler(const ScColumn
& rSrcCol
, ScColumn
& rDestCol
, sc::ColumnBlockPosition
* pDestPos
, InsertDeleteFlags nCopyFlags
) :
1289 mrDestCol(rDestCol
),
1290 mpDestPos(pDestPos
),
1291 mnCopyFlags(nCopyFlags
),
1292 meListenType(sc::SingleCellListening
)
1295 maDestPos
= *mpDestPos
;
1298 ~CopyAsLinkHandler()
1301 *mpDestPos
= maDestPos
;
1304 void setStartListening( bool b
)
1306 meListenType
= b
? sc::SingleCellListening
: sc::NoListening
;
1309 void operator() (const sc::CellStoreType::value_type
& aNode
, size_t nOffset
, size_t nDataSize
)
1311 size_t nRow
= aNode
.position
+ nOffset
;
1313 if (mnCopyFlags
& (IDF_NOTE
|IDF_ADDNOTES
))
1315 bool bCloneCaption
= (mnCopyFlags
& IDF_NOCAPTIONS
) == IDF_NONE
;
1316 duplicateNotes(nRow
, nDataSize
, bCloneCaption
);
1321 case sc::element_type_numeric
:
1323 if ((mnCopyFlags
& (IDF_DATETIME
|IDF_VALUE
)) == IDF_NONE
)
1326 sc::numeric_block::const_iterator it
= sc::numeric_block::begin(*aNode
.data
);
1327 std::advance(it
, nOffset
);
1328 sc::numeric_block::const_iterator itEnd
= it
;
1329 std::advance(itEnd
, nDataSize
);
1331 ScAddress
aSrcPos(mrSrcCol
.GetCol(), nRow
, mrSrcCol
.GetTab());
1332 for (; it
!= itEnd
; ++it
, aSrcPos
.IncRow(), ++nRow
)
1334 if (!canCopyValue(mrSrcCol
.GetDoc(), aSrcPos
, mnCopyFlags
))
1337 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nRow
, createRefCell(nRow
));
1338 setDefaultAttrToDest(nRow
);
1342 case sc::element_type_string
:
1343 case sc::element_type_edittext
:
1345 if (!(mnCopyFlags
& IDF_STRING
))
1348 createRefBlock(aNode
, nOffset
, nDataSize
);
1351 case sc::element_type_formula
:
1353 if (!(mnCopyFlags
& IDF_FORMULA
))
1356 createRefBlock(aNode
, nOffset
, nDataSize
);
1365 class CopyByCloneHandler
1367 const ScColumn
& mrSrcCol
;
1368 ScColumn
& mrDestCol
;
1369 sc::ColumnBlockPosition maDestPos
;
1370 sc::ColumnBlockPosition
* mpDestPos
;
1371 svl::SharedStringPool
* mpSharedStringPool
;
1372 InsertDeleteFlags mnCopyFlags
;
1374 sc::StartListeningType meListenType
;
1376 void setDefaultAttrToDest(size_t nRow
)
1378 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set(
1379 maDestPos
.miCellTextAttrPos
, nRow
, sc::CellTextAttr());
1382 void setDefaultAttrsToDest(size_t nRow
, size_t nSize
)
1384 std::vector
<sc::CellTextAttr
> aAttrs(nSize
); // default values
1385 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set(
1386 maDestPos
.miCellTextAttrPos
, nRow
, aAttrs
.begin(), aAttrs
.end());
1389 void cloneFormulaCell(size_t nRow
, ScFormulaCell
& rSrcCell
)
1391 ScAddress
aDestPos(mrDestCol
.GetCol(), nRow
, mrDestCol
.GetTab());
1393 bool bCloneValue
= (mnCopyFlags
& IDF_VALUE
) != IDF_NONE
;
1394 bool bCloneDateTime
= (mnCopyFlags
& IDF_DATETIME
) != IDF_NONE
;
1395 bool bCloneString
= (mnCopyFlags
& IDF_STRING
) != IDF_NONE
;
1396 bool bCloneSpecialBoolean
= (mnCopyFlags
& IDF_SPECIAL_BOOLEAN
) != IDF_NONE
;
1397 bool bCloneFormula
= (mnCopyFlags
& IDF_FORMULA
) != IDF_NONE
;
1399 bool bForceFormula
= false;
1401 if (bCloneSpecialBoolean
)
1403 // See if the formula consists of =TRUE() or =FALSE().
1404 ScTokenArray
* pCode
= rSrcCell
.GetCode();
1405 if (pCode
&& pCode
->GetLen() == 1)
1407 const formula::FormulaToken
* p
= pCode
->First();
1408 if (p
->GetOpCode() == ocTrue
|| p
->GetOpCode() == ocFalse
)
1409 // This is a boolean formula.
1410 bForceFormula
= true;
1414 if (bForceFormula
|| bCloneFormula
)
1416 // Clone as formula cell.
1417 ScFormulaCell
* pCell
= new ScFormulaCell(rSrcCell
, mrDestCol
.GetDoc(), aDestPos
);
1418 pCell
->SetDirtyVar();
1419 mrDestCol
.SetFormulaCell(maDestPos
, nRow
, pCell
, meListenType
);
1420 setDefaultAttrToDest(nRow
);
1424 if (mrDestCol
.GetDoc().IsUndo())
1429 sal_uInt16 nErr
= rSrcCell
.GetErrCode();
1432 // error codes are cloned with values
1433 ScFormulaCell
* pErrCell
= new ScFormulaCell(&mrDestCol
.GetDoc(), aDestPos
);
1434 pErrCell
->SetErrCode(nErr
);
1435 mrDestCol
.SetFormulaCell(maDestPos
, nRow
, pErrCell
, meListenType
);
1436 setDefaultAttrToDest(nRow
);
1441 if (bCloneValue
|| bCloneDateTime
)
1443 if (rSrcCell
.IsValue())
1445 if (canCopyValue(mrSrcCol
.GetDoc(), ScAddress(mrSrcCol
.GetCol(), nRow
, mrSrcCol
.GetTab()), mnCopyFlags
))
1447 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(
1448 maDestPos
.miCellPos
, nRow
, rSrcCell
.GetValue());
1449 setDefaultAttrToDest(nRow
);
1458 svl::SharedString aStr
= rSrcCell
.GetString();
1460 // Don't create empty string cells.
1463 if (rSrcCell
.IsMultilineResult())
1465 // Clone as an edit text object.
1466 EditEngine
& rEngine
= mrDestCol
.GetDoc().GetEditEngine();
1467 rEngine
.SetText(aStr
.getString());
1468 maDestPos
.miCellPos
=
1469 mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nRow
, rEngine
.CreateTextObject());
1473 maDestPos
.miCellPos
=
1474 mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nRow
, aStr
);
1477 setDefaultAttrToDest(nRow
);
1481 void duplicateNotes(SCROW nStartRow
, size_t nDataSize
, bool bCloneCaption
)
1483 mrSrcCol
.DuplicateNotes(nStartRow
, nDataSize
, mrDestCol
, maDestPos
, bCloneCaption
);
1487 CopyByCloneHandler(const ScColumn
& rSrcCol
, ScColumn
& rDestCol
, sc::ColumnBlockPosition
* pDestPos
,
1488 InsertDeleteFlags nCopyFlags
, svl::SharedStringPool
* pSharedStringPool
) :
1490 mrDestCol(rDestCol
),
1491 mpDestPos(pDestPos
),
1492 mpSharedStringPool(pSharedStringPool
),
1493 mnCopyFlags(nCopyFlags
),
1494 meListenType(sc::SingleCellListening
)
1497 maDestPos
= *mpDestPos
;
1500 ~CopyByCloneHandler()
1503 *mpDestPos
= maDestPos
;
1506 void setStartListening( bool b
)
1508 meListenType
= b
? sc::SingleCellListening
: sc::NoListening
;
1511 void operator() (const sc::CellStoreType::value_type
& aNode
, size_t nOffset
, size_t nDataSize
)
1513 size_t nRow
= aNode
.position
+ nOffset
;
1515 if (mnCopyFlags
& (IDF_NOTE
|IDF_ADDNOTES
))
1517 bool bCloneCaption
= (mnCopyFlags
& IDF_NOCAPTIONS
) == IDF_NONE
;
1518 duplicateNotes(nRow
, nDataSize
, bCloneCaption
);
1523 case sc::element_type_numeric
:
1525 if ((mnCopyFlags
& (IDF_DATETIME
|IDF_VALUE
)) == IDF_NONE
)
1528 sc::numeric_block::const_iterator it
= sc::numeric_block::begin(*aNode
.data
);
1529 std::advance(it
, nOffset
);
1530 sc::numeric_block::const_iterator itEnd
= it
;
1531 std::advance(itEnd
, nDataSize
);
1533 ScAddress
aSrcPos(mrSrcCol
.GetCol(), nRow
, mrSrcCol
.GetTab());
1534 for (; it
!= itEnd
; ++it
, aSrcPos
.IncRow(), ++nRow
)
1536 if (!canCopyValue(mrSrcCol
.GetDoc(), aSrcPos
, mnCopyFlags
))
1539 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nRow
, *it
);
1540 setDefaultAttrToDest(nRow
);
1544 case sc::element_type_string
:
1546 if (!(mnCopyFlags
& IDF_STRING
))
1549 sc::string_block::const_iterator it
= sc::string_block::begin(*aNode
.data
);
1550 std::advance(it
, nOffset
);
1551 sc::string_block::const_iterator itEnd
= it
;
1552 std::advance(itEnd
, nDataSize
);
1554 for (; it
!= itEnd
; ++it
, ++nRow
)
1556 const svl::SharedString
& rStr
= *it
;
1559 // String cell with empty value is used to special-case cell value removal.
1560 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set_empty(
1561 maDestPos
.miCellPos
, nRow
, nRow
);
1562 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set_empty(
1563 maDestPos
.miCellTextAttrPos
, nRow
, nRow
);
1567 if (mpSharedStringPool
)
1569 // Re-intern the string if source is a different document.
1570 svl::SharedString aInterned
= mpSharedStringPool
->intern( rStr
.getString());
1571 maDestPos
.miCellPos
=
1572 mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nRow
, aInterned
);
1576 maDestPos
.miCellPos
=
1577 mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nRow
, rStr
);
1579 setDefaultAttrToDest(nRow
);
1584 case sc::element_type_edittext
:
1586 if (!(mnCopyFlags
& IDF_STRING
))
1589 sc::edittext_block::const_iterator it
= sc::edittext_block::begin(*aNode
.data
);
1590 std::advance(it
, nOffset
);
1591 sc::edittext_block::const_iterator itEnd
= it
;
1592 std::advance(itEnd
, nDataSize
);
1594 std::vector
<EditTextObject
*> aCloned
;
1595 aCloned
.reserve(nDataSize
);
1596 for (; it
!= itEnd
; ++it
)
1597 aCloned
.push_back(ScEditUtil::Clone(**it
, mrDestCol
.GetDoc()));
1599 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(
1600 maDestPos
.miCellPos
, nRow
, aCloned
.begin(), aCloned
.end());
1602 setDefaultAttrsToDest(nRow
, nDataSize
);
1605 case sc::element_type_formula
:
1607 sc::formula_block::const_iterator it
= sc::formula_block::begin(*aNode
.data
);
1608 std::advance(it
, nOffset
);
1609 sc::formula_block::const_iterator itEnd
= it
;
1610 std::advance(itEnd
, nDataSize
);
1612 for (; it
!= itEnd
; ++it
, ++nRow
)
1613 cloneFormulaCell(nRow
, const_cast<ScFormulaCell
&>(**it
));
1624 void ScColumn::CopyToColumn(
1625 sc::CopyToDocContext
& rCxt
,
1626 SCROW nRow1
, SCROW nRow2
, InsertDeleteFlags nFlags
, bool bMarked
, ScColumn
& rColumn
,
1627 const ScMarkData
* pMarkData
, bool bAsLink
) const
1632 if (pMarkData
&& pMarkData
->IsMultiMarked())
1634 ScMarkArrayIter
aIter( pMarkData
->GetArray()+nCol
);
1636 while ( aIter
.Next( nStart
, nEnd
) && nStart
<= nRow2
)
1638 if ( nEnd
>= nRow1
)
1639 CopyToColumn(rCxt
, std::max(nRow1
,nStart
), std::min(nRow2
,nEnd
),
1640 nFlags
, false, rColumn
, pMarkData
, bAsLink
);
1645 OSL_FAIL("CopyToColumn: bMarked, but no mark");
1650 if ( (nFlags
& IDF_ATTRIB
) != IDF_NONE
)
1652 if ( (nFlags
& IDF_STYLES
) != IDF_STYLES
)
1653 { // keep the StyleSheets in the target document
1654 // e.g. DIF and RTF Clipboard-Import
1655 for ( SCROW nRow
= nRow1
; nRow
<= nRow2
; nRow
++ )
1657 const ScStyleSheet
* pStyle
=
1658 rColumn
.pAttrArray
->GetPattern( nRow
)->GetStyleSheet();
1659 const ScPatternAttr
* pPattern
= pAttrArray
->GetPattern( nRow
);
1660 boost::scoped_ptr
<ScPatternAttr
> pNewPattern(new ScPatternAttr( *pPattern
));
1661 pNewPattern
->SetStyleSheet( const_cast<ScStyleSheet
*>(pStyle
) );
1662 rColumn
.pAttrArray
->SetPattern( nRow
, pNewPattern
.get(), true );
1666 pAttrArray
->CopyArea( nRow1
, nRow2
, 0, *rColumn
.pAttrArray
);
1669 if ((nFlags
& IDF_CONTENTS
) != IDF_NONE
)
1673 CopyAsLinkHandler
aFunc(*this, rColumn
, rCxt
.getBlockPosition(rColumn
.nTab
, rColumn
.nCol
), nFlags
);
1674 aFunc
.setStartListening(rCxt
.isStartListening());
1675 sc::ParseBlock(maCells
.begin(), maCells
, aFunc
, nRow1
, nRow2
);
1679 // Compare the ScDocumentPool* to determine if we are copying
1680 // within the same document. If not, re-intern shared strings.
1681 svl::SharedStringPool
* pSharedStringPool
=
1682 (pDocument
->GetPool() != rColumn
.pDocument
->GetPool()) ?
1683 &rColumn
.pDocument
->GetSharedStringPool() : NULL
;
1684 CopyByCloneHandler
aFunc(*this, rColumn
, rCxt
.getBlockPosition(rColumn
.nTab
, rColumn
.nCol
), nFlags
,
1686 aFunc
.setStartListening(rCxt
.isStartListening());
1687 sc::ParseBlock(maCells
.begin(), maCells
, aFunc
, nRow1
, nRow2
);
1690 rColumn
.CellStorageModified();
1694 void ScColumn::UndoToColumn(
1695 sc::CopyToDocContext
& rCxt
, SCROW nRow1
, SCROW nRow2
, InsertDeleteFlags nFlags
, bool bMarked
,
1696 ScColumn
& rColumn
, const ScMarkData
* pMarkData
) const
1699 CopyToColumn(rCxt
, 0, nRow1
-1, IDF_FORMULA
, false, rColumn
);
1701 CopyToColumn(rCxt
, nRow1
, nRow2
, nFlags
, bMarked
, rColumn
, pMarkData
); //TODO: bMarked ????
1704 CopyToColumn(rCxt
, nRow2
+1, MAXROW
, IDF_FORMULA
, false, rColumn
);
1707 void ScColumn::CopyUpdated( const ScColumn
& rPosCol
, ScColumn
& rDestCol
) const
1709 // Copy cells from this column to the destination column only for those
1710 // rows that are present in the position column (rPosCol).
1712 // First, mark all the non-empty cell ranges from the position column.
1713 sc::SingleColumnSpanSet aRangeSet
;
1714 aRangeSet
.scan(rPosCol
);
1716 // Now, copy cells from this column to the destination column for those
1717 // marked row ranges.
1718 sc::SingleColumnSpanSet::SpansType aRanges
;
1719 aRangeSet
.getSpans(aRanges
);
1721 bool bCopyNotes
= true;
1722 CopyToClipHandler
aFunc(*this, rDestCol
, NULL
, bCopyNotes
);
1723 sc::CellStoreType::const_iterator itPos
= maCells
.begin();
1724 sc::SingleColumnSpanSet::SpansType::const_iterator it
= aRanges
.begin(), itEnd
= aRanges
.end();
1725 for (; it
!= itEnd
; ++it
)
1726 itPos
= sc::ParseBlock(itPos
, maCells
, aFunc
, it
->mnRow1
, it
->mnRow2
);
1728 rDestCol
.CellStorageModified();
1731 void ScColumn::CopyScenarioFrom( const ScColumn
& rSrcCol
)
1733 // This is the scenario table, the data is copied into it
1734 ScAttrIterator
aAttrIter( pAttrArray
, 0, MAXROW
);
1735 SCROW nStart
= -1, nEnd
= -1;
1736 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1739 if ( static_cast<const ScMergeFlagAttr
&>(pPattern
->GetItem( ATTR_MERGE_FLAG
)).IsScenario() )
1741 DeleteArea( nStart
, nEnd
, IDF_CONTENTS
);
1742 sc::CopyToDocContext
aCxt(*pDocument
);
1743 ((ScColumn
&)rSrcCol
).
1744 CopyToColumn(aCxt
, nStart
, nEnd
, IDF_CONTENTS
, false, *this);
1746 // UpdateUsed not needed, already done in TestCopyScenario (obsolete comment ?)
1748 sc::RefUpdateContext
aRefCxt(*pDocument
);
1749 aRefCxt
.meMode
= URM_COPY
;
1750 aRefCxt
.maRange
= ScRange(nCol
, nStart
, nTab
, nCol
, nEnd
, nTab
);
1751 aRefCxt
.mnTabDelta
= nTab
- rSrcCol
.nTab
;
1752 UpdateReferenceOnCopy(aRefCxt
, NULL
);
1756 //TODO: make CopyToColumn "const" !!! (obsolete comment ?)
1758 pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1762 void ScColumn::CopyScenarioTo( ScColumn
& rDestCol
) const
1764 // This is the scenario table, the data is copied to the other
1765 ScAttrIterator
aAttrIter( pAttrArray
, 0, MAXROW
);
1766 SCROW nStart
= -1, nEnd
= -1;
1767 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1770 if ( static_cast<const ScMergeFlagAttr
&>(pPattern
->GetItem( ATTR_MERGE_FLAG
)).IsScenario() )
1772 rDestCol
.DeleteArea( nStart
, nEnd
, IDF_CONTENTS
);
1773 sc::CopyToDocContext
aCxt(*rDestCol
.pDocument
);
1774 CopyToColumn(aCxt
, nStart
, nEnd
, IDF_CONTENTS
, false, rDestCol
);
1776 // UpdateUsed not needed, is already done in TestCopyScenario (obsolete comment ?)
1778 sc::RefUpdateContext
aRefCxt(*pDocument
);
1779 aRefCxt
.meMode
= URM_COPY
;
1780 aRefCxt
.maRange
= ScRange(rDestCol
.nCol
, nStart
, rDestCol
.nTab
, rDestCol
.nCol
, nEnd
, rDestCol
.nTab
);
1781 aRefCxt
.mnTabDelta
= rDestCol
.nTab
- nTab
;
1782 rDestCol
.UpdateReferenceOnCopy(aRefCxt
, NULL
);
1783 rDestCol
.UpdateCompile();
1786 //TODO: make CopyToColumn "const" !!! (obsolete comment ?)
1788 pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1792 bool ScColumn::TestCopyScenarioTo( const ScColumn
& rDestCol
) const
1795 ScAttrIterator
aAttrIter( pAttrArray
, 0, MAXROW
);
1796 SCROW nStart
= 0, nEnd
= 0;
1797 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1798 while (pPattern
&& bOk
)
1800 if ( static_cast<const ScMergeFlagAttr
&>(pPattern
->GetItem( ATTR_MERGE_FLAG
)).IsScenario() )
1801 if ( rDestCol
.pAttrArray
->HasAttrib( nStart
, nEnd
, HASATTR_PROTECTED
) )
1804 pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1809 void ScColumn::MarkScenarioIn( ScMarkData
& rDestMark
) const
1811 ScRange
aRange( nCol
, 0, nTab
);
1813 ScAttrIterator
aAttrIter( pAttrArray
, 0, MAXROW
);
1814 SCROW nStart
= -1, nEnd
= -1;
1815 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1818 if ( static_cast<const ScMergeFlagAttr
&>(pPattern
->GetItem( ATTR_MERGE_FLAG
)).IsScenario() )
1820 aRange
.aStart
.SetRow( nStart
);
1821 aRange
.aEnd
.SetRow( nEnd
);
1822 rDestMark
.SetMultiMarkArea( aRange
, true );
1825 pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1831 void resetColumnPosition(sc::CellStoreType
& rCells
, SCCOL nCol
)
1833 sc::CellStoreType::iterator it
= rCells
.begin(), itEnd
= rCells
.end();
1834 for (; it
!= itEnd
; ++it
)
1836 if (it
->type
!= sc::element_type_formula
)
1839 sc::formula_block::iterator itCell
= sc::formula_block::begin(*it
->data
);
1840 sc::formula_block::iterator itCellEnd
= sc::formula_block::end(*it
->data
);
1841 for (; itCell
!= itCellEnd
; ++itCell
)
1843 ScFormulaCell
& rCell
= **itCell
;
1844 rCell
.aPos
.SetCol(nCol
);
1849 class NoteCaptionUpdater
1854 NoteCaptionUpdater( SCCOL nCol
, SCTAB nTab
) : mnCol(nCol
), mnTab(nTab
) {}
1856 void operator() ( size_t nRow
, ScPostIt
* p
)
1858 p
->UpdateCaptionPos(ScAddress(mnCol
,nRow
,mnTab
));
1864 void ScColumn::UpdateNoteCaptions( SCROW nRow1
, SCROW nRow2
)
1866 NoteCaptionUpdater
aFunc(nCol
, nTab
);
1867 sc::ProcessNote(maCellNotes
.begin(), maCellNotes
, nRow1
, nRow2
, aFunc
);
1870 void ScColumn::SwapCol(ScColumn
& rCol
)
1872 maBroadcasters
.swap(rCol
.maBroadcasters
);
1873 maCells
.swap(rCol
.maCells
);
1874 maCellTextAttrs
.swap(rCol
.maCellTextAttrs
);
1875 maCellNotes
.swap(rCol
.maCellNotes
);
1877 // notes update caption
1878 UpdateNoteCaptions(0, MAXROW
);
1879 rCol
.UpdateNoteCaptions(0, MAXROW
);
1881 ScAttrArray
* pTempAttr
= rCol
.pAttrArray
;
1882 rCol
.pAttrArray
= pAttrArray
;
1883 pAttrArray
= pTempAttr
;
1885 // AttrArray needs to have the right column number
1886 pAttrArray
->SetCol(nCol
);
1887 rCol
.pAttrArray
->SetCol(rCol
.nCol
);
1889 std::swap(mbDirtyGroups
, rCol
.mbDirtyGroups
);
1891 // Reset column positions in formula cells.
1892 resetColumnPosition(maCells
, nCol
);
1893 resetColumnPosition(rCol
.maCells
, rCol
.nCol
);
1895 CellStorageModified();
1896 rCol
.CellStorageModified();
1899 void ScColumn::MoveTo(SCROW nStartRow
, SCROW nEndRow
, ScColumn
& rCol
)
1901 pAttrArray
->MoveTo(nStartRow
, nEndRow
, *rCol
.pAttrArray
);
1903 // Mark the non-empty cells within the specified range, for later broadcasting.
1904 sc::SingleColumnSpanSet aNonEmpties
;
1905 aNonEmpties
.scan(*this, nStartRow
, nEndRow
);
1906 sc::SingleColumnSpanSet::SpansType aRanges
;
1907 aNonEmpties
.getSpans(aRanges
);
1909 // Split the formula grouping at the top and bottom boundaries.
1910 sc::CellStoreType::position_type aPos
= maCells
.position(nStartRow
);
1911 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos
, nullptr);
1912 aPos
= maCells
.position(aPos
.first
, nEndRow
+1);
1913 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos
, nullptr);
1915 // Do the same with the destination column.
1916 aPos
= rCol
.maCells
.position(nStartRow
);
1917 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos
, nullptr);
1918 aPos
= rCol
.maCells
.position(aPos
.first
, nEndRow
+1);
1919 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos
, nullptr);
1921 // Move the broadcasters to the destination column.
1922 maBroadcasters
.transfer(nStartRow
, nEndRow
, rCol
.maBroadcasters
, nStartRow
);
1923 maCells
.transfer(nStartRow
, nEndRow
, rCol
.maCells
, nStartRow
);
1924 maCellTextAttrs
.transfer(nStartRow
, nEndRow
, rCol
.maCellTextAttrs
, nStartRow
);
1926 // move the notes to the destination column
1927 maCellNotes
.transfer(nStartRow
, nEndRow
, rCol
.maCellNotes
, nStartRow
);
1928 UpdateNoteCaptions(0, MAXROW
);
1930 // Re-group transferred formula cells.
1931 aPos
= rCol
.maCells
.position(nStartRow
);
1932 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
1933 aPos
= rCol
.maCells
.position(aPos
.first
, nEndRow
+1);
1934 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
1936 CellStorageModified();
1937 rCol
.CellStorageModified();
1939 // Broadcast on moved ranges. Area-broadcast only.
1940 ScHint
aHint(SC_HINT_DATACHANGED
, ScAddress(nCol
, 0, nTab
));
1941 ScAddress
& rPos
= aHint
.GetAddress();
1942 sc::SingleColumnSpanSet::SpansType::const_iterator itRange
= aRanges
.begin(), itRangeEnd
= aRanges
.end();
1943 for (; itRange
!= itRangeEnd
; ++itRange
)
1945 for (SCROW nRow
= itRange
->mnRow1
; nRow
<= itRange
->mnRow2
; ++nRow
)
1948 pDocument
->AreaBroadcast(aHint
);
1955 class SharedTopFormulaCellPicker
: std::unary_function
<sc::CellStoreType::value_type
, void>
1958 virtual ~SharedTopFormulaCellPicker() {}
1960 void operator() ( sc::CellStoreType::value_type
& node
)
1962 if (node
.type
!= sc::element_type_formula
)
1965 size_t nTopRow
= node
.position
;
1967 sc::formula_block::iterator itBeg
= sc::formula_block::begin(*node
.data
);
1968 sc::formula_block::iterator itEnd
= sc::formula_block::end(*node
.data
);
1970 // Only pick shared formula cells that are the top cells of their
1971 // respective shared ranges.
1972 for (sc::formula_block::iterator it
= itBeg
; it
!= itEnd
; ++it
)
1974 ScFormulaCell
* pCell
= *it
;
1975 size_t nRow
= nTopRow
+ std::distance(itBeg
, it
);
1976 if (!pCell
->IsShared())
1978 processNonShared(pCell
, nRow
);
1982 if (pCell
->IsSharedTop())
1984 ScFormulaCell
** pp
= &(*it
);
1985 processSharedTop(pp
, nRow
, pCell
->GetSharedLength());
1987 // Move to the last cell in the group, to get incremented to
1988 // the next cell in the next iteration.
1989 size_t nOffsetToLast
= pCell
->GetSharedLength() - 1;
1990 std::advance(it
, nOffsetToLast
);
1995 virtual void processNonShared( ScFormulaCell
* /*pCell*/, size_t /*nRow*/ ) {}
1996 virtual void processSharedTop( ScFormulaCell
** /*ppCells*/, size_t /*nRow*/, size_t /*nLength*/ ) {}
1999 class UpdateRefOnCopy
2001 const sc::RefUpdateContext
& mrCxt
;
2002 ScDocument
* mpUndoDoc
;
2006 UpdateRefOnCopy(const sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
) :
2007 mrCxt(rCxt
), mpUndoDoc(pUndoDoc
), mbUpdated(false) {}
2009 bool isUpdated() const { return mbUpdated
; }
2011 void operator() (sc::CellStoreType::value_type
& node
, size_t nOffset
, size_t nDataSize
)
2013 if (node
.type
!= sc::element_type_formula
)
2016 sc::formula_block::iterator it
= sc::formula_block::begin(*node
.data
);
2017 std::advance(it
, nOffset
);
2018 sc::formula_block::iterator itEnd
= it
;
2019 std::advance(itEnd
, nDataSize
);
2021 for (; it
!= itEnd
; ++it
)
2023 ScFormulaCell
& rCell
= **it
;
2024 mbUpdated
|= rCell
.UpdateReference(mrCxt
, mpUndoDoc
);
2029 class UpdateRefOnNonCopy
: std::unary_function
<sc::FormulaGroupEntry
, void>
2033 const sc::RefUpdateContext
* mpCxt
;
2034 ScDocument
* mpUndoDoc
;
2037 void recompileTokenArray( ScFormulaCell
& rTopCell
)
2039 // We need to re-compile the token array when a range name is
2040 // modified, to correctly reflect the new references in the
2042 ScCompiler
aComp(&mpCxt
->mrDoc
, rTopCell
.aPos
, *rTopCell
.GetCode());
2043 aComp
.SetGrammar(mpCxt
->mrDoc
.GetGrammar());
2044 aComp
.CompileTokenArray();
2047 void updateRefOnShift( sc::FormulaGroupEntry
& rGroup
)
2049 if (!rGroup
.mbShared
)
2051 ScAddress
aUndoPos(mnCol
, rGroup
.mnRow
, mnTab
);
2052 mbUpdated
|= rGroup
.mpCell
->UpdateReferenceOnShift(*mpCxt
, mpUndoDoc
, &aUndoPos
);
2056 // Update references of a formula group.
2057 ScFormulaCell
** pp
= rGroup
.mpCells
;
2058 ScFormulaCell
** ppEnd
= pp
+ rGroup
.mnLength
;
2059 ScFormulaCell
* pTop
= *pp
;
2060 ScTokenArray
* pCode
= pTop
->GetCode();
2061 boost::scoped_ptr
<ScTokenArray
> pOldCode(pCode
->Clone());
2062 ScAddress aOldPos
= pTop
->aPos
;
2064 // Run this before the position gets updated.
2065 sc::RefUpdateResult aRes
= pCode
->AdjustReferenceOnShift(*mpCxt
, aOldPos
);
2067 if (pTop
->UpdatePosOnShift(*mpCxt
))
2069 // Update the positions of all formula cells.
2070 for (++pp
; pp
!= ppEnd
; ++pp
) // skip the top cell.
2072 ScFormulaCell
* pFC
= *pp
;
2073 pFC
->aPos
.Move(mpCxt
->mnColDelta
, mpCxt
->mnRowDelta
, mpCxt
->mnTabDelta
);
2076 if (pCode
->IsRecalcModeOnRefMove())
2077 aRes
.mbValueChanged
= true;
2079 else if (aRes
.mbReferenceModified
&& pCode
->IsRecalcModeOnRefMove())
2081 // The cell itself hasn't shifted. But it may have ROW or COLUMN
2082 // referencing another cell that has.
2083 aRes
.mbValueChanged
= true;
2086 if (aRes
.mbNameModified
)
2087 recompileTokenArray(*pTop
);
2089 if (aRes
.mbReferenceModified
|| aRes
.mbNameModified
)
2091 sc::EndListeningContext
aEndCxt(mpCxt
->mrDoc
, pOldCode
.get());
2092 aEndCxt
.setPositionDelta(
2093 ScAddress(-mpCxt
->mnColDelta
, -mpCxt
->mnRowDelta
, -mpCxt
->mnTabDelta
));
2095 for (pp
= rGroup
.mpCells
; pp
!= ppEnd
; ++pp
)
2097 ScFormulaCell
* p
= *pp
;
2098 p
->EndListeningTo(aEndCxt
);
2099 p
->SetNeedsListening(true);
2104 fillUndoDoc(aOldPos
, rGroup
.mnLength
, *pOldCode
);
2107 if (aRes
.mbValueChanged
)
2109 for (pp
= rGroup
.mpCells
; pp
!= ppEnd
; ++pp
)
2111 ScFormulaCell
* p
= *pp
;
2112 p
->SetNeedsDirty(true);
2117 void updateRefOnMove( sc::FormulaGroupEntry
& rGroup
)
2119 if (!rGroup
.mbShared
)
2121 ScAddress
aUndoPos(mnCol
, rGroup
.mnRow
, mnTab
);
2122 mbUpdated
|= rGroup
.mpCell
->UpdateReferenceOnMove(*mpCxt
, mpUndoDoc
, &aUndoPos
);
2126 // Update references of a formula group.
2127 ScFormulaCell
** pp
= rGroup
.mpCells
;
2128 ScFormulaCell
** ppEnd
= pp
+ rGroup
.mnLength
;
2129 ScFormulaCell
* pTop
= *pp
;
2130 ScTokenArray
* pCode
= pTop
->GetCode();
2131 boost::scoped_ptr
<ScTokenArray
> pOldCode(pCode
->Clone());
2133 ScAddress aPos
= pTop
->aPos
;
2134 ScAddress aOldPos
= aPos
;
2136 if (mpCxt
->maRange
.In(aPos
))
2138 // The cell is being moved or copied to a new position. The
2139 // position has already been updated prior to this call.
2140 // Determine its original position before the move which will be
2141 // used to adjust relative references later.
2144 aPos
.Col() - mpCxt
->mnColDelta
,
2145 aPos
.Row() - mpCxt
->mnRowDelta
,
2146 aPos
.Tab() - mpCxt
->mnTabDelta
);
2149 bool bRecalcOnMove
= pCode
->IsRecalcModeOnRefMove();
2151 bRecalcOnMove
= aPos
!= aOldPos
;
2153 sc::RefUpdateResult aRes
= pCode
->AdjustReferenceOnMove(*mpCxt
, aOldPos
, aPos
);
2155 if (aRes
.mbReferenceModified
|| aRes
.mbNameModified
|| bRecalcOnMove
)
2157 sc::AutoCalcSwitch(mpCxt
->mrDoc
, false);
2159 if (aRes
.mbNameModified
)
2160 recompileTokenArray(*pTop
);
2162 // Perform end-listening, start-listening, and dirtying on all
2163 // formula cells in the group.
2165 // Make sure that the start and end listening contexts share the
2166 // same block position set, else an invalid iterator may ensue.
2167 boost::shared_ptr
<sc::ColumnBlockPositionSet
> pPosSet(
2168 new sc::ColumnBlockPositionSet(mpCxt
->mrDoc
));
2170 sc::StartListeningContext
aStartCxt(mpCxt
->mrDoc
, pPosSet
);
2171 sc::EndListeningContext
aEndCxt(mpCxt
->mrDoc
, pPosSet
, pOldCode
.get());
2173 aEndCxt
.setPositionDelta(
2174 ScAddress(-mpCxt
->mnColDelta
, -mpCxt
->mnRowDelta
, -mpCxt
->mnTabDelta
));
2176 for (; pp
!= ppEnd
; ++pp
)
2178 ScFormulaCell
* p
= *pp
;
2179 p
->EndListeningTo(aEndCxt
);
2180 p
->StartListeningTo(aStartCxt
);
2184 fillUndoDoc(aOldPos
, rGroup
.mnLength
, *pOldCode
);
2188 void fillUndoDoc( const ScAddress
& rOldPos
, SCROW nLength
, const ScTokenArray
& rOldCode
)
2190 if (!mpUndoDoc
|| nLength
<= 0)
2193 // Insert the old formula group into the undo document.
2194 ScAddress aUndoPos
= rOldPos
;
2195 ScFormulaCell
* pFC
= new ScFormulaCell(mpUndoDoc
, aUndoPos
, rOldCode
.Clone());
2199 mpUndoDoc
->SetFormulaCell(aUndoPos
, pFC
);
2203 std::vector
<ScFormulaCell
*> aCells
;
2204 aCells
.reserve(nLength
);
2205 ScFormulaCellGroupRef xGroup
= pFC
->CreateCellGroup(nLength
, false);
2206 aCells
.push_back(pFC
);
2208 for (SCROW i
= 1; i
< nLength
; ++i
, aUndoPos
.IncRow())
2210 pFC
= new ScFormulaCell(mpUndoDoc
, aUndoPos
, xGroup
);
2211 aCells
.push_back(pFC
);
2214 if (!mpUndoDoc
->SetFormulaCells(rOldPos
, aCells
))
2215 // Insertion failed. Delete all formula cells.
2216 std::for_each(aCells
.begin(), aCells
.end(), boost::checked_deleter
<ScFormulaCell
>());
2221 SCCOL nCol
, SCTAB nTab
, const sc::RefUpdateContext
* pCxt
,
2222 ScDocument
* pUndoDoc
) :
2223 mnCol(nCol
), mnTab(nTab
), mpCxt(pCxt
),
2224 mpUndoDoc(pUndoDoc
), mbUpdated(false) {}
2226 void operator() ( sc::FormulaGroupEntry
& rGroup
)
2228 switch (mpCxt
->meMode
)
2231 updateRefOnShift(rGroup
);
2234 updateRefOnMove(rGroup
);
2240 if (rGroup
.mbShared
)
2242 ScAddress
aUndoPos(mnCol
, rGroup
.mnRow
, mnTab
);
2243 ScFormulaCell
** pp
= rGroup
.mpCells
;
2244 ScFormulaCell
** ppEnd
= pp
+ rGroup
.mnLength
;
2245 for (; pp
!= ppEnd
; ++pp
, aUndoPos
.IncRow())
2247 ScFormulaCell
* p
= *pp
;
2248 mbUpdated
|= p
->UpdateReference(*mpCxt
, mpUndoDoc
, &aUndoPos
);
2253 ScAddress
aUndoPos(mnCol
, rGroup
.mnRow
, mnTab
);
2254 mbUpdated
|= rGroup
.mpCell
->UpdateReference(*mpCxt
, mpUndoDoc
, &aUndoPos
);
2258 bool isUpdated() const { return mbUpdated
; }
2261 class UpdateRefGroupBoundChecker
: public SharedTopFormulaCellPicker
2263 const sc::RefUpdateContext
& mrCxt
;
2264 std::vector
<SCROW
>& mrBounds
;
2267 UpdateRefGroupBoundChecker(const sc::RefUpdateContext
& rCxt
, std::vector
<SCROW
>& rBounds
) :
2268 mrCxt(rCxt
), mrBounds(rBounds
) {}
2270 virtual ~UpdateRefGroupBoundChecker() {}
2272 virtual void processSharedTop( ScFormulaCell
** ppCells
, size_t /*nRow*/, size_t /*nLength*/ ) SAL_OVERRIDE
2274 // Check its tokens and record its reference boundaries.
2275 ScFormulaCell
& rCell
= **ppCells
;
2276 const ScTokenArray
& rCode
= *rCell
.GetCode();
2277 rCode
.CheckRelativeReferenceBounds(
2278 mrCxt
, rCell
.aPos
, rCell
.GetSharedLength(), mrBounds
);
2282 class UpdateRefExpandGroupBoundChecker
: public SharedTopFormulaCellPicker
2284 const sc::RefUpdateContext
& mrCxt
;
2285 std::vector
<SCROW
>& mrBounds
;
2288 UpdateRefExpandGroupBoundChecker(const sc::RefUpdateContext
& rCxt
, std::vector
<SCROW
>& rBounds
) :
2289 mrCxt(rCxt
), mrBounds(rBounds
) {}
2291 virtual ~UpdateRefExpandGroupBoundChecker() {}
2293 virtual void processSharedTop( ScFormulaCell
** ppCells
, size_t /*nRow*/, size_t /*nLength*/ ) SAL_OVERRIDE
2295 // Check its tokens and record its reference boundaries.
2296 ScFormulaCell
& rCell
= **ppCells
;
2297 const ScTokenArray
& rCode
= *rCell
.GetCode();
2298 rCode
.CheckExpandReferenceBounds(
2299 mrCxt
, rCell
.aPos
, rCell
.GetSharedLength(), mrBounds
);
2303 class FormulaGroupPicker
: public SharedTopFormulaCellPicker
2305 std::vector
<sc::FormulaGroupEntry
>& mrGroups
;
2308 FormulaGroupPicker( std::vector
<sc::FormulaGroupEntry
>& rGroups
) : mrGroups(rGroups
) {}
2310 virtual ~FormulaGroupPicker() {}
2312 virtual void processNonShared( ScFormulaCell
* pCell
, size_t nRow
) SAL_OVERRIDE
2314 mrGroups
.push_back(sc::FormulaGroupEntry(pCell
, nRow
));
2317 virtual void processSharedTop( ScFormulaCell
** ppCells
, size_t nRow
, size_t nLength
) SAL_OVERRIDE
2319 mrGroups
.push_back(sc::FormulaGroupEntry(ppCells
, nRow
, nLength
));
2325 bool ScColumn::UpdateReferenceOnCopy( const sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
)
2327 // When copying, the range equals the destination range where cells
2328 // are pasted, and the dx, dy, dz refer to the distance from the
2331 UpdateRefOnCopy
aHandler(rCxt
, pUndoDoc
);
2332 sc::CellStoreType::position_type aPos
= maCells
.position(rCxt
.maRange
.aStart
.Row());
2333 sc::ProcessBlock(aPos
.first
, maCells
, aHandler
, rCxt
.maRange
.aStart
.Row(), rCxt
.maRange
.aEnd
.Row());
2335 // The formula groups at the top and bottom boundaries are expected to
2336 // have been split prior to this call. Here, we only do the joining.
2337 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
2338 if (rCxt
.maRange
.aEnd
.Row() < MAXROW
)
2340 aPos
= maCells
.position(aPos
.first
, rCxt
.maRange
.aEnd
.Row()+1);
2341 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
2344 return aHandler
.isUpdated();
2347 bool ScColumn::UpdateReference( sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
)
2349 if (rCxt
.meMode
== URM_COPY
)
2350 return UpdateReferenceOnCopy(rCxt
, pUndoDoc
);
2352 if (IsEmptyData() || pDocument
->IsClipOrUndo())
2353 // Cells in this column are all empty, or clip or undo doc. No update needed.
2356 std::vector
<SCROW
> aBounds
;
2358 bool bThisColShifted
= (rCxt
.maRange
.aStart
.Tab() <= nTab
&& nTab
<= rCxt
.maRange
.aEnd
.Tab() &&
2359 rCxt
.maRange
.aStart
.Col() <= nCol
&& nCol
<= rCxt
.maRange
.aEnd
.Col());
2360 if (bThisColShifted
)
2362 // Cells in this column is being shifted. Split formula grouping at
2363 // the top and bottom boundaries before they get shifted.
2364 // Also, for deleted rows split at the top of the deleted area to adapt
2365 // the affected group length.
2367 if (rCxt
.mnRowDelta
< 0)
2369 nSplitPos
= rCxt
.maRange
.aStart
.Row() + rCxt
.mnRowDelta
;
2370 if (ValidRow(nSplitPos
))
2371 aBounds
.push_back(nSplitPos
);
2373 nSplitPos
= rCxt
.maRange
.aStart
.Row();
2374 if (ValidRow(nSplitPos
))
2376 aBounds
.push_back(nSplitPos
);
2377 nSplitPos
= rCxt
.maRange
.aEnd
.Row() + 1;
2378 if (ValidRow(nSplitPos
))
2379 aBounds
.push_back(nSplitPos
);
2383 // Check the row positions at which the group must be split per relative
2385 UpdateRefGroupBoundChecker
aBoundChecker(rCxt
, aBounds
);
2386 std::for_each(maCells
.begin(), maCells
.end(), aBoundChecker
);
2388 // If expand reference edges is on, splitting groups may happen anywhere
2389 // where a reference points to an adjacent row of the insertion.
2390 if (rCxt
.mnRowDelta
> 0 && rCxt
.mrDoc
.IsExpandRefs())
2392 UpdateRefExpandGroupBoundChecker
aExpandChecker(rCxt
, aBounds
);
2393 std::for_each(maCells
.begin(), maCells
.end(), aExpandChecker
);
2396 // Do the actual splitting.
2397 sc::SharedFormulaUtil::splitFormulaCellGroups(maCells
, aBounds
);
2399 // Collect all formula groups.
2400 std::vector
<sc::FormulaGroupEntry
> aGroups
= GetFormulaGroupEntries();
2402 // Process all collected formula groups.
2403 UpdateRefOnNonCopy
aHandler(nCol
, nTab
, &rCxt
, pUndoDoc
);
2404 aHandler
= std::for_each(aGroups
.begin(), aGroups
.end(), aHandler
);
2405 if (aHandler
.isUpdated())
2406 rCxt
.maRegroupCols
.set(nTab
, nCol
);
2408 return aHandler
.isUpdated();
2411 std::vector
<sc::FormulaGroupEntry
> ScColumn::GetFormulaGroupEntries()
2413 std::vector
<sc::FormulaGroupEntry
> aGroups
;
2414 std::for_each(maCells
.begin(), maCells
.end(), FormulaGroupPicker(aGroups
));
2420 class UpdateTransHandler
2423 sc::CellStoreType::iterator miPos
;
2426 ScDocument
* mpUndoDoc
;
2428 UpdateTransHandler(ScColumn
& rColumn
, const ScRange
& rSource
, const ScAddress
& rDest
, ScDocument
* pUndoDoc
) :
2430 miPos(rColumn
.GetCellStore().begin()),
2431 maSource(rSource
), maDest(rDest
), mpUndoDoc(pUndoDoc
) {}
2433 void operator() (size_t nRow
, ScFormulaCell
* pCell
)
2435 sc::CellStoreType::position_type aPos
= mrColumn
.GetCellStore().position(miPos
, nRow
);
2437 sc::SharedFormulaUtil::unshareFormulaCell(aPos
, *pCell
);
2438 pCell
->UpdateTranspose(maSource
, maDest
, mpUndoDoc
);
2439 ScColumn::JoinNewFormulaCell(aPos
, *pCell
);
2443 class UpdateGrowHandler
2446 sc::CellStoreType::iterator miPos
;
2451 UpdateGrowHandler(ScColumn
& rColumn
, const ScRange
& rArea
, SCCOL nGrowX
, SCROW nGrowY
) :
2453 miPos(rColumn
.GetCellStore().begin()),
2454 maArea(rArea
), mnGrowX(nGrowX
), mnGrowY(nGrowY
) {}
2456 void operator() (size_t nRow
, ScFormulaCell
* pCell
)
2458 sc::CellStoreType::position_type aPos
= mrColumn
.GetCellStore().position(miPos
, nRow
);
2460 sc::SharedFormulaUtil::unshareFormulaCell(aPos
, *pCell
);
2461 pCell
->UpdateGrow(maArea
, mnGrowX
, mnGrowY
);
2462 ScColumn::JoinNewFormulaCell(aPos
, *pCell
);
2466 class InsertTabUpdater
2468 sc::RefUpdateInsertTabContext
& mrCxt
;
2469 sc::CellTextAttrStoreType
& mrTextAttrs
;
2470 sc::CellTextAttrStoreType::iterator miAttrPos
;
2475 InsertTabUpdater(sc::RefUpdateInsertTabContext
& rCxt
, sc::CellTextAttrStoreType
& rTextAttrs
, SCTAB nTab
) :
2477 mrTextAttrs(rTextAttrs
),
2478 miAttrPos(rTextAttrs
.begin()),
2480 mbModified(false) {}
2482 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2484 pCell
->UpdateInsertTab(mrCxt
);
2488 void operator() (size_t nRow
, EditTextObject
* pCell
)
2490 editeng::FieldUpdater aUpdater
= pCell
->GetFieldUpdater();
2491 aUpdater
.updateTableFields(mnTab
);
2492 miAttrPos
= mrTextAttrs
.set(miAttrPos
, nRow
, sc::CellTextAttr());
2496 bool isModified() const { return mbModified
; }
2499 class DeleteTabUpdater
2501 sc::RefUpdateDeleteTabContext
& mrCxt
;
2502 sc::CellTextAttrStoreType
& mrTextAttrs
;
2503 sc::CellTextAttrStoreType::iterator miAttrPos
;
2507 DeleteTabUpdater(sc::RefUpdateDeleteTabContext
& rCxt
, sc::CellTextAttrStoreType
& rTextAttrs
, SCTAB nTab
) :
2509 mrTextAttrs(rTextAttrs
),
2510 miAttrPos(rTextAttrs
.begin()),
2512 mbModified(false) {}
2514 void operator() (size_t, ScFormulaCell
* pCell
)
2516 pCell
->UpdateDeleteTab(mrCxt
);
2520 void operator() (size_t nRow
, EditTextObject
* pCell
)
2522 editeng::FieldUpdater aUpdater
= pCell
->GetFieldUpdater();
2523 aUpdater
.updateTableFields(mnTab
);
2524 miAttrPos
= mrTextAttrs
.set(miAttrPos
, nRow
, sc::CellTextAttr());
2528 bool isModified() const { return mbModified
; }
2531 class InsertAbsTabUpdater
2533 sc::CellTextAttrStoreType
& mrTextAttrs
;
2534 sc::CellTextAttrStoreType::iterator miAttrPos
;
2539 InsertAbsTabUpdater(sc::CellTextAttrStoreType
& rTextAttrs
, SCTAB nTab
, SCTAB nNewPos
) :
2540 mrTextAttrs(rTextAttrs
),
2541 miAttrPos(rTextAttrs
.begin()),
2544 mbModified(false) {}
2546 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2548 pCell
->UpdateInsertTabAbs(mnNewPos
);
2552 void operator() (size_t nRow
, EditTextObject
* pCell
)
2554 editeng::FieldUpdater aUpdater
= pCell
->GetFieldUpdater();
2555 aUpdater
.updateTableFields(mnTab
);
2556 miAttrPos
= mrTextAttrs
.set(miAttrPos
, nRow
, sc::CellTextAttr());
2560 bool isModified() const { return mbModified
; }
2563 class MoveTabUpdater
2565 sc::RefUpdateMoveTabContext
& mrCxt
;
2566 sc::CellTextAttrStoreType
& mrTextAttrs
;
2567 sc::CellTextAttrStoreType::iterator miAttrPos
;
2571 MoveTabUpdater(sc::RefUpdateMoveTabContext
& rCxt
, sc::CellTextAttrStoreType
& rTextAttrs
, SCTAB nTab
) :
2573 mrTextAttrs(rTextAttrs
),
2574 miAttrPos(rTextAttrs
.begin()),
2576 mbModified(false) {}
2578 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2580 pCell
->UpdateMoveTab(mrCxt
, mnTab
);
2584 void operator() (size_t nRow
, EditTextObject
* pCell
)
2586 editeng::FieldUpdater aUpdater
= pCell
->GetFieldUpdater();
2587 aUpdater
.updateTableFields(mnTab
);
2588 miAttrPos
= mrTextAttrs
.set(miAttrPos
, nRow
, sc::CellTextAttr());
2592 bool isModified() const { return mbModified
; }
2595 class UpdateCompileHandler
2597 bool mbForceIfNameInUse
:1;
2599 UpdateCompileHandler(bool bForceIfNameInUse
) :
2600 mbForceIfNameInUse(bForceIfNameInUse
) {}
2602 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2604 pCell
->UpdateCompile(mbForceIfNameInUse
);
2612 TabNoSetter(SCTAB nTab
) : mnTab(nTab
) {}
2614 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2616 pCell
->aPos
.SetTab(mnTab
);
2620 class UsedRangeNameFinder
2622 std::set
<sal_uInt16
>& mrIndexes
;
2624 UsedRangeNameFinder(std::set
<sal_uInt16
>& rIndexes
) : mrIndexes(rIndexes
) {}
2626 void operator() (size_t /*nRow*/, const ScFormulaCell
* pCell
)
2628 pCell
->FindRangeNamesInUse(mrIndexes
);
2632 struct SetDirtyVarHandler
2634 void operator() (size_t /*nRow*/, ScFormulaCell
* p
)
2640 class SetDirtyHandler
2643 const sc::SetFormulaDirtyContext
& mrCxt
;
2645 SetDirtyHandler( ScDocument
& rDoc
, const sc::SetFormulaDirtyContext
& rCxt
) :
2646 mrDoc(rDoc
), mrCxt(rCxt
) {}
2648 void operator() (size_t /*nRow*/, ScFormulaCell
* p
)
2650 if (mrCxt
.mbClearTabDeletedFlag
)
2652 if (!p
->IsShared() || p
->IsSharedTop())
2654 ScTokenArray
* pCode
= p
->GetCode();
2655 pCode
->ClearTabDeleted(
2656 p
->aPos
, mrCxt
.mnTabDeletedStart
, mrCxt
.mnTabDeletedEnd
);
2661 if (!mrDoc
.IsInFormulaTree(p
))
2662 mrDoc
.PutInFormulaTree(p
);
2666 class SetDirtyOnRangeHandler
2668 sc::SingleColumnSpanSet maValueRanges
;
2671 SetDirtyOnRangeHandler(ScColumn
& rColumn
) : mrColumn(rColumn
) {}
2673 void operator() (size_t /*nRow*/, ScFormulaCell
* p
)
2678 void operator() (mdds::mtv::element_t type
, size_t nTopRow
, size_t nDataSize
)
2680 if (type
== sc::element_type_empty
)
2681 // Ignore empty blocks.
2684 // Non-formula cells.
2685 SCROW nRow1
= nTopRow
;
2686 SCROW nRow2
= nTopRow
+ nDataSize
- 1;
2687 maValueRanges
.set(nRow1
, nRow2
, true);
2692 std::vector
<SCROW
> aRows
;
2693 maValueRanges
.getRows(aRows
);
2694 mrColumn
.BroadcastCells(aRows
, SC_HINT_DATACHANGED
);
2697 void fillBroadcastSpans( sc::ColumnSpanSet
& rBroadcastSpans
) const
2699 SCCOL nCol
= mrColumn
.GetCol();
2700 SCTAB nTab
= mrColumn
.GetTab();
2701 sc::SingleColumnSpanSet::SpansType aSpans
;
2702 maValueRanges
.getSpans(aSpans
);
2704 sc::SingleColumnSpanSet::SpansType::const_iterator it
= aSpans
.begin(), itEnd
= aSpans
.end();
2705 for (; it
!= itEnd
; ++it
)
2706 rBroadcastSpans
.set(nTab
, nCol
, it
->mnRow1
, it
->mnRow2
, true);
2710 class SetTableOpDirtyOnRangeHandler
2712 sc::SingleColumnSpanSet maValueRanges
;
2715 SetTableOpDirtyOnRangeHandler(ScColumn
& rColumn
) : mrColumn(rColumn
) {}
2717 void operator() (size_t /*nRow*/, ScFormulaCell
* p
)
2719 p
->SetTableOpDirty();
2722 void operator() (mdds::mtv::element_t type
, size_t nTopRow
, size_t nDataSize
)
2724 if (type
== sc::element_type_empty
)
2725 // Ignore empty blocks.
2728 // Non-formula cells.
2729 SCROW nRow1
= nTopRow
;
2730 SCROW nRow2
= nTopRow
+ nDataSize
- 1;
2731 maValueRanges
.set(nRow1
, nRow2
, true);
2736 std::vector
<SCROW
> aRows
;
2737 maValueRanges
.getRows(aRows
);
2738 mrColumn
.BroadcastCells(aRows
, SC_HINT_TABLEOPDIRTY
);
2742 struct SetDirtyAfterLoadHandler
2744 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2747 // Simply set dirty and append to FormulaTree, without broadcasting,
2748 // which is a magnitude faster. This is used to calculate the entire
2749 // document, e.g. when loading alien file formats.
2750 pCell
->SetDirtyAfterLoad();
2752 /* This was used with the binary file format that stored results, where only
2753 * newly compiled and volatile functions and their dependents had to be
2754 * recalculated, which was faster then. Since that was moved to 'binfilter' to
2755 * convert to an XML file this isn't needed anymore, and not used for other
2756 * file formats. Kept for reference in case mechanism needs to be reactivated
2757 * for some file formats, we'd have to introduce a controlling parameter to
2758 * this method here then.
2761 // If the cell was alsready dirty because of CalcAfterLoad,
2762 // FormulaTracking has to take place.
2763 if (pCell
->GetDirty())
2769 struct SetDirtyIfPostponedHandler
2771 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2773 if (pCell
->IsPostponedDirty() || pCell
->HasRelNameReference())
2778 struct CalcAllHandler
2780 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2782 #if OSL_DEBUG_LEVEL > 1
2783 // after F9 ctrl-F9: check the calculation for each FormulaTree
2784 double nOldVal
, nNewVal
;
2785 nOldVal
= pCell
->GetValue();
2788 #if OSL_DEBUG_LEVEL > 1
2789 if (pCell
->GetCode()->IsRecalcModeNormal())
2790 nNewVal
= pCell
->GetValue();
2792 nNewVal
= nOldVal
; // random(), jetzt() etc.
2794 OSL_ENSURE(nOldVal
== nNewVal
, "CalcAll: nOldVal != nNewVal");
2799 class CompileAllHandler
2801 sc::CompileFormulaContext
& mrCxt
;
2803 CompileAllHandler( sc::CompileFormulaContext
& rCxt
) : mrCxt(rCxt
) {}
2805 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2807 // for unconditional compilation
2808 // bCompile=true and pCode->nError=0
2809 pCell
->GetCode()->SetCodeError(0);
2810 pCell
->SetCompile(true);
2811 pCell
->CompileTokenArray(mrCxt
);
2815 class CompileXMLHandler
2817 sc::CompileFormulaContext
& mrCxt
;
2818 ScProgress
& mrProgress
;
2819 const ScColumn
& mrCol
;
2821 CompileXMLHandler( sc::CompileFormulaContext
& rCxt
, ScProgress
& rProgress
, const ScColumn
& rCol
) :
2823 mrProgress(rProgress
),
2826 void operator() (size_t nRow
, ScFormulaCell
* pCell
)
2828 sal_uInt32 nFormat
= mrCol
.GetNumberFormat(nRow
);
2829 if( (nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
) != 0)
2830 // Non-default number format is set.
2831 pCell
->SetNeedNumberFormat(false);
2832 else if (pCell
->NeedsNumberFormat())
2833 pCell
->SetDirtyVar();
2835 if (pCell
->GetMatrixFlag())
2836 pCell
->SetDirtyVar();
2838 pCell
->CompileXML(mrCxt
, mrProgress
);
2842 class CompileErrorCellsHandler
2844 sc::CompileFormulaContext
& mrCxt
;
2846 sc::CellStoreType::iterator miPos
;
2847 sal_uInt16 mnErrCode
;
2850 CompileErrorCellsHandler( sc::CompileFormulaContext
& rCxt
, ScColumn
& rColumn
, sal_uInt16 nErrCode
) :
2853 miPos(mrColumn
.GetCellStore().begin()),
2854 mnErrCode(nErrCode
),
2859 void operator() (size_t nRow
, ScFormulaCell
* pCell
)
2861 sal_uInt16 nCurError
= pCell
->GetRawError();
2863 // It's not an error cell. Skip it.
2866 if (mnErrCode
&& nCurError
!= mnErrCode
)
2867 // Error code is specified, and it doesn't match. Skip it.
2870 sc::CellStoreType::position_type aPos
= mrColumn
.GetCellStore().position(miPos
, nRow
);
2872 sc::SharedFormulaUtil::unshareFormulaCell(aPos
, *pCell
);
2873 pCell
->GetCode()->SetCodeError(0);
2874 OUString aFormula
= pCell
->GetFormula(mrCxt
);
2875 pCell
->Compile(mrCxt
, aFormula
, false);
2876 ScColumn::JoinNewFormulaCell(aPos
, *pCell
);
2881 bool isCompiled() const { return mbCompiled
; }
2884 class CalcAfterLoadHandler
2886 sc::CompileFormulaContext
& mrCxt
;
2887 bool mbStartListening
;
2890 CalcAfterLoadHandler( sc::CompileFormulaContext
& rCxt
, bool bStartListening
) :
2891 mrCxt(rCxt
), mbStartListening(bStartListening
) {}
2893 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2895 pCell
->CalcAfterLoad(mrCxt
, mbStartListening
);
2899 struct ResetChangedHandler
2901 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2903 pCell
->SetChanged(false);
2908 * Ambiguous script type counts as edit cell.
2910 class FindEditCellsHandler
2913 sc::CellTextAttrStoreType::iterator miAttrPos
;
2914 sc::CellStoreType::iterator miCellPos
;
2917 FindEditCellsHandler(ScColumn
& rCol
) :
2919 miAttrPos(rCol
.GetCellAttrStore().begin()),
2920 miCellPos(rCol
.GetCellStore().begin()) {}
2922 bool operator() (size_t, const EditTextObject
*)
2924 // This is definitely an edit text cell.
2928 bool operator() (size_t nRow
, const ScFormulaCell
* p
)
2930 // With a formula cell, it's considered an edit text cell when either
2931 // the result is multi-line or it has more than one script types.
2932 SvtScriptType nScriptType
= mrColumn
.GetRangeScriptType(miAttrPos
, nRow
, nRow
, miCellPos
);
2933 if (IsAmbiguousScriptNonZero(nScriptType
))
2936 return const_cast<ScFormulaCell
*>(p
)->IsMultilineResult();
2940 * Callback for a block of other types.
2942 std::pair
<size_t,bool> operator() (const sc::CellStoreType::value_type
& node
, size_t nOffset
, size_t nDataSize
)
2944 typedef std::pair
<size_t,bool> RetType
;
2946 if (node
.type
== sc::element_type_empty
)
2947 // Ignore empty blocks.
2948 return RetType(0, false);
2950 // Check the script type of a non-empty element and see if it has
2951 // multiple script types.
2952 for (size_t i
= 0; i
< nDataSize
; ++i
)
2954 SCROW nRow
= node
.position
+ i
+ nOffset
;
2955 SvtScriptType nScriptType
= mrColumn
.GetRangeScriptType(miAttrPos
, nRow
, nRow
, miCellPos
);
2956 if (IsAmbiguousScriptNonZero(nScriptType
))
2957 // Return the offset from the first row.
2958 return RetType(i
+nOffset
, true);
2961 // No edit text cell found.
2962 return RetType(0, false);
2968 void ScColumn::UpdateTranspose( const ScRange
& rSource
, const ScAddress
& rDest
,
2969 ScDocument
* pUndoDoc
)
2971 UpdateTransHandler
aFunc(*this, rSource
, rDest
, pUndoDoc
);
2972 sc::ProcessFormula(maCells
, aFunc
);
2975 void ScColumn::UpdateGrow( const ScRange
& rArea
, SCCOL nGrowX
, SCROW nGrowY
)
2977 UpdateGrowHandler
aFunc(*this, rArea
, nGrowX
, nGrowY
);
2978 sc::ProcessFormula(maCells
, aFunc
);
2981 void ScColumn::UpdateInsertTab( sc::RefUpdateInsertTabContext
& rCxt
)
2983 if (nTab
>= rCxt
.mnInsertPos
)
2985 nTab
+= rCxt
.mnSheets
;
2986 pAttrArray
->SetTab(nTab
);
2989 UpdateInsertTabOnlyCells(rCxt
);
2992 void ScColumn::UpdateInsertTabOnlyCells( sc::RefUpdateInsertTabContext
& rCxt
)
2994 InsertTabUpdater
aFunc(rCxt
, maCellTextAttrs
, nTab
);
2995 sc::ProcessFormulaEditText(maCells
, aFunc
);
2996 if (aFunc
.isModified())
2997 CellStorageModified();
3000 void ScColumn::UpdateDeleteTab( sc::RefUpdateDeleteTabContext
& rCxt
)
3002 if (nTab
> rCxt
.mnDeletePos
)
3004 nTab
-= rCxt
.mnSheets
;
3005 pAttrArray
->SetTab(nTab
);
3008 DeleteTabUpdater
aFunc(rCxt
, maCellTextAttrs
, nTab
);
3009 sc::ProcessFormulaEditText(maCells
, aFunc
);
3010 if (aFunc
.isModified())
3011 CellStorageModified();
3014 void ScColumn::UpdateInsertTabAbs(SCTAB nNewPos
)
3016 InsertAbsTabUpdater
aFunc(maCellTextAttrs
, nTab
, nNewPos
);
3017 sc::ProcessFormulaEditText(maCells
, aFunc
);
3018 if (aFunc
.isModified())
3019 CellStorageModified();
3022 void ScColumn::UpdateMoveTab( sc::RefUpdateMoveTabContext
& rCxt
, SCTAB nTabNo
)
3025 pAttrArray
->SetTab( nTabNo
);
3027 MoveTabUpdater
aFunc(rCxt
, maCellTextAttrs
, nTab
);
3028 sc::ProcessFormulaEditText(maCells
, aFunc
);
3029 if (aFunc
.isModified())
3030 CellStorageModified();
3033 void ScColumn::UpdateCompile( bool bForceIfNameInUse
)
3035 UpdateCompileHandler
aFunc(bForceIfNameInUse
);
3036 sc::ProcessFormula(maCells
, aFunc
);
3039 void ScColumn::SetTabNo(SCTAB nNewTab
)
3042 pAttrArray
->SetTab( nNewTab
);
3044 TabNoSetter
aFunc(nTab
);
3045 sc::ProcessFormula(maCells
, aFunc
);
3048 void ScColumn::FindRangeNamesInUse(SCROW nRow1
, SCROW nRow2
, std::set
<sal_uInt16
>& rIndexes
) const
3050 UsedRangeNameFinder
aFunc(rIndexes
);
3051 sc::ParseFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aFunc
);
3054 void ScColumn::SetDirtyVar()
3056 SetDirtyVarHandler aFunc
;
3057 sc::ProcessFormula(maCells
, aFunc
);
3060 bool ScColumn::IsFormulaDirty( SCROW nRow
) const
3062 if (!ValidRow(nRow
))
3065 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nRow
);
3066 sc::CellStoreType::const_iterator it
= aPos
.first
;
3067 if (it
->type
!= sc::element_type_formula
)
3068 // This is not a formula cell block.
3071 const ScFormulaCell
* p
= sc::formula_block::at(*it
->data
, aPos
.second
);
3072 return p
->GetDirty();
3075 void ScColumn::SetAllFormulasDirty( const sc::SetFormulaDirtyContext
& rCxt
)
3077 // is only done documentwide, no FormulaTracking
3078 sc::AutoCalcSwitch
aSwitch(*pDocument
, false);
3079 SetDirtyHandler
aFunc(*pDocument
, rCxt
);
3080 sc::ProcessFormula(maCells
, aFunc
);
3083 void ScColumn::SetDirtyFromClip( SCROW nRow1
, SCROW nRow2
, sc::ColumnSpanSet
& rBroadcastSpans
)
3085 // Set all formula cells in the range dirty, and pick up all non-formula
3086 // cells for later broadcasting. We don't broadcast here.
3087 sc::AutoCalcSwitch
aSwitch(*pDocument
, false);
3089 SetDirtyOnRangeHandler
aHdl(*this);
3090 sc::ProcessFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aHdl
, aHdl
);
3091 aHdl
.fillBroadcastSpans(rBroadcastSpans
);
3096 class BroadcastBroadcastersHandler
3099 ScAddress
& mrAddress
;
3103 explicit BroadcastBroadcastersHandler( ScHint
& rHint
)
3105 , mrAddress(mrHint
.GetAddress())
3106 , mbBroadcasted(false)
3110 void operator() ( size_t nRow
, SvtBroadcaster
* pBroadcaster
)
3112 mrAddress
.SetRow(nRow
);
3113 pBroadcaster
->Broadcast(mrHint
);
3114 mbBroadcasted
= true;
3117 bool wasBroadcasted() { return mbBroadcasted
; }
3122 bool ScColumn::BroadcastBroadcasters( SCROW nRow1
, SCROW nRow2
, ScHint
& rHint
)
3124 rHint
.GetAddress().SetCol(nCol
);
3125 BroadcastBroadcastersHandler
aBroadcasterHdl( rHint
);
3126 sc::ProcessBroadcaster(maBroadcasters
.begin(), maBroadcasters
, nRow1
, nRow2
, aBroadcasterHdl
);
3127 return aBroadcasterHdl
.wasBroadcasted();
3130 void ScColumn::SetDirty( SCROW nRow1
, SCROW nRow2
, BroadcastMode eMode
)
3132 // broadcasts everything within the range, with FormulaTracking
3133 sc::AutoCalcSwitch
aSwitch(*pDocument
, false);
3137 case BROADCAST_NONE
:
3139 // Handler only used with formula cells.
3140 SetDirtyOnRangeHandler
aHdl(*this);
3141 sc::ProcessFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aHdl
);
3144 case BROADCAST_DATA_POSITIONS
:
3146 // Handler used with both, formula and non-formula cells.
3147 SetDirtyOnRangeHandler
aHdl(*this);
3148 sc::ProcessFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aHdl
, aHdl
);
3152 case BROADCAST_BROADCASTERS
:
3154 // Handler only used with formula cells.
3155 SetDirtyOnRangeHandler
aHdl(*this);
3156 sc::ProcessFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aHdl
);
3157 // Broadcast all broadcasters in range.
3158 ScHint
aHint( SC_HINT_DATACHANGED
, ScAddress( nCol
, nRow1
, nTab
));
3159 BroadcastBroadcasters( nRow1
, nRow2
, aHint
);
3165 void ScColumn::SetTableOpDirty( const ScRange
& rRange
)
3167 sc::AutoCalcSwitch
aSwitch(*pDocument
, false);
3169 SCROW nRow1
= rRange
.aStart
.Row(), nRow2
= rRange
.aEnd
.Row();
3170 SetTableOpDirtyOnRangeHandler
aHdl(*this);
3171 sc::ProcessFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aHdl
, aHdl
);
3175 void ScColumn::SetDirtyAfterLoad()
3177 sc::AutoCalcSwitch
aSwitch(*pDocument
, false);
3178 SetDirtyAfterLoadHandler aFunc
;
3179 sc::ProcessFormula(maCells
, aFunc
);
3184 class RecalcOnRefMoveCollector
3186 std::vector
<SCROW
> maDirtyRows
;
3188 void operator() (size_t nRow
, ScFormulaCell
* pCell
)
3190 if (pCell
->GetDirty() && pCell
->GetCode()->IsRecalcModeOnRefMove())
3191 maDirtyRows
.push_back(nRow
);
3194 const std::vector
<SCROW
>& getDirtyRows() const
3202 void ScColumn::SetDirtyIfPostponed()
3204 sc::AutoCalcSwitch
aSwitch(*pDocument
, false);
3205 SetDirtyIfPostponedHandler aFunc
;
3206 sc::ProcessFormula(maCells
, aFunc
);
3209 void ScColumn::BroadcastRecalcOnRefMove()
3211 sc::AutoCalcSwitch
aSwitch(*pDocument
, false);
3212 RecalcOnRefMoveCollector aFunc
;
3213 sc::ProcessFormula(maCells
, aFunc
);
3214 BroadcastCells(aFunc
.getDirtyRows(), SC_HINT_DATACHANGED
);
3219 class TransferListenersHandler
3222 typedef std::vector
<SvtListener
*> ListenersType
;
3226 ListenersType maListeners
;
3228 typedef std::vector
<Entry
> ListenerListType
;
3230 void swapListeners( std::vector
<Entry
>& rListenerList
)
3232 maListenerList
.swap(rListenerList
);
3235 void operator() ( size_t nRow
, SvtBroadcaster
* pBroadcaster
)
3237 assert(pBroadcaster
);
3239 // It's important to make a copy here.
3240 SvtBroadcaster::ListenersType aLis
= pBroadcaster
->GetAllListeners();
3242 // No listeners to transfer.
3246 aEntry
.mnRow
= nRow
;
3248 SvtBroadcaster::ListenersType::iterator it
= aLis
.begin(), itEnd
= aLis
.end();
3249 for (; it
!= itEnd
; ++it
)
3251 SvtListener
* pLis
= *it
;
3252 pLis
->EndListening(*pBroadcaster
);
3253 aEntry
.maListeners
.push_back(pLis
);
3256 maListenerList
.push_back(aEntry
);
3258 // At this point, the source broadcaster should have no more listeners.
3259 assert(!pBroadcaster
->HasListeners());
3263 ListenerListType maListenerList
;
3266 class RemoveEmptyBroadcasterHandler
3268 sc::ColumnSpanSet maSet
;
3274 RemoveEmptyBroadcasterHandler( ScDocument
& rDoc
, SCCOL nCol
, SCTAB nTab
) :
3275 maSet(false), mrDoc(rDoc
), mnCol(nCol
), mnTab(nTab
) {}
3277 void operator() ( size_t nRow
, SvtBroadcaster
* pBroadcaster
)
3279 if (!pBroadcaster
->HasListeners())
3280 maSet
.set(mnTab
, mnCol
, nRow
, true);
3285 sc::PurgeListenerAction
aAction(mrDoc
);
3286 maSet
.executeAction(aAction
);
3292 void ScColumn::TransferListeners(
3293 ScColumn
& rDestCol
, SCROW nRow1
, SCROW nRow2
, SCROW nRowDelta
)
3298 if (!ValidRow(nRow1
) || !ValidRow(nRow2
))
3301 if (nRowDelta
<= 0 && !ValidRow(nRow1
+nRowDelta
))
3304 if (nRowDelta
>= 0 && !ValidRow(nRow2
+nRowDelta
))
3307 // Collect all listeners from the source broadcasters. The listeners will
3308 // be removed from their broadcasters as they are collected.
3309 TransferListenersHandler aFunc
;
3310 sc::ProcessBroadcaster(maBroadcasters
.begin(), maBroadcasters
, nRow1
, nRow2
, aFunc
);
3312 TransferListenersHandler::ListenerListType aListenerList
;
3313 aFunc
.swapListeners(aListenerList
);
3315 // Re-register listeners with their destination broadcasters.
3316 sc::BroadcasterStoreType::iterator itDestPos
= rDestCol
.maBroadcasters
.begin();
3317 TransferListenersHandler::ListenerListType::iterator it
= aListenerList
.begin(), itEnd
= aListenerList
.end();
3318 for (; it
!= itEnd
; ++it
)
3320 TransferListenersHandler::Entry
& rEntry
= *it
;
3322 SCROW nDestRow
= rEntry
.mnRow
+ nRowDelta
;
3324 sc::BroadcasterStoreType::position_type aPos
=
3325 rDestCol
.maBroadcasters
.position(itDestPos
, nDestRow
);
3327 itDestPos
= aPos
.first
;
3328 SvtBroadcaster
* pDestBrd
= NULL
;
3329 if (aPos
.first
->type
== sc::element_type_broadcaster
)
3331 // Existing broadcaster.
3332 pDestBrd
= sc::broadcaster_block::at(*aPos
.first
->data
, aPos
.second
);
3336 // No existing broadcaster. Create a new one.
3337 assert(aPos
.first
->type
== sc::element_type_empty
);
3338 pDestBrd
= new SvtBroadcaster
;
3339 itDestPos
= rDestCol
.maBroadcasters
.set(itDestPos
, nDestRow
, pDestBrd
);
3342 // Transfer all listeners from the source to the destination.
3343 SvtBroadcaster::ListenersType::iterator it2
= rEntry
.maListeners
.begin(), it2End
= rEntry
.maListeners
.end();
3344 for (; it2
!= it2End
; ++it2
)
3346 SvtListener
* pLis
= *it2
;
3347 pLis
->StartListening(*pDestBrd
);
3351 // Remove any broadcasters that have no listeners.
3352 RemoveEmptyBroadcasterHandler
aFuncRemoveEmpty(*pDocument
, nCol
, nTab
);
3353 sc::ProcessBroadcaster(maBroadcasters
.begin(), maBroadcasters
, nRow1
, nRow2
, aFuncRemoveEmpty
);
3354 aFuncRemoveEmpty
.purge();
3357 void ScColumn::CalcAll()
3359 CalcAllHandler aFunc
;
3360 sc::ProcessFormula(maCells
, aFunc
);
3363 void ScColumn::CompileAll( sc::CompileFormulaContext
& rCxt
)
3365 CompileAllHandler
aFunc(rCxt
);
3366 sc::ProcessFormula(maCells
, aFunc
);
3369 void ScColumn::CompileXML( sc::CompileFormulaContext
& rCxt
, ScProgress
& rProgress
)
3371 CompileXMLHandler
aFunc(rCxt
, rProgress
, *this);
3372 sc::ProcessFormula(maCells
, aFunc
);
3373 RegroupFormulaCells();
3376 bool ScColumn::CompileErrorCells( sc::CompileFormulaContext
& rCxt
, sal_uInt16 nErrCode
)
3378 CompileErrorCellsHandler
aHdl(rCxt
, *this, nErrCode
);
3379 sc::ProcessFormula(maCells
, aHdl
);
3380 return aHdl
.isCompiled();
3383 void ScColumn::CalcAfterLoad( sc::CompileFormulaContext
& rCxt
, bool bStartListening
)
3385 CalcAfterLoadHandler
aFunc(rCxt
, bStartListening
);
3386 sc::ProcessFormula(maCells
, aFunc
);
3389 void ScColumn::ResetChanged( SCROW nStartRow
, SCROW nEndRow
)
3391 ResetChangedHandler aFunc
;
3392 sc::ProcessFormula(maCells
.begin(), maCells
, nStartRow
, nEndRow
, aFunc
);
3395 bool ScColumn::HasEditCells(SCROW nStartRow
, SCROW nEndRow
, SCROW
& rFirst
)
3397 // used in GetOptimalHeight - ambiguous script type counts as edit cell
3399 FindEditCellsHandler
aFunc(*this);
3400 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
=
3401 sc::FindFormulaEditText(maCells
, nStartRow
, nEndRow
, aFunc
);
3403 if (aPos
.first
== maCells
.end())
3406 rFirst
= aPos
.first
->position
+ aPos
.second
;
3410 SCsROW
ScColumn::SearchStyle(
3411 SCsROW nRow
, const ScStyleSheet
* pSearchStyle
, bool bUp
, bool bInSelection
,
3412 const ScMarkData
& rMark
) const
3416 if (rMark
.IsMultiMarked())
3417 return pAttrArray
->SearchStyle(nRow
, pSearchStyle
, bUp
, rMark
.GetArray()+nCol
);
3422 return pAttrArray
->SearchStyle( nRow
, pSearchStyle
, bUp
, NULL
);
3425 bool ScColumn::SearchStyleRange(
3426 SCsROW
& rRow
, SCsROW
& rEndRow
, const ScStyleSheet
* pSearchStyle
, bool bUp
,
3427 bool bInSelection
, const ScMarkData
& rMark
) const
3431 if (rMark
.IsMultiMarked())
3432 return pAttrArray
->SearchStyleRange(
3433 rRow
, rEndRow
, pSearchStyle
, bUp
, rMark
.GetArray() + nCol
);
3438 return pAttrArray
->SearchStyleRange( rRow
, rEndRow
, pSearchStyle
, bUp
, NULL
);
3441 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */