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"
45 #include <svl/poolcach.hxx>
46 #include <svl/zforlist.hxx>
47 #include "svl/sharedstringpool.hxx"
48 #include <editeng/scripttypeitem.hxx>
49 #include "editeng/fieldupdater.hxx"
54 #include <boost/scoped_ptr.hpp>
56 using ::editeng::SvxBorderLine
;
57 using namespace formula
;
61 inline bool IsAmbiguousScriptNonZero( sal_uInt8 nScript
)
63 //! move to a header file
64 return ( nScript
!= SCRIPTTYPE_LATIN
&&
65 nScript
!= SCRIPTTYPE_ASIAN
&&
66 nScript
!= SCRIPTTYPE_COMPLEX
&&
72 ScNeededSizeOptions::ScNeededSizeOptions() :
73 pPattern(NULL
), bFormula(false), bSkipMerged(true), bGetFont(true), bTotalSize(false)
77 ScColumn::ScColumn() :
78 maCellTextAttrs(MAXROWCOUNT
),
79 maCellNotes(MAXROWCOUNT
),
80 maBroadcasters(MAXROWCOUNT
),
97 void ScColumn::Init(SCCOL nNewCol
, SCTAB nNewTab
, ScDocument
* pDoc
)
102 pAttrArray
= new ScAttrArray( nCol
, nTab
, pDocument
);
106 SCsROW
ScColumn::GetNextUnprotected( SCROW nRow
, bool bUp
) const
108 return pAttrArray
->GetNextUnprotected(nRow
, bUp
);
112 sal_uInt16
ScColumn::GetBlockMatrixEdges( SCROW nRow1
, SCROW nRow2
, sal_uInt16 nMask
) const
116 if (!ValidRow(nRow1
) || !ValidRow(nRow2
) || nRow1
> nRow2
)
119 ScAddress
aOrigin(ScAddress::INITIALIZE_INVALID
);
123 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nRow1
);
124 if (aPos
.first
->type
!= sc::element_type_formula
)
127 const ScFormulaCell
* pCell
= sc::formula_block::at(*aPos
.first
->data
, aPos
.second
);
128 if (!pCell
->GetMatrixFlag())
131 return pCell
->GetMatrixEdge(aOrigin
);
135 sal_uInt16 nEdges
= 0;
137 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nRow1
);
138 sc::CellStoreType::const_iterator it
= aPos
.first
;
139 size_t nOffset
= aPos
.second
;
141 for (;it
!= maCells
.end() && nRow
<= nRow2
; ++it
, nOffset
= 0)
143 if (it
->type
!= sc::element_type_formula
)
146 nRow
+= it
->size
- nOffset
;
150 size_t nRowsToRead
= nRow2
- nRow
+ 1;
151 size_t nEnd
= std::min(it
->size
, nRowsToRead
);
152 sc::formula_block::const_iterator itCell
= sc::formula_block::begin(*it
->data
);
153 std::advance(itCell
, nOffset
);
154 for (size_t i
= nOffset
; i
< nEnd
; ++itCell
, ++i
)
156 // Loop inside the formula block.
157 const ScFormulaCell
* pCell
= *itCell
;
158 if (!pCell
->GetMatrixFlag())
161 nEdges
= pCell
->GetMatrixEdge(aOrigin
);
165 if (nEdges
& MatrixEdgeTop
)
166 bOpen
= true; // top edge opens, keep on looking
168 return nEdges
| MatrixEdgeOpen
; // there's something that wasn't opened
169 else if (nEdges
& MatrixEdgeInside
)
170 return nEdges
; // inside
171 // (nMask & 16 and (4 and not 16)) or
172 // (nMask & 4 and (16 and not 4))
173 if (((nMask
& MatrixEdgeRight
) && (nEdges
& MatrixEdgeLeft
) && !(nEdges
& MatrixEdgeRight
)) ||
174 ((nMask
& MatrixEdgeLeft
) && (nEdges
& MatrixEdgeRight
) && !(nEdges
& MatrixEdgeLeft
)))
175 return nEdges
; // only left/right edge
177 if (nEdges
& MatrixEdgeBottom
)
178 bOpen
= false; // bottom edge closes
184 nEdges
|= MatrixEdgeOpen
; // not closed, matrix continues
190 bool ScColumn::HasSelectionMatrixFragment(const ScMarkData
& rMark
) const
194 if (!rMark
.IsMultiMarked())
197 ScAddress
aOrigin(ScAddress::INITIALIZE_INVALID
);
198 ScAddress aCurOrigin
= aOrigin
;
201 ScRangeList aRanges
= rMark
.GetMarkedRanges();
202 for (size_t i
= 0, n
= aRanges
.size(); i
< n
; ++i
)
204 const ScRange
& r
= *aRanges
[i
];
205 if (nTab
< r
.aStart
.Tab() || r
.aEnd
.Tab() < nTab
)
208 if (nCol
< r
.aStart
.Col() || r
.aEnd
.Col() < nCol
)
211 SCROW nTop
= r
.aStart
.Row(), nBottom
= r
.aEnd
.Row();
213 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nRow
);
214 sc::CellStoreType::const_iterator it
= aPos
.first
;
215 size_t nOffset
= aPos
.second
;
217 for (;it
!= maCells
.end() && nRow
<= nBottom
; ++it
, nOffset
= 0)
219 if (it
->type
!= sc::element_type_formula
)
222 nRow
+= it
->size
- nOffset
;
226 // This is a formula cell block.
227 size_t nRowsToRead
= nBottom
- nRow
+ 1;
228 size_t nEnd
= std::min(it
->size
, nRowsToRead
);
229 sc::formula_block::const_iterator itCell
= sc::formula_block::begin(*it
->data
);
230 std::advance(itCell
, nOffset
);
231 for (size_t j
= nOffset
; j
< nEnd
; ++itCell
, ++j
)
233 // Loop inside the formula block.
234 const ScFormulaCell
* pCell
= *itCell
;
235 if (!pCell
->GetMatrixFlag())
236 // cell is not a part of a matrix.
239 sal_uInt16 nEdges
= pCell
->GetMatrixEdge(aOrigin
);
245 if (nEdges
& MatrixEdgeTop
)
246 bOpen
= true; // top edge opens, keep on looking
248 return true; // there's something that wasn't opened
249 else if (nEdges
& MatrixEdgeInside
)
250 bFound
= true; // inside, all selected?
252 if ((((nEdges
& MatrixEdgeLeft
) | MatrixEdgeRight
) ^ ((nEdges
& MatrixEdgeRight
) | MatrixEdgeLeft
)))
253 // either left or right, but not both.
254 bFound
= true; // only left/right edge, all selected?
256 if (nEdges
& MatrixEdgeBottom
)
257 bOpen
= false; // bottom edge closes
261 // Check if the matrix is inside the selection in its entirety.
263 // TODO: It's more efficient to skip the matrix range if
264 // it's within selection, to avoid checking it again and
267 if (aCurOrigin
!= aOrigin
)
268 { // new matrix to check?
269 aCurOrigin
= aOrigin
;
270 const ScFormulaCell
* pFCell
;
271 if (pCell
->GetMatrixFlag() == MM_REFERENCE
)
272 pFCell
= pDocument
->GetFormulaCell(aOrigin
);
278 pFCell
->GetMatColsRows(nC
, nR
);
279 ScRange
aRange(aOrigin
, ScAddress(aOrigin
.Col()+nC
-1, aOrigin
.Row()+nR
-1, aOrigin
.Tab()));
280 if (rMark
.IsAllMarked(aRange
))
284 bFound
= false; // done already
302 bool ScColumn::HasAttrib( SCROW nRow1
, SCROW nRow2
, sal_uInt16 nMask
) const
304 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
))
329 bool ScColumn::ExtendMerge( SCCOL nThisCol
, SCROW nStartRow
, SCROW nEndRow
,
330 SCCOL
& rPaintCol
, SCROW
& rPaintRow
,
333 return pAttrArray
->ExtendMerge( nThisCol
, nStartRow
, nEndRow
, rPaintCol
, rPaintRow
, bRefresh
);
337 void ScColumn::MergeSelectionPattern( ScMergePatternState
& rState
, const ScMarkData
& rMark
, bool bDeep
) const
342 if ( rMark
.IsMultiMarked() )
344 const ScMarkArray
* pArray
= rMark
.GetArray() + nCol
;
345 if ( pArray
->HasMarks() )
347 ScMarkArrayIter
aMarkIter( pArray
);
348 while (aMarkIter
.Next( nTop
, nBottom
))
349 pAttrArray
->MergePatternArea( nTop
, nBottom
, rState
, bDeep
);
355 void ScColumn::MergePatternArea( ScMergePatternState
& rState
, SCROW nRow1
, SCROW nRow2
, bool bDeep
) const
357 pAttrArray
->MergePatternArea( nRow1
, nRow2
, rState
, bDeep
);
361 void ScColumn::MergeBlockFrame( SvxBoxItem
* pLineOuter
, SvxBoxInfoItem
* pLineInner
,
363 SCROW nStartRow
, SCROW nEndRow
, bool bLeft
, SCCOL nDistRight
) const
365 pAttrArray
->MergeBlockFrame( pLineOuter
, pLineInner
, rFlags
, nStartRow
, nEndRow
, bLeft
, nDistRight
);
369 void ScColumn::ApplyBlockFrame( const SvxBoxItem
* pLineOuter
, const SvxBoxInfoItem
* pLineInner
,
370 SCROW nStartRow
, SCROW nEndRow
, bool bLeft
, SCCOL nDistRight
)
372 pAttrArray
->ApplyBlockFrame( pLineOuter
, pLineInner
, nStartRow
, nEndRow
, bLeft
, nDistRight
);
376 const ScPatternAttr
* ScColumn::GetPattern( SCROW nRow
) const
378 return pAttrArray
->GetPattern( nRow
);
382 const SfxPoolItem
* ScColumn::GetAttr( SCROW nRow
, sal_uInt16 nWhich
) const
384 return &pAttrArray
->GetPattern( nRow
)->GetItemSet().Get(nWhich
);
388 const ScPatternAttr
* ScColumn::GetMostUsedPattern( SCROW nStartRow
, SCROW nEndRow
) const
390 ::std::map
< const ScPatternAttr
*, size_t > aAttrMap
;
391 const ScPatternAttr
* pMaxPattern
= 0;
392 size_t nMaxCount
= 0;
394 ScAttrIterator
aAttrIter( pAttrArray
, nStartRow
, nEndRow
);
395 const ScPatternAttr
* pPattern
;
396 SCROW nAttrRow1
= 0, nAttrRow2
= 0;
398 while( (pPattern
= aAttrIter
.Next( nAttrRow1
, nAttrRow2
)) != 0 )
400 size_t& rnCount
= aAttrMap
[ pPattern
];
401 rnCount
+= (nAttrRow2
- nAttrRow1
+ 1);
402 if( rnCount
> nMaxCount
)
404 pMaxPattern
= pPattern
;
412 sal_uInt32
ScColumn::GetNumberFormat( SCROW nStartRow
, SCROW nEndRow
) const
414 SCROW nPatStartRow
, nPatEndRow
;
415 const ScPatternAttr
* pPattern
= pAttrArray
->GetPatternRange(nPatStartRow
, nPatEndRow
, nStartRow
);
416 sal_uInt32 nFormat
= pPattern
->GetNumberFormat(pDocument
->GetFormatTable());
417 while (nEndRow
> nPatEndRow
)
419 nStartRow
= nPatEndRow
+ 1;
420 pPattern
= pAttrArray
->GetPatternRange(nPatStartRow
, nPatEndRow
, nStartRow
);
421 sal_uInt32 nTmpFormat
= pPattern
->GetNumberFormat(pDocument
->GetFormatTable());
422 if (nFormat
!= nTmpFormat
)
429 sal_uInt32
ScColumn::GetNumberFormat( SCROW nRow
) const
431 return pAttrArray
->GetPattern( nRow
)->GetNumberFormat( pDocument
->GetFormatTable() );
435 SCsROW
ScColumn::ApplySelectionCache( SfxItemPoolCache
* pCache
, const ScMarkData
& rMark
, ScEditDataArray
* pDataArray
)
441 if ( rMark
.IsMultiMarked() )
443 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
444 while (aMarkIter
.Next( nTop
, nBottom
))
446 pAttrArray
->ApplyCacheArea( nTop
, nBottom
, pCache
, pDataArray
);
453 else if (nTop
==0 && nBottom
==MAXROW
)
460 void ScColumn::ChangeSelectionIndent( bool bIncrement
, const ScMarkData
& rMark
)
465 if ( pAttrArray
&& rMark
.IsMultiMarked() )
467 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
468 while (aMarkIter
.Next( nTop
, nBottom
))
469 pAttrArray
->ChangeIndent(nTop
, nBottom
, bIncrement
);
473 void ScColumn::ClearSelectionItems( const sal_uInt16
* pWhich
,const ScMarkData
& rMark
)
478 if ( pAttrArray
&& rMark
.IsMultiMarked() )
480 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
481 while (aMarkIter
.Next( nTop
, nBottom
))
482 pAttrArray
->ClearItems(nTop
, nBottom
, pWhich
);
487 void ScColumn::DeleteSelection( sal_uInt16 nDelFlag
, const ScMarkData
& rMark
)
492 if ( rMark
.IsMultiMarked() )
494 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
495 while (aMarkIter
.Next( nTop
, nBottom
))
496 DeleteArea(nTop
, nBottom
, nDelFlag
);
501 void ScColumn::ApplyPattern( SCROW nRow
, const ScPatternAttr
& rPatAttr
)
503 const SfxItemSet
* pSet
= &rPatAttr
.GetItemSet();
504 SfxItemPoolCache
aCache( pDocument
->GetPool(), pSet
);
506 const ScPatternAttr
* pPattern
= pAttrArray
->GetPattern( nRow
);
508 // true = keep old content
510 ScPatternAttr
* pNewPattern
= (ScPatternAttr
*) &aCache
.ApplyTo( *pPattern
, true );
511 ScDocumentPool::CheckRef( *pPattern
);
512 ScDocumentPool::CheckRef( *pNewPattern
);
514 if (pNewPattern
!= pPattern
)
515 pAttrArray
->SetPattern( nRow
, pNewPattern
);
519 void ScColumn::ApplyPatternArea( SCROW nStartRow
, SCROW nEndRow
, const ScPatternAttr
& rPatAttr
,
520 ScEditDataArray
* pDataArray
)
522 const SfxItemSet
* pSet
= &rPatAttr
.GetItemSet();
523 SfxItemPoolCache
aCache( pDocument
->GetPool(), pSet
);
524 pAttrArray
->ApplyCacheArea( nStartRow
, nEndRow
, &aCache
, pDataArray
);
527 bool ScColumn::SetAttrEntries(ScAttrEntry
* pData
, SCSIZE nSize
)
529 return pAttrArray
->SetAttrEntries(pData
, nSize
);
532 void ScColumn::ApplyPatternIfNumberformatIncompatible( const ScRange
& rRange
,
533 const ScPatternAttr
& rPattern
, short nNewType
)
535 const SfxItemSet
* pSet
= &rPattern
.GetItemSet();
536 SfxItemPoolCache
aCache( pDocument
->GetPool(), pSet
);
537 SvNumberFormatter
* pFormatter
= pDocument
->GetFormatTable();
538 SCROW nEndRow
= rRange
.aEnd
.Row();
539 for ( SCROW nRow
= rRange
.aStart
.Row(); nRow
<= nEndRow
; nRow
++ )
542 const ScPatternAttr
* pPattern
= pAttrArray
->GetPatternRange(
543 nRow1
, nRow2
, nRow
);
544 sal_uInt32 nFormat
= pPattern
->GetNumberFormat( pFormatter
);
545 short nOldType
= pFormatter
->GetType( nFormat
);
546 if ( nOldType
== nNewType
|| pFormatter
->IsCompatible( nOldType
, nNewType
) )
550 SCROW nNewRow1
= std::max( nRow1
, nRow
);
551 SCROW nNewRow2
= std::min( nRow2
, nEndRow
);
552 pAttrArray
->ApplyCacheArea( nNewRow1
, nNewRow2
, &aCache
);
558 void ScColumn::AddCondFormat( SCROW nStartRow
, SCROW nEndRow
, sal_uInt32 nIndex
)
560 pAttrArray
->AddCondFormat( nStartRow
, nEndRow
, nIndex
);
563 void ScColumn::RemoveCondFormat( SCROW nStartRow
, SCROW nEndRow
, sal_uInt32 nIndex
)
565 pAttrArray
->RemoveCondFormat( nStartRow
, nEndRow
, nIndex
);
569 void ScColumn::ApplyStyle( SCROW nRow
, const ScStyleSheet
& rStyle
)
571 const ScPatternAttr
* pPattern
= pAttrArray
->GetPattern(nRow
);
572 ScPatternAttr
* pNewPattern
= new ScPatternAttr(*pPattern
);
575 pNewPattern
->SetStyleSheet((ScStyleSheet
*)&rStyle
);
576 pAttrArray
->SetPattern(nRow
, pNewPattern
, true);
582 void ScColumn::ApplyStyleArea( SCROW nStartRow
, SCROW nEndRow
, const ScStyleSheet
& rStyle
)
584 pAttrArray
->ApplyStyleArea(nStartRow
, nEndRow
, (ScStyleSheet
*)&rStyle
);
588 void ScColumn::ApplySelectionStyle(const ScStyleSheet
& rStyle
, const ScMarkData
& rMark
)
593 if ( rMark
.IsMultiMarked() )
595 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
596 while (aMarkIter
.Next( nTop
, nBottom
))
597 pAttrArray
->ApplyStyleArea(nTop
, nBottom
, (ScStyleSheet
*)&rStyle
);
602 void ScColumn::ApplySelectionLineStyle( const ScMarkData
& rMark
,
603 const SvxBorderLine
* pLine
, bool bColorOnly
)
605 if ( bColorOnly
&& !pLine
)
611 if (rMark
.IsMultiMarked())
613 ScMarkArrayIter
aMarkIter( rMark
.GetArray()+nCol
);
614 while (aMarkIter
.Next( nTop
, nBottom
))
615 pAttrArray
->ApplyLineStyleArea(nTop
, nBottom
, pLine
, bColorOnly
);
620 const ScStyleSheet
* ScColumn::GetStyle( SCROW nRow
) const
622 return pAttrArray
->GetPattern( nRow
)->GetStyleSheet();
626 const ScStyleSheet
* ScColumn::GetSelectionStyle( const ScMarkData
& rMark
, bool& rFound
) const
629 if (!rMark
.IsMultiMarked())
631 OSL_FAIL("No selection in ScColumn::GetSelectionStyle");
637 const ScStyleSheet
* pStyle
= NULL
;
638 const ScStyleSheet
* pNewStyle
;
640 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
643 while (bEqual
&& aMarkIter
.Next( nTop
, nBottom
))
645 ScAttrIterator
aAttrIter( pAttrArray
, nTop
, nBottom
);
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
659 return bEqual
? pStyle
: NULL
;
663 const ScStyleSheet
* ScColumn::GetAreaStyle( bool& rFound
, SCROW nRow1
, SCROW nRow2
) const
669 const ScStyleSheet
* pStyle
= NULL
;
670 const ScStyleSheet
* pNewStyle
;
672 ScAttrIterator
aAttrIter( pAttrArray
, nRow1
, nRow2
);
675 const ScPatternAttr
* pPattern
;
676 while (bEqual
&& ( pPattern
= aAttrIter
.Next( nRow
, nDummy
) ) != NULL
)
678 pNewStyle
= pPattern
->GetStyleSheet();
680 if ( !pNewStyle
|| ( pStyle
&& pNewStyle
!= pStyle
) )
681 bEqual
= false; // difference
685 return bEqual
? pStyle
: NULL
;
688 void ScColumn::FindStyleSheet( const SfxStyleSheetBase
* pStyleSheet
, ScFlatBoolRowSegments
& rUsedRows
, bool bReset
)
690 pAttrArray
->FindStyleSheet( pStyleSheet
, rUsedRows
, bReset
);
693 bool ScColumn::IsStyleSheetUsed( const ScStyleSheet
& rStyle
, bool bGatherAllStyles
) const
695 return pAttrArray
->IsStyleSheetUsed( rStyle
, bGatherAllStyles
);
699 bool ScColumn::ApplyFlags( SCROW nStartRow
, SCROW nEndRow
, sal_Int16 nFlags
)
701 return pAttrArray
->ApplyFlags( nStartRow
, nEndRow
, nFlags
);
705 bool ScColumn::RemoveFlags( SCROW nStartRow
, SCROW nEndRow
, sal_Int16 nFlags
)
707 return pAttrArray
->RemoveFlags( nStartRow
, nEndRow
, nFlags
);
711 void ScColumn::ClearItems( SCROW nStartRow
, SCROW nEndRow
, const sal_uInt16
* pWhich
)
713 pAttrArray
->ClearItems( nStartRow
, nEndRow
, pWhich
);
717 void ScColumn::SetPattern( SCROW nRow
, const ScPatternAttr
& rPatAttr
, bool bPutToPool
)
719 pAttrArray
->SetPattern( nRow
, &rPatAttr
, bPutToPool
);
723 void ScColumn::SetPatternArea( SCROW nStartRow
, SCROW nEndRow
,
724 const ScPatternAttr
& rPatAttr
, bool bPutToPool
)
726 pAttrArray
->SetPatternArea( nStartRow
, nEndRow
, &rPatAttr
, bPutToPool
);
730 void ScColumn::ApplyAttr( SCROW nRow
, const SfxPoolItem
& rAttr
)
732 // in order to only create a new SetItem, we don't need SfxItemPoolCache.
733 //! Warning: SfxItemPoolCache seems to create to many Refs for the new SetItem ??
735 ScDocumentPool
* pDocPool
= pDocument
->GetPool();
737 const ScPatternAttr
* pOldPattern
= pAttrArray
->GetPattern( nRow
);
738 ScPatternAttr
* pTemp
= new ScPatternAttr(*pOldPattern
);
739 pTemp
->GetItemSet().Put(rAttr
);
740 const ScPatternAttr
* pNewPattern
= (const ScPatternAttr
*) &pDocPool
->Put( *pTemp
);
742 if ( pNewPattern
!= pOldPattern
)
743 pAttrArray
->SetPattern( nRow
, pNewPattern
);
745 pDocPool
->Remove( *pNewPattern
); // free up resources
750 ScDocument
& ScColumn::GetDoc()
755 const ScDocument
& ScColumn::GetDoc() const
760 ScRefCellValue
ScColumn::GetCellValue( SCROW nRow
) const
762 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nRow
);
763 if (aPos
.first
== maCells
.end())
764 return ScRefCellValue();
766 return GetCellValue(aPos
.first
, aPos
.second
);
769 ScRefCellValue
ScColumn::GetCellValue( const sc::CellStoreType::const_iterator
& itPos
, size_t nOffset
) const
771 ScRefCellValue aVal
; // Defaults to empty cell.
774 case sc::element_type_numeric
:
776 aVal
.mfValue
= sc::numeric_block::at(*itPos
->data
, nOffset
);
777 aVal
.meType
= CELLTYPE_VALUE
;
779 case sc::element_type_string
:
781 aVal
.mpString
= &sc::string_block::at(*itPos
->data
, nOffset
);
782 aVal
.meType
= CELLTYPE_STRING
;
784 case sc::element_type_edittext
:
786 aVal
.mpEditText
= sc::edittext_block::at(*itPos
->data
, nOffset
);
787 aVal
.meType
= CELLTYPE_EDIT
;
789 case sc::element_type_formula
:
791 aVal
.mpFormula
= sc::formula_block::at(*itPos
->data
, nOffset
);
792 aVal
.meType
= CELLTYPE_FORMULA
;
803 ScFormulaCell
* cloneFormulaCell(ScDocument
* pDoc
, const ScAddress
& rNewPos
, ScFormulaCell
& rOldCell
)
805 ScFormulaCell
* pNew
= new ScFormulaCell(rOldCell
, *pDoc
, rNewPos
, SC_CLONECELL_ADJUST3DREL
);
806 rOldCell
.EndListeningTo(pDoc
);
807 pNew
->StartListeningTo(pDoc
);
814 void ScColumn::SwapRow(SCROW nRow1
, SCROW nRow2
)
820 // Ensure that nRow1 < nRow2.
822 std::swap(nRow1
, nRow2
);
824 // Broadcasters (if exist) should NOT be swapped.
826 sc::CellStoreType::position_type aPos1
= maCells
.position(nRow1
);
827 if (aPos1
.first
== maCells
.end())
830 sc::CellStoreType::position_type aPos2
= maCells
.position(aPos1
.first
, nRow2
);
831 if (aPos2
.first
== maCells
.end())
834 std::vector
<SCROW
> aRows
;
836 aRows
.push_back(nRow1
);
837 aRows
.push_back(nRow2
);
839 sc::CellStoreType::iterator it1
= aPos1
.first
, it2
= aPos2
.first
;
841 if (it1
->type
== it2
->type
)
843 // Both positions are of the same type. Do a simple value swap.
846 case sc::element_type_empty
:
847 // Both are empty. Nothing to swap.
849 case sc::element_type_numeric
:
851 sc::numeric_block::at(*it1
->data
, aPos1
.second
),
852 sc::numeric_block::at(*it2
->data
, aPos2
.second
));
854 case sc::element_type_string
:
856 sc::string_block::at(*it1
->data
, aPos1
.second
),
857 sc::string_block::at(*it2
->data
, aPos2
.second
));
859 case sc::element_type_edittext
:
861 sc::edittext_block::at(*it1
->data
, aPos1
.second
),
862 sc::edittext_block::at(*it2
->data
, aPos2
.second
));
864 case sc::element_type_formula
:
866 // Swapping of formula cells involve adjustment of references wrt their positions.
867 sc::formula_block::iterator itf1
= sc::formula_block::begin(*it1
->data
);
868 sc::formula_block::iterator itf2
= sc::formula_block::begin(*it2
->data
);
869 std::advance(itf1
, aPos1
.second
);
870 std::advance(itf2
, aPos2
.second
);
872 // TODO: Find out a way to adjust references without cloning new instances.
873 boost::scoped_ptr
<ScFormulaCell
> pOld1(*itf1
);
874 boost::scoped_ptr
<ScFormulaCell
> pOld2(*itf2
);
875 DetachFormulaCell(aPos1
, **itf1
);
876 DetachFormulaCell(aPos2
, **itf2
);
877 ScFormulaCell
* pNew1
= cloneFormulaCell(pDocument
, ScAddress(nCol
, nRow1
, nTab
), *pOld2
);
878 ScFormulaCell
* pNew2
= cloneFormulaCell(pDocument
, ScAddress(nCol
, nRow2
, nTab
), *pOld1
);
882 ActivateNewFormulaCell(aPos1
, *pNew1
);
883 ActivateNewFormulaCell(aPos2
, *pNew2
);
890 SwapCellTextAttrs(nRow1
, nRow2
);
891 SwapCellNotes(nRow1
, nRow2
);
892 CellStorageModified();
893 BroadcastCells(aRows
, SC_HINT_DATACHANGED
);
897 // The two cells are of different types.
899 ScRefCellValue aCell1
= GetCellValue(aPos1
.first
, aPos1
.second
);
900 ScRefCellValue aCell2
= GetCellValue(aPos2
.first
, aPos2
.second
);
902 // Make sure to put cells in row 1 first then row 2!
904 if (aCell1
.meType
== CELLTYPE_NONE
)
906 // cell 1 is empty and cell 2 is not.
907 switch (aCell2
.meType
)
910 it1
= maCells
.set(it1
, nRow1
, aCell2
.mfValue
); // it2 becomes invalid.
911 maCells
.set_empty(it1
, nRow2
, nRow2
);
913 case CELLTYPE_STRING
:
914 it1
= maCells
.set(it1
, nRow1
, *aCell2
.mpString
);
915 maCells
.set_empty(it1
, nRow2
, nRow2
);
920 it1
, nRow1
, const_cast<EditTextObject
*>(aCell2
.mpEditText
));
922 maCells
.release(it1
, nRow2
, p
);
925 case CELLTYPE_FORMULA
:
927 // cell 1 is empty and cell 2 is a formula cell.
928 ScFormulaCell
* pNew
= cloneFormulaCell(pDocument
, ScAddress(nCol
, nRow1
, nTab
), *aCell2
.mpFormula
);
929 DetachFormulaCell(aPos2
, *aCell2
.mpFormula
);
930 it1
= maCells
.set(it1
, nRow1
, pNew
);
931 maCells
.set_empty(it1
, nRow2
, nRow2
); // original formula cell gets deleted.
932 ActivateNewFormulaCell(it1
, nRow1
, *pNew
);
939 SwapCellTextAttrs(nRow1
, nRow2
);
940 SwapCellNotes(nRow1
, nRow2
);
941 CellStorageModified();
942 BroadcastCells(aRows
, SC_HINT_DATACHANGED
);
946 if (aCell2
.meType
== CELLTYPE_NONE
)
948 // cell 1 is not empty and cell 2 is empty.
949 switch (aCell1
.meType
)
952 // Value is copied in Cell1.
953 it1
= maCells
.set_empty(it1
, nRow1
, nRow1
);
954 maCells
.set(it1
, nRow2
, aCell1
.mfValue
);
956 case CELLTYPE_STRING
:
958 svl::SharedString aStr
= *aCell1
.mpString
; // make a copy.
959 it1
= maCells
.set_empty(it1
, nRow1
, nRow1
); // original string is gone.
960 maCells
.set(it1
, nRow2
, aStr
);
966 it1
= maCells
.release(it1
, nRow1
, p
);
967 maCells
.set(it1
, nRow2
, p
);
970 case CELLTYPE_FORMULA
:
972 // cell 1 is a formula cell and cell 2 is empty.
973 ScFormulaCell
* pNew
= cloneFormulaCell(pDocument
, ScAddress(nCol
, nRow2
, nTab
), *aCell1
.mpFormula
);
974 DetachFormulaCell(aPos1
, *aCell1
.mpFormula
);
975 it1
= maCells
.set_empty(it1
, nRow1
, nRow1
); // original formula cell is gone.
976 it1
= maCells
.set(it1
, nRow2
, pNew
);
977 ActivateNewFormulaCell(it1
, nRow2
, *pNew
);
984 SwapCellTextAttrs(nRow1
, nRow2
);
985 SwapCellNotes(nRow1
, nRow2
);
986 CellStorageModified();
987 BroadcastCells(aRows
, SC_HINT_DATACHANGED
);
991 // Neither cells are empty, and they are of different types.
992 switch (aCell1
.meType
)
996 switch (aCell2
.meType
)
998 case CELLTYPE_STRING
:
999 it1
= maCells
.set(it1
, nRow1
, *aCell2
.mpString
);
1004 it1
, nRow1
, const_cast<EditTextObject
*>(aCell2
.mpEditText
));
1006 it1
= maCells
.release(it1
, nRow2
, p
);
1009 case CELLTYPE_FORMULA
:
1011 DetachFormulaCell(aPos2
, *aCell2
.mpFormula
);
1012 ScFormulaCell
* pNew
= cloneFormulaCell(pDocument
, ScAddress(nCol
, nRow1
, nTab
), *aCell2
.mpFormula
);
1013 it1
= maCells
.set(it1
, nRow1
, pNew
);
1014 ActivateNewFormulaCell(it1
, nRow1
, *pNew
);
1015 // The old formula cell will get overwritten below.
1022 maCells
.set(it1
, nRow2
, aCell1
.mfValue
);
1026 case CELLTYPE_STRING
:
1028 svl::SharedString aStr
= *aCell1
.mpString
; // make a copy.
1029 switch (aCell2
.meType
)
1031 case CELLTYPE_VALUE
:
1032 it1
= maCells
.set(it1
, nRow1
, aCell2
.mfValue
);
1037 it1
, nRow1
, const_cast<EditTextObject
*>(aCell2
.mpEditText
));
1039 it1
= maCells
.release(it1
, nRow2
, p
); // prevent it being overwritten.
1042 case CELLTYPE_FORMULA
:
1044 // cell 1 - string, cell 2 - formula
1045 DetachFormulaCell(aPos2
, *aCell2
.mpFormula
);
1046 ScFormulaCell
* pNew
= cloneFormulaCell(pDocument
, ScAddress(nCol
, nRow1
, nTab
), *aCell2
.mpFormula
);
1047 it1
= maCells
.set(it1
, nRow1
, pNew
);
1048 ActivateNewFormulaCell(it1
, nRow1
, *pNew
);
1049 // Old formula cell will get overwritten below.
1056 maCells
.set(it1
, nRow2
, aStr
);
1062 it1
= maCells
.release(it1
, nRow1
, p
);
1064 switch (aCell2
.meType
)
1066 case CELLTYPE_VALUE
:
1067 it1
= maCells
.set(it1
, nRow1
, aCell2
.mfValue
);
1069 case CELLTYPE_STRING
:
1070 it1
= maCells
.set(it1
, nRow1
, *aCell2
.mpString
);
1072 case CELLTYPE_FORMULA
:
1074 DetachFormulaCell(aPos2
, *aCell2
.mpFormula
);
1075 ScFormulaCell
* pNew
= cloneFormulaCell(pDocument
, ScAddress(nCol
, nRow1
, nTab
), *aCell2
.mpFormula
);
1076 it1
= maCells
.set(it1
, nRow1
, pNew
);
1077 ActivateNewFormulaCell(it1
, nRow1
, *pNew
);
1078 // Old formula cell will get overwritten below.
1085 maCells
.set(it1
, nRow2
, const_cast<EditTextObject
*>(aCell1
.mpEditText
));
1088 case CELLTYPE_FORMULA
:
1090 // cell 1 is a formula cell and cell 2 is not.
1091 DetachFormulaCell(aPos1
, *aCell1
.mpFormula
);
1092 ScFormulaCell
* pNew
= cloneFormulaCell(pDocument
, ScAddress(nCol
, nRow2
, nTab
), *aCell1
.mpFormula
);
1093 switch (aCell2
.meType
)
1095 case CELLTYPE_VALUE
:
1096 it1
= maCells
.set(it1
, nRow1
, aCell2
.mfValue
);
1098 case CELLTYPE_STRING
:
1099 it1
= maCells
.set(it1
, nRow1
, *aCell2
.mpString
);
1103 it1
= maCells
.set(it1
, nRow1
, aCell2
.mpEditText
);
1105 it1
= maCells
.release(it1
, nRow2
, p
);
1112 it1
= maCells
.set(it1
, nRow2
, pNew
);
1113 ActivateNewFormulaCell(it1
, nRow2
, *pNew
);
1120 SwapCellTextAttrs(nRow1
, nRow2
);
1121 SwapCellNotes(nRow1
, nRow2
);
1122 CellStorageModified();
1123 BroadcastCells(aRows
, SC_HINT_DATACHANGED
);
1129 * Adjust references in formula cell with respect to column-wise relocation.
1131 void updateRefInFormulaCell( ScDocument
* pDoc
, ScFormulaCell
& rCell
, SCCOL nCol
, SCTAB nTab
, SCCOL nColDiff
)
1133 rCell
.aPos
.SetCol(nCol
);
1134 sc::RefUpdateContext
aCxt(*pDoc
);
1135 aCxt
.meMode
= URM_MOVE
;
1136 aCxt
.maRange
= ScRange(ScAddress(nCol
, 0, nTab
), ScAddress(nCol
, MAXROW
, nTab
));
1137 aCxt
.mnColDelta
= nColDiff
;
1138 rCell
.UpdateReference(aCxt
);
1143 void ScColumn::SwapCell( SCROW nRow
, ScColumn
& rCol
)
1145 sc::CellStoreType::position_type aPos1
= maCells
.position(nRow
);
1146 sc::CellStoreType::position_type aPos2
= rCol
.maCells
.position(nRow
);
1148 if (aPos1
.first
->type
== sc::element_type_formula
)
1150 ScFormulaCell
& rCell
= *sc::formula_block::at(*aPos1
.first
->data
, aPos1
.second
);
1151 updateRefInFormulaCell(pDocument
, rCell
, rCol
.nCol
, nTab
, rCol
.nCol
- nCol
);
1152 sc::SharedFormulaUtil::unshareFormulaCell(aPos1
, rCell
);
1155 if (aPos2
.first
->type
== sc::element_type_formula
)
1157 ScFormulaCell
& rCell
= *sc::formula_block::at(*aPos2
.first
->data
, aPos2
.second
);
1158 updateRefInFormulaCell(pDocument
, rCell
, nCol
, nTab
, nCol
- rCol
.nCol
);
1159 sc::SharedFormulaUtil::unshareFormulaCell(aPos2
, rCell
);
1162 maCells
.swap(nRow
, nRow
, rCol
.maCells
, nRow
);
1163 maCellTextAttrs
.swap(nRow
, nRow
, rCol
.maCellTextAttrs
, nRow
);
1164 maCellNotes
.swap(nRow
, nRow
, rCol
.maCellNotes
, nRow
);
1166 aPos1
= maCells
.position(nRow
);
1167 aPos2
= rCol
.maCells
.position(nRow
);
1169 if (aPos1
.first
->type
== sc::element_type_formula
)
1171 ScFormulaCell
& rCell
= *sc::formula_block::at(*aPos1
.first
->data
, aPos1
.second
);
1172 JoinNewFormulaCell(aPos1
, rCell
);
1175 if (aPos2
.first
->type
== sc::element_type_formula
)
1177 ScFormulaCell
& rCell
= *sc::formula_block::at(*aPos2
.first
->data
, aPos2
.second
);
1178 rCol
.JoinNewFormulaCell(aPos2
, rCell
);
1181 CellStorageModified();
1182 rCol
.CellStorageModified();
1186 bool ScColumn::TestInsertCol( SCROW nStartRow
, SCROW nEndRow
) const
1191 // Return false if we have any non-empty cells between nStartRow and nEndRow inclusive.
1192 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nStartRow
);
1193 sc::CellStoreType::const_iterator it
= aPos
.first
;
1194 if (it
->type
!= sc::element_type_empty
)
1197 // Get the length of the remaining empty segment.
1198 size_t nLen
= it
->size
- aPos
.second
;
1199 SCROW nNextNonEmptyRow
= nStartRow
+ nLen
;
1200 if (nNextNonEmptyRow
<= nEndRow
)
1203 // AttrArray only looks for merged cells
1205 return pAttrArray
? pAttrArray
->TestInsertCol(nStartRow
, nEndRow
) : true;
1209 bool ScColumn::TestInsertRow( SCROW nStartRow
, SCSIZE nSize
) const
1211 // AttrArray only looks for merged cells
1213 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nStartRow
);
1214 sc::CellStoreType::const_iterator it
= aPos
.first
;
1215 if (it
->type
== sc::element_type_empty
&& maCells
.block_size() == 1)
1216 // The entire cell array is empty.
1217 return pAttrArray
->TestInsertRow(nSize
);
1220 // See if there would be any non-empty cell that gets pushed out.
1222 // Find the position of the last non-empty cell below nStartRow.
1223 size_t nLastNonEmptyRow
= MAXROW
;
1224 sc::CellStoreType::const_reverse_iterator it
= maCells
.rbegin();
1225 if (it
->type
== sc::element_type_empty
)
1226 nLastNonEmptyRow
-= it
->size
;
1228 if (nLastNonEmptyRow
< static_cast<size_t>(nStartRow
))
1229 // No cells would get pushed out.
1230 return pAttrArray
->TestInsertRow(nSize
);
1232 if (nLastNonEmptyRow
+ nSize
> static_cast<size_t>(MAXROW
))
1233 // At least one cell would get pushed out. Not good.
1236 return pAttrArray
->TestInsertRow(nSize
);
1240 void ScColumn::InsertRow( SCROW nStartRow
, SCSIZE nSize
)
1242 pAttrArray
->InsertRow( nStartRow
, nSize
);
1244 maCellNotes
.insert_empty(nStartRow
, nSize
);
1245 maCellNotes
.resize(MAXROWCOUNT
);
1247 maBroadcasters
.insert_empty(nStartRow
, nSize
);
1248 maBroadcasters
.resize(MAXROWCOUNT
);
1250 maCellTextAttrs
.insert_empty(nStartRow
, nSize
);
1251 maCellTextAttrs
.resize(MAXROWCOUNT
);
1253 maCells
.insert_empty(nStartRow
, nSize
);
1254 maCells
.resize(MAXROWCOUNT
);
1256 CellStorageModified();
1258 // We *probably* don't need to broadcast here since the parent call seems
1259 // to take care of it.
1264 class CopyToClipHandler
1266 const ScColumn
& mrSrcCol
;
1267 ScColumn
& mrDestCol
;
1268 sc::ColumnBlockPosition maDestPos
;
1269 sc::ColumnBlockPosition
* mpDestPos
;
1272 void setDefaultAttrsToDest(size_t nRow
, size_t nSize
)
1274 std::vector
<sc::CellTextAttr
> aAttrs(nSize
); // default values
1275 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set(
1276 maDestPos
.miCellTextAttrPos
, nRow
, aAttrs
.begin(), aAttrs
.end());
1279 void duplicateNotes(SCROW nStartRow
, size_t nDataSize
)
1281 mrSrcCol
.DuplicateNotes(nStartRow
, nDataSize
, mrDestCol
, maDestPos
);
1285 CopyToClipHandler(const ScColumn
& rSrcCol
, ScColumn
& rDestCol
, sc::ColumnBlockPosition
* pDestPos
, bool bCopyNotes
) :
1286 mrSrcCol(rSrcCol
), mrDestCol(rDestCol
), mpDestPos(pDestPos
), mbCopyNotes(bCopyNotes
)
1289 maDestPos
= *mpDestPos
;
1291 mrDestCol
.InitBlockPosition(maDestPos
);
1294 ~CopyToClipHandler()
1297 *mpDestPos
= maDestPos
;
1300 void operator() (const sc::CellStoreType::value_type
& aNode
, size_t nOffset
, size_t nDataSize
)
1302 size_t nTopRow
= aNode
.position
+ nOffset
;
1308 case sc::element_type_numeric
:
1310 sc::numeric_block::const_iterator it
= sc::numeric_block::begin(*aNode
.data
);
1311 std::advance(it
, nOffset
);
1312 sc::numeric_block::const_iterator itEnd
= it
;
1313 std::advance(itEnd
, nDataSize
);
1314 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nTopRow
, it
, itEnd
);
1317 case sc::element_type_string
:
1319 sc::string_block::const_iterator it
= sc::string_block::begin(*aNode
.data
);
1320 std::advance(it
, nOffset
);
1321 sc::string_block::const_iterator itEnd
= it
;
1322 std::advance(itEnd
, nDataSize
);
1323 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nTopRow
, it
, itEnd
);
1327 case sc::element_type_edittext
:
1329 sc::edittext_block::const_iterator it
= sc::edittext_block::begin(*aNode
.data
);
1330 std::advance(it
, nOffset
);
1331 sc::edittext_block::const_iterator itEnd
= it
;
1332 std::advance(itEnd
, nDataSize
);
1334 std::vector
<EditTextObject
*> aCloned
;
1335 aCloned
.reserve(nDataSize
);
1336 for (; it
!= itEnd
; ++it
)
1337 aCloned
.push_back(ScEditUtil::Clone(**it
, mrDestCol
.GetDoc()));
1339 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(
1340 maDestPos
.miCellPos
, nTopRow
, aCloned
.begin(), aCloned
.end());
1343 case sc::element_type_formula
:
1345 sc::formula_block::const_iterator it
= sc::formula_block::begin(*aNode
.data
);
1346 std::advance(it
, nOffset
);
1347 sc::formula_block::const_iterator itEnd
= it
;
1348 std::advance(itEnd
, nDataSize
);
1350 std::vector
<ScFormulaCell
*> aCloned
;
1351 aCloned
.reserve(nDataSize
);
1352 ScAddress
aDestPos(mrDestCol
.GetCol(), nTopRow
, mrDestCol
.GetTab());
1353 for (; it
!= itEnd
; ++it
, aDestPos
.IncRow())
1355 const ScFormulaCell
& rOld
= **it
;
1356 if (rOld
.GetDirty() && mrSrcCol
.GetDoc().GetAutoCalc())
1357 const_cast<ScFormulaCell
&>(rOld
).Interpret();
1359 aCloned
.push_back(new ScFormulaCell(rOld
, mrDestCol
.GetDoc(), aDestPos
));
1362 // Group the cloned formula cells.
1363 if (!aCloned
.empty())
1364 sc::SharedFormulaUtil::groupFormulaCells(aCloned
.begin(), aCloned
.end());
1366 sc::CellStoreType
& rDestCells
= mrDestCol
.GetCellStore();
1367 maDestPos
.miCellPos
= rDestCells
.set(
1368 maDestPos
.miCellPos
, nTopRow
, aCloned
.begin(), aCloned
.end());
1370 // Merge adjacent formula cell groups (if applicable).
1371 sc::CellStoreType::position_type aPos
=
1372 rDestCells
.position(maDestPos
.miCellPos
, nTopRow
);
1373 maDestPos
.miCellPos
= aPos
.first
;
1374 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
1375 size_t nLastRow
= nTopRow
+ nDataSize
;
1376 if (nLastRow
< static_cast<size_t>(MAXROW
))
1378 aPos
= rDestCells
.position(maDestPos
.miCellPos
, nLastRow
+1);
1379 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
1388 setDefaultAttrsToDest(nTopRow
, nDataSize
);
1391 duplicateNotes(nTopRow
, nDataSize
);
1397 void ScColumn::CopyToClip(
1398 sc::CopyToClipContext
& rCxt
, SCROW nRow1
, SCROW nRow2
, ScColumn
& rColumn
) const
1400 pAttrArray
->CopyArea( nRow1
, nRow2
, 0, *rColumn
.pAttrArray
,
1401 rCxt
.isKeepScenarioFlags() ? (SC_MF_ALL
& ~SC_MF_SCENARIO
) : SC_MF_ALL
);
1403 CopyToClipHandler
aFunc(*this, rColumn
, rCxt
.getBlockPosition(rColumn
.nTab
, rColumn
.nCol
), rCxt
.isCloneNotes());
1404 sc::ParseBlock(maCells
.begin(), maCells
, aFunc
, nRow1
, nRow2
);
1406 rColumn
.CellStorageModified();
1409 void ScColumn::CopyStaticToDocument(SCROW nRow1
, SCROW nRow2
, ScColumn
& rDestCol
)
1414 sc::ColumnBlockPosition aDestPos
;
1415 CopyCellTextAttrsToDocument(nRow1
, nRow2
, rDestCol
);
1416 CopyCellNotesToDocument(nRow1
, nRow2
, rDestCol
);
1418 // First, clear the destination column for the specified row range.
1419 rDestCol
.maCells
.set_empty(nRow1
, nRow2
);
1421 aDestPos
.miCellPos
= rDestCol
.maCells
.begin();
1423 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nRow1
);
1424 sc::CellStoreType::const_iterator it
= aPos
.first
;
1425 size_t nOffset
= aPos
.second
;
1426 size_t nDataSize
= 0;
1427 size_t nCurRow
= nRow1
;
1429 for (; it
!= maCells
.end() && nCurRow
<= static_cast<size_t>(nRow2
); ++it
, nOffset
= 0, nCurRow
+= nDataSize
)
1431 bool bLastBlock
= false;
1432 nDataSize
= it
->size
- nOffset
;
1433 if (nCurRow
+ nDataSize
- 1 > static_cast<size_t>(nRow2
))
1435 // Truncate the block to copy to clipboard.
1436 nDataSize
= nRow2
- nCurRow
+ 1;
1442 case sc::element_type_numeric
:
1444 sc::numeric_block::const_iterator itData
= sc::numeric_block::begin(*it
->data
);
1445 std::advance(itData
, nOffset
);
1446 sc::numeric_block::const_iterator itDataEnd
= itData
;
1447 std::advance(itDataEnd
, nDataSize
);
1448 aDestPos
.miCellPos
= rDestCol
.maCells
.set(aDestPos
.miCellPos
, nCurRow
, itData
, itDataEnd
);
1451 case sc::element_type_string
:
1453 sc::string_block::const_iterator itData
= sc::string_block::begin(*it
->data
);
1454 std::advance(itData
, nOffset
);
1455 sc::string_block::const_iterator itDataEnd
= itData
;
1456 std::advance(itDataEnd
, nDataSize
);
1457 aDestPos
.miCellPos
= rDestCol
.maCells
.set(aDestPos
.miCellPos
, nCurRow
, itData
, itDataEnd
);
1460 case sc::element_type_edittext
:
1462 sc::edittext_block::const_iterator itData
= sc::edittext_block::begin(*it
->data
);
1463 std::advance(itData
, nOffset
);
1464 sc::edittext_block::const_iterator itDataEnd
= itData
;
1465 std::advance(itDataEnd
, nDataSize
);
1467 // Convert to simple strings.
1468 std::vector
<svl::SharedString
> aConverted
;
1469 aConverted
.reserve(nDataSize
);
1470 for (; itData
!= itDataEnd
; ++itData
)
1472 const EditTextObject
& rObj
= **itData
;
1473 svl::SharedString aSS
= pDocument
->GetSharedStringPool().intern(ScEditUtil::GetString(rObj
, pDocument
));
1474 aConverted
.push_back(aSS
);
1476 aDestPos
.miCellPos
= rDestCol
.maCells
.set(aDestPos
.miCellPos
, nCurRow
, aConverted
.begin(), aConverted
.end());
1479 case sc::element_type_formula
:
1481 sc::formula_block::const_iterator itData
= sc::formula_block::begin(*it
->data
);
1482 std::advance(itData
, nOffset
);
1483 sc::formula_block::const_iterator itDataEnd
= itData
;
1484 std::advance(itDataEnd
, nDataSize
);
1486 // Interpret and convert to raw values.
1487 for (SCROW i
= 0; itData
!= itDataEnd
; ++itData
, ++i
)
1489 SCROW nRow
= nCurRow
+ i
;
1491 ScFormulaCell
& rFC
= const_cast<ScFormulaCell
&>(**itData
);
1492 if (rFC
.GetDirty() && pDocument
->GetAutoCalc())
1495 if (rFC
.GetErrCode())
1496 // Skip cells with error.
1500 aDestPos
.miCellPos
= rDestCol
.maCells
.set(aDestPos
.miCellPos
, nRow
, rFC
.GetValue());
1503 svl::SharedString aSS
= rFC
.GetString();
1505 aDestPos
.miCellPos
= rDestCol
.maCells
.set(aDestPos
.miCellPos
, nRow
, aSS
);
1518 rDestCol
.CellStorageModified();
1521 void ScColumn::CopyCellToDocument( SCROW nSrcRow
, SCROW nDestRow
, ScColumn
& rDestCol
)
1523 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nSrcRow
);
1524 sc::CellStoreType::const_iterator it
= aPos
.first
;
1528 case sc::element_type_numeric
:
1529 rDestCol
.maCells
.set(nDestRow
, sc::numeric_block::at(*it
->data
, aPos
.second
));
1531 case sc::element_type_string
:
1532 rDestCol
.maCells
.set(nDestRow
, sc::string_block::at(*it
->data
, aPos
.second
));
1534 case sc::element_type_edittext
:
1536 EditTextObject
* p
= sc::edittext_block::at(*it
->data
, aPos
.second
);
1537 if (pDocument
== rDestCol
.pDocument
)
1538 rDestCol
.maCells
.set(nDestRow
, p
->Clone());
1540 rDestCol
.maCells
.set(nDestRow
, ScEditUtil::Clone(*p
, *rDestCol
.pDocument
));
1543 case sc::element_type_formula
:
1545 ScFormulaCell
* p
= sc::formula_block::at(*it
->data
, aPos
.second
);
1546 if (p
->GetDirty() && pDocument
->GetAutoCalc())
1549 ScAddress aDestPos
= p
->aPos
;
1550 aDestPos
.SetRow(nDestRow
);
1551 ScFormulaCell
* pNew
= new ScFormulaCell(*p
, *rDestCol
.pDocument
, aDestPos
);
1552 rDestCol
.SetFormulaCell(nDestRow
, pNew
);
1555 case sc::element_type_empty
:
1558 rDestCol
.maCells
.set_empty(nDestRow
, nDestRow
);
1564 rDestCol
.maCellTextAttrs
.set(nDestRow
, maCellTextAttrs
.get
<sc::CellTextAttr
>(nSrcRow
));
1565 ScPostIt
* pNote
= maCellNotes
.get
<ScPostIt
*>(nSrcRow
);
1566 rDestCol
.maCellNotes
.set(nDestRow
, pNote
);
1568 pNote
->UpdateCaptionPos(ScAddress(rDestCol
.nCol
, nDestRow
, rDestCol
.nTab
));
1572 rDestCol
.maCellTextAttrs
.set_empty(nDestRow
, nDestRow
);
1573 rDestCol
.maCellNotes
.set_empty(nDestRow
, nDestRow
);
1576 rDestCol
.CellStorageModified();
1581 bool canCopyValue(const ScDocument
& rDoc
, const ScAddress
& rPos
, sal_uInt16 nFlags
)
1583 sal_uInt32 nNumIndex
= static_cast<const SfxUInt32Item
*>(rDoc
.GetAttr(rPos
, ATTR_VALUE_FORMAT
))->GetValue();
1584 short nType
= rDoc
.GetFormatTable()->GetType(nNumIndex
);
1585 if ((nType
== NUMBERFORMAT_DATE
) || (nType
== NUMBERFORMAT_TIME
) || (nType
== NUMBERFORMAT_DATETIME
))
1586 return ((nFlags
& IDF_DATETIME
) != 0);
1588 return ((nFlags
& IDF_VALUE
) != 0);
1591 class CopyAsLinkHandler
1593 const ScColumn
& mrSrcCol
;
1594 ScColumn
& mrDestCol
;
1595 sc::ColumnBlockPosition maDestPos
;
1596 sc::ColumnBlockPosition
* mpDestPos
;
1597 sal_uInt16 mnCopyFlags
;
1599 void setDefaultAttrToDest(size_t nRow
)
1601 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set(
1602 maDestPos
.miCellTextAttrPos
, nRow
, sc::CellTextAttr());
1605 void setDefaultAttrsToDest(size_t nRow
, size_t nSize
)
1607 std::vector
<sc::CellTextAttr
> aAttrs(nSize
); // default values
1608 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set(
1609 maDestPos
.miCellTextAttrPos
, nRow
, aAttrs
.begin(), aAttrs
.end());
1612 ScFormulaCell
* createRefCell(size_t nRow
)
1614 ScSingleRefData aRef
;
1615 aRef
.InitAddress(ScAddress(mrSrcCol
.GetCol(), nRow
, mrSrcCol
.GetTab())); // Absolute reference.
1616 aRef
.SetFlag3D(true);
1619 aArr
.AddSingleReference(aRef
);
1620 return new ScFormulaCell(&mrDestCol
.GetDoc(), ScAddress(mrDestCol
.GetCol(), nRow
, mrDestCol
.GetTab()), aArr
);
1623 void createRefBlock(const sc::CellStoreType::value_type
& aNode
, size_t nOffset
, size_t nDataSize
)
1625 size_t nTopRow
= aNode
.position
+ nOffset
;
1627 for (size_t i
= 0; i
< nDataSize
; ++i
)
1629 SCROW nRow
= nTopRow
+ i
;
1630 mrDestCol
.SetFormulaCell(maDestPos
, nRow
, createRefCell(nRow
));
1633 setDefaultAttrsToDest(nTopRow
, nDataSize
);
1636 void duplicateNotes(SCROW nStartRow
, size_t nDataSize
, bool bCloneCaption
)
1638 mrSrcCol
.DuplicateNotes(nStartRow
, nDataSize
, mrDestCol
, maDestPos
, bCloneCaption
);
1642 CopyAsLinkHandler(const ScColumn
& rSrcCol
, ScColumn
& rDestCol
, sc::ColumnBlockPosition
* pDestPos
, sal_uInt16 nCopyFlags
) :
1643 mrSrcCol(rSrcCol
), mrDestCol(rDestCol
), mpDestPos(pDestPos
), mnCopyFlags(nCopyFlags
)
1646 maDestPos
= *mpDestPos
;
1649 ~CopyAsLinkHandler()
1652 *mpDestPos
= maDestPos
;
1655 void operator() (const sc::CellStoreType::value_type
& aNode
, size_t nOffset
, size_t nDataSize
)
1657 size_t nRow
= aNode
.position
+ nOffset
;
1659 if (mnCopyFlags
& (IDF_NOTE
|IDF_ADDNOTES
))
1661 bool bCloneCaption
= (mnCopyFlags
& IDF_NOCAPTIONS
) == 0;
1662 duplicateNotes(nRow
, nDataSize
, bCloneCaption
);
1667 case sc::element_type_numeric
:
1669 if ((mnCopyFlags
& (IDF_DATETIME
|IDF_VALUE
)) == 0)
1672 sc::numeric_block::const_iterator it
= sc::numeric_block::begin(*aNode
.data
);
1673 std::advance(it
, nOffset
);
1674 sc::numeric_block::const_iterator itEnd
= it
;
1675 std::advance(itEnd
, nDataSize
);
1677 ScAddress
aSrcPos(mrSrcCol
.GetCol(), nRow
, mrSrcCol
.GetTab());
1678 for (; it
!= itEnd
; ++it
, aSrcPos
.IncRow(), ++nRow
)
1680 if (!canCopyValue(mrSrcCol
.GetDoc(), aSrcPos
, mnCopyFlags
))
1683 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nRow
, createRefCell(nRow
));
1684 setDefaultAttrToDest(nRow
);
1688 case sc::element_type_string
:
1689 case sc::element_type_edittext
:
1691 if (!(mnCopyFlags
& IDF_STRING
))
1694 createRefBlock(aNode
, nOffset
, nDataSize
);
1697 case sc::element_type_formula
:
1699 if (!(mnCopyFlags
& IDF_FORMULA
))
1702 createRefBlock(aNode
, nOffset
, nDataSize
);
1711 class CopyByCloneHandler
1713 const ScColumn
& mrSrcCol
;
1714 ScColumn
& mrDestCol
;
1715 sc::ColumnBlockPosition maDestPos
;
1716 sc::ColumnBlockPosition
* mpDestPos
;
1717 sal_uInt16 mnCopyFlags
;
1719 void setDefaultAttrToDest(size_t nRow
)
1721 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set(
1722 maDestPos
.miCellTextAttrPos
, nRow
, sc::CellTextAttr());
1725 void setDefaultAttrsToDest(size_t nRow
, size_t nSize
)
1727 std::vector
<sc::CellTextAttr
> aAttrs(nSize
); // default values
1728 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set(
1729 maDestPos
.miCellTextAttrPos
, nRow
, aAttrs
.begin(), aAttrs
.end());
1732 void cloneFormulaCell(size_t nRow
, ScFormulaCell
& rSrcCell
)
1734 ScAddress
aDestPos(mrDestCol
.GetCol(), nRow
, mrDestCol
.GetTab());
1736 bool bCloneValue
= (mnCopyFlags
& IDF_VALUE
) != 0;
1737 bool bCloneDateTime
= (mnCopyFlags
& IDF_DATETIME
) != 0;
1738 bool bCloneString
= (mnCopyFlags
& IDF_STRING
) != 0;
1739 bool bCloneSpecialBoolean
= (mnCopyFlags
& IDF_SPECIAL_BOOLEAN
) != 0;
1740 bool bCloneFormula
= (mnCopyFlags
& IDF_FORMULA
) != 0;
1742 bool bForceFormula
= false;
1744 if (bCloneSpecialBoolean
)
1746 // See if the formula consists of =TRUE() or =FALSE().
1747 ScTokenArray
* pCode
= rSrcCell
.GetCode();
1748 if (pCode
&& pCode
->GetLen() == 1)
1750 const formula::FormulaToken
* p
= pCode
->First();
1751 if (p
->GetOpCode() == ocTrue
|| p
->GetOpCode() == ocFalse
)
1752 // This is a boolean formula.
1753 bForceFormula
= true;
1757 if (bForceFormula
|| bCloneFormula
)
1759 // Clone as formula cell.
1760 ScFormulaCell
* pCell
= new ScFormulaCell(rSrcCell
, mrDestCol
.GetDoc(), aDestPos
);
1761 pCell
->SetDirtyVar();
1762 mrDestCol
.SetFormulaCell(maDestPos
, nRow
, pCell
);
1763 setDefaultAttrToDest(nRow
);
1767 if (mrDestCol
.GetDoc().IsUndo())
1772 sal_uInt16 nErr
= rSrcCell
.GetErrCode();
1775 // error codes are cloned with values
1776 ScFormulaCell
* pErrCell
= new ScFormulaCell(&mrDestCol
.GetDoc(), aDestPos
);
1777 pErrCell
->SetErrCode(nErr
);
1778 mrDestCol
.SetFormulaCell(maDestPos
, nRow
, pErrCell
);
1779 setDefaultAttrToDest(nRow
);
1784 if (bCloneValue
|| bCloneDateTime
)
1786 if (rSrcCell
.IsValue())
1788 if (canCopyValue(mrSrcCol
.GetDoc(), ScAddress(mrSrcCol
.GetCol(), nRow
, mrSrcCol
.GetTab()), mnCopyFlags
))
1790 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(
1791 maDestPos
.miCellPos
, nRow
, rSrcCell
.GetValue());
1792 setDefaultAttrToDest(nRow
);
1801 svl::SharedString aStr
= rSrcCell
.GetString();
1803 // Don't create empty string cells.
1806 if (rSrcCell
.IsMultilineResult())
1808 // Clone as an edit text object.
1809 EditEngine
& rEngine
= mrDestCol
.GetDoc().GetEditEngine();
1810 rEngine
.SetText(aStr
.getString());
1811 maDestPos
.miCellPos
=
1812 mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nRow
, rEngine
.CreateTextObject());
1816 maDestPos
.miCellPos
=
1817 mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nRow
, aStr
);
1820 setDefaultAttrToDest(nRow
);
1824 void duplicateNotes(SCROW nStartRow
, size_t nDataSize
, bool bCloneCaption
)
1826 mrSrcCol
.DuplicateNotes(nStartRow
, nDataSize
, mrDestCol
, maDestPos
, bCloneCaption
);
1830 CopyByCloneHandler(const ScColumn
& rSrcCol
, ScColumn
& rDestCol
, sc::ColumnBlockPosition
* pDestPos
, sal_uInt16 nCopyFlags
) :
1831 mrSrcCol(rSrcCol
), mrDestCol(rDestCol
), mpDestPos(pDestPos
), mnCopyFlags(nCopyFlags
)
1834 maDestPos
= *mpDestPos
;
1837 ~CopyByCloneHandler()
1840 *mpDestPos
= maDestPos
;
1843 void operator() (const sc::CellStoreType::value_type
& aNode
, size_t nOffset
, size_t nDataSize
)
1845 size_t nRow
= aNode
.position
+ nOffset
;
1847 if (mnCopyFlags
& (IDF_NOTE
|IDF_ADDNOTES
))
1849 bool bCloneCaption
= (mnCopyFlags
& IDF_NOCAPTIONS
) == 0;
1850 duplicateNotes(nRow
, nDataSize
, bCloneCaption
);
1855 case sc::element_type_numeric
:
1857 if ((mnCopyFlags
& (IDF_DATETIME
|IDF_VALUE
)) == 0)
1860 sc::numeric_block::const_iterator it
= sc::numeric_block::begin(*aNode
.data
);
1861 std::advance(it
, nOffset
);
1862 sc::numeric_block::const_iterator itEnd
= it
;
1863 std::advance(itEnd
, nDataSize
);
1865 ScAddress
aSrcPos(mrSrcCol
.GetCol(), nRow
, mrSrcCol
.GetTab());
1866 for (; it
!= itEnd
; ++it
, aSrcPos
.IncRow(), ++nRow
)
1868 if (!canCopyValue(mrSrcCol
.GetDoc(), aSrcPos
, mnCopyFlags
))
1871 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nRow
, *it
);
1872 setDefaultAttrToDest(nRow
);
1876 case sc::element_type_string
:
1878 if (!(mnCopyFlags
& IDF_STRING
))
1881 sc::string_block::const_iterator it
= sc::string_block::begin(*aNode
.data
);
1882 std::advance(it
, nOffset
);
1883 sc::string_block::const_iterator itEnd
= it
;
1884 std::advance(itEnd
, nDataSize
);
1886 for (; it
!= itEnd
; ++it
, ++nRow
)
1888 const svl::SharedString
& rStr
= *it
;
1891 // String cell with empty value is used to special-case cell value removal.
1892 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set_empty(
1893 maDestPos
.miCellPos
, nRow
, nRow
);
1894 maDestPos
.miCellTextAttrPos
= mrDestCol
.GetCellAttrStore().set_empty(
1895 maDestPos
.miCellTextAttrPos
, nRow
, nRow
);
1899 maDestPos
.miCellPos
=
1900 mrDestCol
.GetCellStore().set(maDestPos
.miCellPos
, nRow
, rStr
);
1901 setDefaultAttrToDest(nRow
);
1906 case sc::element_type_edittext
:
1908 if (!(mnCopyFlags
& IDF_STRING
))
1911 sc::edittext_block::const_iterator it
= sc::edittext_block::begin(*aNode
.data
);
1912 std::advance(it
, nOffset
);
1913 sc::edittext_block::const_iterator itEnd
= it
;
1914 std::advance(itEnd
, nDataSize
);
1916 std::vector
<EditTextObject
*> aCloned
;
1917 aCloned
.reserve(nDataSize
);
1918 for (; it
!= itEnd
; ++it
, ++nRow
)
1919 aCloned
.push_back(ScEditUtil::Clone(**it
, mrDestCol
.GetDoc()));
1921 maDestPos
.miCellPos
= mrDestCol
.GetCellStore().set(
1922 maDestPos
.miCellPos
, nRow
, aCloned
.begin(), aCloned
.end());
1924 setDefaultAttrsToDest(nRow
, nDataSize
);
1927 case sc::element_type_formula
:
1929 sc::formula_block::const_iterator it
= sc::formula_block::begin(*aNode
.data
);
1930 std::advance(it
, nOffset
);
1931 sc::formula_block::const_iterator itEnd
= it
;
1932 std::advance(itEnd
, nDataSize
);
1934 for (; it
!= itEnd
; ++it
, ++nRow
)
1935 cloneFormulaCell(nRow
, const_cast<ScFormulaCell
&>(**it
));
1946 void ScColumn::CopyToColumn(
1947 sc::CopyToDocContext
& rCxt
,
1948 SCROW nRow1
, SCROW nRow2
, sal_uInt16 nFlags
, bool bMarked
, ScColumn
& rColumn
,
1949 const ScMarkData
* pMarkData
, bool bAsLink
) const
1954 if (pMarkData
&& pMarkData
->IsMultiMarked())
1956 ScMarkArrayIter
aIter( pMarkData
->GetArray()+nCol
);
1958 while ( aIter
.Next( nStart
, nEnd
) && nStart
<= nRow2
)
1960 if ( nEnd
>= nRow1
)
1961 CopyToColumn(rCxt
, std::max(nRow1
,nStart
), std::min(nRow2
,nEnd
),
1962 nFlags
, false, rColumn
, pMarkData
, bAsLink
);
1967 OSL_FAIL("CopyToColumn: bMarked, but no mark");
1972 if ( (nFlags
& IDF_ATTRIB
) != 0 )
1974 if ( (nFlags
& IDF_STYLES
) != IDF_STYLES
)
1975 { // keep the StyleSheets in the target document
1976 // e.g. DIF and RTF Clipboard-Import
1977 for ( SCROW nRow
= nRow1
; nRow
<= nRow2
; nRow
++ )
1979 const ScStyleSheet
* pStyle
=
1980 rColumn
.pAttrArray
->GetPattern( nRow
)->GetStyleSheet();
1981 const ScPatternAttr
* pPattern
= pAttrArray
->GetPattern( nRow
);
1982 ScPatternAttr
* pNewPattern
= new ScPatternAttr( *pPattern
);
1983 pNewPattern
->SetStyleSheet( (ScStyleSheet
*)pStyle
);
1984 rColumn
.pAttrArray
->SetPattern( nRow
, pNewPattern
, true );
1989 pAttrArray
->CopyArea( nRow1
, nRow2
, 0, *rColumn
.pAttrArray
);
1992 if ((nFlags
& IDF_CONTENTS
) != 0)
1996 CopyAsLinkHandler
aFunc(*this, rColumn
, rCxt
.getBlockPosition(rColumn
.nTab
, rColumn
.nCol
), nFlags
);
1997 sc::ParseBlock(maCells
.begin(), maCells
, aFunc
, nRow1
, nRow2
);
2001 CopyByCloneHandler
aFunc(*this, rColumn
, rCxt
.getBlockPosition(rColumn
.nTab
, rColumn
.nCol
), nFlags
);
2002 sc::ParseBlock(maCells
.begin(), maCells
, aFunc
, nRow1
, nRow2
);
2005 rColumn
.CellStorageModified();
2010 void ScColumn::UndoToColumn(
2011 sc::CopyToDocContext
& rCxt
, SCROW nRow1
, SCROW nRow2
, sal_uInt16 nFlags
, bool bMarked
,
2012 ScColumn
& rColumn
, const ScMarkData
* pMarkData
) const
2015 CopyToColumn(rCxt
, 0, nRow1
-1, IDF_FORMULA
, false, rColumn
);
2017 CopyToColumn(rCxt
, nRow1
, nRow2
, nFlags
, bMarked
, rColumn
, pMarkData
); //! bMarked ????
2020 CopyToColumn(rCxt
, nRow2
+1, MAXROW
, IDF_FORMULA
, false, rColumn
);
2024 void ScColumn::CopyUpdated( const ScColumn
& rPosCol
, ScColumn
& rDestCol
) const
2026 // Copy cells from this column to the destination column only for those
2027 // rows that are present in the position column (rPosCol).
2029 // First, mark all the non-empty cell ranges from the position column.
2030 sc::SingleColumnSpanSet aRangeSet
;
2031 aRangeSet
.scan(rPosCol
);
2033 // Now, copy cells from this column to the destination column for those
2034 // marked row ranges.
2035 sc::SingleColumnSpanSet::SpansType aRanges
;
2036 aRangeSet
.getSpans(aRanges
);
2038 bool bCopyNotes
= true;
2039 CopyToClipHandler
aFunc(*this, rDestCol
, NULL
, bCopyNotes
);
2040 sc::CellStoreType::const_iterator itPos
= maCells
.begin();
2041 sc::SingleColumnSpanSet::SpansType::const_iterator it
= aRanges
.begin(), itEnd
= aRanges
.end();
2042 for (; it
!= itEnd
; ++it
)
2043 itPos
= sc::ParseBlock(itPos
, maCells
, aFunc
, it
->mnRow1
, it
->mnRow2
);
2045 rDestCol
.CellStorageModified();
2049 void ScColumn::CopyScenarioFrom( const ScColumn
& rSrcCol
)
2051 // This is the scenario table, the data is copied into it
2052 sc::CopyToDocContext
aCxt(*pDocument
);
2053 ScAttrIterator
aAttrIter( pAttrArray
, 0, MAXROW
);
2054 SCROW nStart
= -1, nEnd
= -1;
2055 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nStart
, nEnd
);
2058 if ( ((ScMergeFlagAttr
&)pPattern
->GetItem( ATTR_MERGE_FLAG
)).IsScenario() )
2060 DeleteArea( nStart
, nEnd
, IDF_CONTENTS
);
2061 ((ScColumn
&)rSrcCol
).
2062 CopyToColumn(aCxt
, nStart
, nEnd
, IDF_CONTENTS
, false, *this);
2064 // UpdateUsed not needed, already done in TestCopyScenario (obsolete comment ?)
2066 sc::RefUpdateContext
aRefCxt(*pDocument
);
2067 aRefCxt
.meMode
= URM_COPY
;
2068 aRefCxt
.maRange
= ScRange(nCol
, nStart
, nTab
, nCol
, nEnd
, nTab
);
2069 aRefCxt
.mnTabDelta
= nTab
- rSrcCol
.nTab
;
2070 UpdateReferenceOnCopy(aRefCxt
, NULL
);
2074 //! make CopyToColumn "const" !!! (obsolete comment ?)
2076 pPattern
= aAttrIter
.Next( nStart
, nEnd
);
2081 void ScColumn::CopyScenarioTo( ScColumn
& rDestCol
) const
2083 // This is the scenario table, the data is copied to the other
2084 sc::CopyToDocContext
aCxt(*rDestCol
.pDocument
);
2085 ScAttrIterator
aAttrIter( pAttrArray
, 0, MAXROW
);
2086 SCROW nStart
= -1, nEnd
= -1;
2087 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nStart
, nEnd
);
2090 if ( ((ScMergeFlagAttr
&)pPattern
->GetItem( ATTR_MERGE_FLAG
)).IsScenario() )
2092 rDestCol
.DeleteArea( nStart
, nEnd
, IDF_CONTENTS
);
2093 CopyToColumn(aCxt
, nStart
, nEnd
, IDF_CONTENTS
, false, rDestCol
);
2095 // UpdateUsed not needed, is already done in TestCopyScenario (obsolete comment ?)
2097 sc::RefUpdateContext
aRefCxt(*pDocument
);
2098 aRefCxt
.meMode
= URM_COPY
;
2099 aRefCxt
.maRange
= ScRange(rDestCol
.nCol
, nStart
, rDestCol
.nTab
, rDestCol
.nCol
, nEnd
, rDestCol
.nTab
);
2100 aRefCxt
.mnTabDelta
= rDestCol
.nTab
- nTab
;
2101 rDestCol
.UpdateReferenceOnCopy(aRefCxt
, NULL
);
2102 rDestCol
.UpdateCompile();
2105 //! make CopyToColumn "const" !!! (obsolete comment ?)
2107 pPattern
= aAttrIter
.Next( nStart
, nEnd
);
2112 bool ScColumn::TestCopyScenarioTo( const ScColumn
& rDestCol
) const
2115 ScAttrIterator
aAttrIter( pAttrArray
, 0, MAXROW
);
2116 SCROW nStart
= 0, nEnd
= 0;
2117 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nStart
, nEnd
);
2118 while (pPattern
&& bOk
)
2120 if ( ((ScMergeFlagAttr
&)pPattern
->GetItem( ATTR_MERGE_FLAG
)).IsScenario() )
2121 if ( rDestCol
.pAttrArray
->HasAttrib( nStart
, nEnd
, HASATTR_PROTECTED
) )
2124 pPattern
= aAttrIter
.Next( nStart
, nEnd
);
2130 void ScColumn::MarkScenarioIn( ScMarkData
& rDestMark
) const
2132 ScRange
aRange( nCol
, 0, nTab
);
2134 ScAttrIterator
aAttrIter( pAttrArray
, 0, MAXROW
);
2135 SCROW nStart
= -1, nEnd
= -1;
2136 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nStart
, nEnd
);
2139 if ( ((ScMergeFlagAttr
&)pPattern
->GetItem( ATTR_MERGE_FLAG
)).IsScenario() )
2141 aRange
.aStart
.SetRow( nStart
);
2142 aRange
.aEnd
.SetRow( nEnd
);
2143 rDestMark
.SetMultiMarkArea( aRange
, true );
2146 pPattern
= aAttrIter
.Next( nStart
, nEnd
);
2152 void resetColumnPosition(sc::CellStoreType
& rCells
, SCCOL nCol
)
2154 sc::CellStoreType::iterator it
= rCells
.begin(), itEnd
= rCells
.end();
2155 for (; it
!= itEnd
; ++it
)
2157 if (it
->type
!= sc::element_type_formula
)
2160 sc::formula_block::iterator itCell
= sc::formula_block::begin(*it
->data
);
2161 sc::formula_block::iterator itCellEnd
= sc::formula_block::end(*it
->data
);
2162 for (; itCell
!= itCellEnd
; ++itCell
)
2164 ScFormulaCell
& rCell
= **itCell
;
2165 rCell
.aPos
.SetCol(nCol
);
2172 void ScColumn::UpdateNoteCaptions()
2174 sc::CellNoteStoreType::const_iterator itBlk
= maCellNotes
.begin(), itBlkEnd
= maCellNotes
.end();
2175 sc::cellnote_block::const_iterator itData
, itDataEnd
;
2178 for (;itBlk
!=itBlkEnd
;++itBlk
)
2183 itData
= sc::cellnote_block::begin(*itBlk
->data
);
2184 itDataEnd
= sc::cellnote_block::end(*itBlk
->data
);
2185 for(;itData
!=itDataEnd
; ++itData
)
2187 ScPostIt
* pNote
= *itData
;
2188 pNote
->UpdateCaptionPos(ScAddress(nCol
, curRow
, nTab
));
2195 curRow
+= itBlk
->size
;
2200 void ScColumn::SwapCol(ScColumn
& rCol
)
2202 maBroadcasters
.swap(rCol
.maBroadcasters
);
2203 maCells
.swap(rCol
.maCells
);
2204 maCellTextAttrs
.swap(rCol
.maCellTextAttrs
);
2205 maCellNotes
.swap(rCol
.maCellNotes
);
2207 // notes update caption
2208 UpdateNoteCaptions();
2209 rCol
.UpdateNoteCaptions();
2211 ScAttrArray
* pTempAttr
= rCol
.pAttrArray
;
2212 rCol
.pAttrArray
= pAttrArray
;
2213 pAttrArray
= pTempAttr
;
2215 // AttrArray needs to have the right column number
2216 pAttrArray
->SetCol(nCol
);
2217 rCol
.pAttrArray
->SetCol(rCol
.nCol
);
2219 std::swap(mbDirtyGroups
, rCol
.mbDirtyGroups
);
2221 // Reset column positions in formula cells.
2222 resetColumnPosition(maCells
, nCol
);
2223 resetColumnPosition(rCol
.maCells
, rCol
.nCol
);
2225 CellStorageModified();
2226 rCol
.CellStorageModified();
2229 void ScColumn::MoveTo(SCROW nStartRow
, SCROW nEndRow
, ScColumn
& rCol
)
2231 pAttrArray
->MoveTo(nStartRow
, nEndRow
, *rCol
.pAttrArray
);
2233 // Mark the non-empty cells within the specified range, for later broadcasting.
2234 sc::SingleColumnSpanSet aNonEmpties
;
2235 aNonEmpties
.scan(*this, nStartRow
, nEndRow
);
2236 sc::SingleColumnSpanSet::SpansType aRanges
;
2237 aNonEmpties
.getSpans(aRanges
);
2239 // Split the formula grouping at the top and bottom boundaries.
2240 sc::CellStoreType::position_type aPos
= maCells
.position(nStartRow
);
2241 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos
);
2242 aPos
= maCells
.position(aPos
.first
, nEndRow
+1);
2243 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos
);
2245 // Do the same with the destination column.
2246 aPos
= rCol
.maCells
.position(nStartRow
);
2247 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos
);
2248 aPos
= rCol
.maCells
.position(aPos
.first
, nEndRow
+1);
2249 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos
);
2251 // Move the broadcasters to the destination column.
2252 maBroadcasters
.transfer(nStartRow
, nEndRow
, rCol
.maBroadcasters
, nStartRow
);
2253 maCells
.transfer(nStartRow
, nEndRow
, rCol
.maCells
, nStartRow
);
2254 maCellTextAttrs
.transfer(nStartRow
, nEndRow
, rCol
.maCellTextAttrs
, nStartRow
);
2256 // move the notes to the destination column
2257 maCellNotes
.transfer(nStartRow
, nEndRow
, rCol
.maCellNotes
, nStartRow
);
2258 UpdateNoteCaptions();
2260 // Re-group transferred formula cells.
2261 aPos
= rCol
.maCells
.position(nStartRow
);
2262 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
2263 aPos
= rCol
.maCells
.position(aPos
.first
, nEndRow
+1);
2264 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
2266 CellStorageModified();
2267 rCol
.CellStorageModified();
2269 // Broadcast on moved ranges. Area-broadcast only.
2270 ScHint
aHint(SC_HINT_DATACHANGED
, ScAddress(nCol
, 0, nTab
));
2271 ScAddress
& rPos
= aHint
.GetAddress();
2272 sc::SingleColumnSpanSet::SpansType::const_iterator itRange
= aRanges
.begin(), itRangeEnd
= aRanges
.end();
2273 for (; itRange
!= itRangeEnd
; ++itRange
)
2275 for (SCROW nRow
= itRange
->mnRow1
; nRow
<= itRange
->mnRow2
; ++nRow
)
2278 pDocument
->AreaBroadcast(aHint
);
2285 class SubTotalCellPicker
2287 sc::ColumnSpanSet
& mrSet
;
2292 SubTotalCellPicker(sc::ColumnSpanSet
& rSet
, SCTAB nTab
, SCCOL nCol
, bool bVal
) :
2293 mrSet(rSet
), mnTab(nTab
), mnCol(nCol
), mbVal(bVal
) {}
2295 void operator() (size_t nRow
, const ScFormulaCell
* pCell
)
2297 if (pCell
->IsSubTotal())
2298 mrSet
.set(mnTab
, mnCol
, nRow
, mbVal
);
2304 void ScColumn::MarkSubTotalCells( sc::ColumnSpanSet
& rSet
, SCROW nRow1
, SCROW nRow2
, bool bVal
) const
2306 SubTotalCellPicker
aFunc(rSet
, nTab
, nCol
, bVal
);
2307 sc::ParseFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aFunc
);
2312 class UpdateRefOnCopy
2314 const sc::RefUpdateContext
& mrCxt
;
2315 ScDocument
* mpUndoDoc
;
2319 UpdateRefOnCopy(const sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
) :
2320 mrCxt(rCxt
), mpUndoDoc(pUndoDoc
), mbUpdated(false) {}
2322 bool isUpdated() const { return mbUpdated
; }
2324 void operator() (sc::CellStoreType::value_type
& node
, size_t nOffset
, size_t nDataSize
)
2326 if (node
.type
!= sc::element_type_formula
)
2329 sc::formula_block::iterator it
= sc::formula_block::begin(*node
.data
);
2330 std::advance(it
, nOffset
);
2331 sc::formula_block::iterator itEnd
= it
;
2332 std::advance(itEnd
, nDataSize
);
2334 for (; it
!= itEnd
; ++it
)
2336 ScFormulaCell
& rCell
= **it
;
2337 mbUpdated
|= rCell
.UpdateReference(mrCxt
, mpUndoDoc
);
2342 class UpdateRefOnNonCopy
2346 const sc::RefUpdateContext
& mrCxt
;
2347 ScDocument
* mpUndoDoc
;
2352 SCCOL nCol
, SCTAB nTab
, const sc::RefUpdateContext
& rCxt
,
2353 ScDocument
* pUndoDoc
) :
2354 mnCol(nCol
), mnTab(nTab
), mrCxt(rCxt
),
2355 mpUndoDoc(pUndoDoc
), mbUpdated(false) {}
2357 void operator() (size_t nRow
, ScFormulaCell
* pCell
)
2359 ScAddress
aUndoPos(mnCol
, nRow
, mnTab
);
2360 mbUpdated
|= pCell
->UpdateReference(mrCxt
, mpUndoDoc
, &aUndoPos
);
2363 bool isUpdated() const { return mbUpdated
; }
2366 class UpdateRefGroupBoundChecker
: std::unary_function
<sc::CellStoreType::value_type
, void>
2368 const sc::RefUpdateContext
& mrCxt
;
2369 std::vector
<SCROW
>& mrBounds
;
2371 UpdateRefGroupBoundChecker(const sc::RefUpdateContext
& rCxt
, std::vector
<SCROW
>& rBounds
) :
2372 mrCxt(rCxt
), mrBounds(rBounds
) {}
2374 void operator() (const sc::CellStoreType::value_type
& node
)
2376 if (node
.type
!= sc::element_type_formula
)
2379 sc::formula_block::const_iterator it
= sc::formula_block::begin(*node
.data
);
2380 sc::formula_block::const_iterator itEnd
= sc::formula_block::end(*node
.data
);
2382 // Only pick shared formula cells that are the top cells of their
2383 // respective shared ranges.
2384 for (; it
!= itEnd
; ++it
)
2386 const ScFormulaCell
& rCell
= **it
;
2387 if (!rCell
.IsShared())
2390 if (rCell
.IsSharedTop())
2392 // Check its tokens and record its reference boundaries.
2393 const ScTokenArray
& rCode
= *rCell
.GetCode();
2394 rCode
.CheckRelativeReferenceBounds(
2395 mrCxt
, rCell
.aPos
, rCell
.GetSharedLength(), mrBounds
);
2397 // Move to the last cell in the group, to get incremented to
2398 // the next cell in the next iteration.
2399 size_t nOffsetToLast
= rCell
.GetSharedLength() - 1;
2400 std::advance(it
, nOffsetToLast
);
2408 bool ScColumn::UpdateReferenceOnCopy( const sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
)
2410 // When copying, the range equals the destination range where cells
2411 // are pasted, and the dx, dy, dz refer to the distance from the
2414 UpdateRefOnCopy
aHandler(rCxt
, pUndoDoc
);
2415 sc::CellStoreType::position_type aPos
= maCells
.position(rCxt
.maRange
.aStart
.Row());
2416 sc::ProcessBlock(aPos
.first
, maCells
, aHandler
, rCxt
.maRange
.aStart
.Row(), rCxt
.maRange
.aEnd
.Row());
2418 // The formula groups at the top and bottom boundaries are expected to
2419 // have been split prior to this call. Here, we only do the joining.
2420 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
2421 if (rCxt
.maRange
.aEnd
.Row() < MAXROW
)
2423 aPos
= maCells
.position(aPos
.first
, rCxt
.maRange
.aEnd
.Row()+1);
2424 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos
);
2427 return aHandler
.isUpdated();
2430 bool ScColumn::UpdateReference( sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
)
2432 if (rCxt
.meMode
== URM_COPY
)
2433 return UpdateReferenceOnCopy(rCxt
, pUndoDoc
);
2436 // Cells in this column are all empty.
2439 std::vector
<SCROW
> aBounds
;
2441 bool bThisColShifted
= (rCxt
.maRange
.aStart
.Tab() <= nTab
&& nTab
<= rCxt
.maRange
.aEnd
.Tab() &&
2442 rCxt
.maRange
.aStart
.Col() <= nCol
&& nCol
<= rCxt
.maRange
.aEnd
.Col());
2443 if (bThisColShifted
)
2445 // Cells in this column is being shifted. Split formula grouping at
2446 // the top and bottom boundaries before they get shifted.
2447 // Also, for deleted rows split at the top of the deleted area to adapt
2448 // the affected group length.
2450 if (rCxt
.mnRowDelta
< 0)
2452 nSplitPos
= rCxt
.maRange
.aStart
.Row() + rCxt
.mnRowDelta
;
2453 if (ValidRow(nSplitPos
))
2454 aBounds
.push_back(nSplitPos
);
2456 nSplitPos
= rCxt
.maRange
.aStart
.Row();
2457 if (ValidRow(nSplitPos
))
2459 aBounds
.push_back(nSplitPos
);
2460 nSplitPos
= rCxt
.maRange
.aEnd
.Row() + 1;
2461 if (ValidRow(nSplitPos
))
2462 aBounds
.push_back(nSplitPos
);
2466 // Check the row positions at which the group must be split per relative
2468 UpdateRefGroupBoundChecker
aBoundChecker(rCxt
, aBounds
);
2469 std::for_each(maCells
.begin(), maCells
.end(), aBoundChecker
);
2471 // Do the actual splitting.
2472 sc::SharedFormulaUtil::splitFormulaCellGroups(maCells
, aBounds
);
2474 UpdateRefOnNonCopy
aHandler(nCol
, nTab
, rCxt
, pUndoDoc
);
2475 sc::ProcessFormula(maCells
, aHandler
);
2476 if (aHandler
.isUpdated())
2477 rCxt
.maRegroupCols
.set(nTab
, nCol
);
2479 return aHandler
.isUpdated();
2484 class UpdateTransHandler
2487 sc::CellStoreType::iterator miPos
;
2490 ScDocument
* mpUndoDoc
;
2492 UpdateTransHandler(ScColumn
& rColumn
, const ScRange
& rSource
, const ScAddress
& rDest
, ScDocument
* pUndoDoc
) :
2494 miPos(rColumn
.GetCellStore().begin()),
2495 maSource(rSource
), maDest(rDest
), mpUndoDoc(pUndoDoc
) {}
2497 void operator() (size_t nRow
, ScFormulaCell
* pCell
)
2499 sc::CellStoreType::position_type aPos
= mrColumn
.GetCellStore().position(miPos
, nRow
);
2501 sc::SharedFormulaUtil::unshareFormulaCell(aPos
, *pCell
);
2502 pCell
->UpdateTranspose(maSource
, maDest
, mpUndoDoc
);
2503 mrColumn
.JoinNewFormulaCell(aPos
, *pCell
);
2507 class UpdateGrowHandler
2510 sc::CellStoreType::iterator miPos
;
2515 UpdateGrowHandler(ScColumn
& rColumn
, const ScRange
& rArea
, SCCOL nGrowX
, SCROW nGrowY
) :
2517 miPos(rColumn
.GetCellStore().begin()),
2518 maArea(rArea
), mnGrowX(nGrowX
), mnGrowY(nGrowY
) {}
2520 void operator() (size_t nRow
, ScFormulaCell
* pCell
)
2522 sc::CellStoreType::position_type aPos
= mrColumn
.GetCellStore().position(miPos
, nRow
);
2524 sc::SharedFormulaUtil::unshareFormulaCell(aPos
, *pCell
);
2525 pCell
->UpdateGrow(maArea
, mnGrowX
, mnGrowY
);
2526 mrColumn
.JoinNewFormulaCell(aPos
, *pCell
);
2530 class InsertTabUpdater
2532 sc::RefUpdateInsertTabContext
& mrCxt
;
2533 sc::CellTextAttrStoreType
& mrTextAttrs
;
2534 sc::CellTextAttrStoreType::iterator miAttrPos
;
2539 InsertTabUpdater(sc::RefUpdateInsertTabContext
& rCxt
, sc::CellTextAttrStoreType
& rTextAttrs
, SCTAB nTab
) :
2541 mrTextAttrs(rTextAttrs
),
2542 miAttrPos(rTextAttrs
.begin()),
2544 mbModified(false) {}
2546 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2548 pCell
->UpdateInsertTab(mrCxt
);
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 DeleteTabUpdater
2565 sc::RefUpdateDeleteTabContext
& mrCxt
;
2566 sc::CellTextAttrStoreType
& mrTextAttrs
;
2567 sc::CellTextAttrStoreType::iterator miAttrPos
;
2571 DeleteTabUpdater(sc::RefUpdateDeleteTabContext
& rCxt
, sc::CellTextAttrStoreType
& rTextAttrs
, SCTAB nTab
) :
2573 mrTextAttrs(rTextAttrs
),
2574 miAttrPos(rTextAttrs
.begin()),
2576 mbModified(false) {}
2578 void operator() (size_t, ScFormulaCell
* pCell
)
2580 pCell
->UpdateDeleteTab(mrCxt
);
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 InsertAbsTabUpdater
2597 sc::CellTextAttrStoreType
& mrTextAttrs
;
2598 sc::CellTextAttrStoreType::iterator miAttrPos
;
2603 InsertAbsTabUpdater(sc::CellTextAttrStoreType
& rTextAttrs
, SCTAB nTab
, SCTAB nNewPos
) :
2604 mrTextAttrs(rTextAttrs
),
2605 miAttrPos(rTextAttrs
.begin()),
2608 mbModified(false) {}
2610 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2612 pCell
->UpdateInsertTabAbs(mnNewPos
);
2616 void operator() (size_t nRow
, EditTextObject
* pCell
)
2618 editeng::FieldUpdater aUpdater
= pCell
->GetFieldUpdater();
2619 aUpdater
.updateTableFields(mnTab
);
2620 miAttrPos
= mrTextAttrs
.set(miAttrPos
, nRow
, sc::CellTextAttr());
2624 bool isModified() const { return mbModified
; }
2627 class MoveTabUpdater
2629 sc::RefUpdateMoveTabContext
& mrCxt
;
2630 sc::CellTextAttrStoreType
& mrTextAttrs
;
2631 sc::CellTextAttrStoreType::iterator miAttrPos
;
2635 MoveTabUpdater(sc::RefUpdateMoveTabContext
& rCxt
, sc::CellTextAttrStoreType
& rTextAttrs
, SCTAB nTab
) :
2637 mrTextAttrs(rTextAttrs
),
2638 miAttrPos(rTextAttrs
.begin()),
2640 mbModified(false) {}
2642 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2644 pCell
->UpdateMoveTab(mrCxt
, mnTab
);
2648 void operator() (size_t nRow
, EditTextObject
* pCell
)
2650 editeng::FieldUpdater aUpdater
= pCell
->GetFieldUpdater();
2651 aUpdater
.updateTableFields(mnTab
);
2652 miAttrPos
= mrTextAttrs
.set(miAttrPos
, nRow
, sc::CellTextAttr());
2656 bool isModified() const { return mbModified
; }
2659 class UpdateCompileHandler
2661 bool mbForceIfNameInUse
:1;
2663 UpdateCompileHandler(bool bForceIfNameInUse
) :
2664 mbForceIfNameInUse(bForceIfNameInUse
) {}
2666 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2668 pCell
->UpdateCompile(mbForceIfNameInUse
);
2676 TabNoSetter(SCTAB nTab
) : mnTab(nTab
) {}
2678 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2680 pCell
->aPos
.SetTab(mnTab
);
2684 class UsedRangeNameFinder
2686 std::set
<sal_uInt16
>& mrIndexes
;
2688 UsedRangeNameFinder(std::set
<sal_uInt16
>& rIndexes
) : mrIndexes(rIndexes
) {}
2690 void operator() (size_t /*nRow*/, const ScFormulaCell
* pCell
)
2692 pCell
->FindRangeNamesInUse(mrIndexes
);
2696 struct SetDirtyVarHandler
2698 void operator() (size_t /*nRow*/, ScFormulaCell
* p
)
2704 class SetDirtyHandler
2708 SetDirtyHandler(ScDocument
& rDoc
) : mrDoc(rDoc
) {}
2710 void operator() (size_t /*nRow*/, ScFormulaCell
* p
)
2713 if (!mrDoc
.IsInFormulaTree(p
))
2714 mrDoc
.PutInFormulaTree(p
);
2718 class SetDirtyOnRangeHandler
2720 sc::SingleColumnSpanSet maValueRanges
;
2723 SetDirtyOnRangeHandler(ScColumn
& rColumn
) : mrColumn(rColumn
) {}
2725 void operator() (size_t /*nRow*/, ScFormulaCell
* p
)
2730 void operator() (mdds::mtv::element_t type
, size_t nTopRow
, size_t nDataSize
)
2732 if (type
== sc::element_type_empty
)
2733 // Ignore empty blocks.
2736 // Non-formula cells.
2737 SCROW nRow1
= nTopRow
;
2738 SCROW nRow2
= nTopRow
+ nDataSize
- 1;
2739 maValueRanges
.set(nRow1
, nRow2
, true);
2744 std::vector
<SCROW
> aRows
;
2745 maValueRanges
.getRows(aRows
);
2746 mrColumn
.BroadcastCells(aRows
, SC_HINT_DATACHANGED
);
2750 class SetTableOpDirtyOnRangeHandler
2752 sc::SingleColumnSpanSet maValueRanges
;
2755 SetTableOpDirtyOnRangeHandler(ScColumn
& rColumn
) : mrColumn(rColumn
) {}
2757 void operator() (size_t /*nRow*/, ScFormulaCell
* p
)
2759 p
->SetTableOpDirty();
2762 void operator() (mdds::mtv::element_t type
, size_t nTopRow
, size_t nDataSize
)
2764 if (type
== sc::element_type_empty
)
2765 // Ignore empty blocks.
2768 // Non-formula cells.
2769 SCROW nRow1
= nTopRow
;
2770 SCROW nRow2
= nTopRow
+ nDataSize
- 1;
2771 maValueRanges
.set(nRow1
, nRow2
, true);
2776 std::vector
<SCROW
> aRows
;
2777 maValueRanges
.getRows(aRows
);
2778 mrColumn
.BroadcastCells(aRows
, SC_HINT_TABLEOPDIRTY
);
2782 struct SetDirtyAfterLoadHandler
2784 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2787 // Simply set dirty and append to FormulaTree, without broadcasting,
2788 // which is a magnitude faster. This is used to calculate the entire
2789 // document, e.g. when loading alien file formats.
2790 pCell
->SetDirtyAfterLoad();
2792 /* This was used with the binary file format that stored results, where only
2793 * newly compiled and volatile functions and their dependents had to be
2794 * recalculated, which was faster then. Since that was moved to 'binfilter' to
2795 * convert to an XML file this isn't needed anymore, and not used for other
2796 * file formats. Kept for reference in case mechanism needs to be reactivated
2797 * for some file formats, we'd have to introduce a controlling parameter to
2798 * this method here then.
2801 // If the cell was alsready dirty because of CalcAfterLoad,
2802 // FormulaTracking has to take place.
2803 if (pCell
->GetDirty())
2809 struct SetDirtyIfPostponedHandler
2811 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2813 if (pCell
->IsPostponedDirty() || pCell
->HasRelNameReference())
2818 struct CalcAllHandler
2820 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2822 #if OSL_DEBUG_LEVEL > 1
2823 // after F9 ctrl-F9: check the calculation for each FormulaTree
2824 double nOldVal
, nNewVal
;
2825 nOldVal
= pCell
->GetValue();
2828 #if OSL_DEBUG_LEVEL > 1
2829 if (pCell
->GetCode()->IsRecalcModeNormal())
2830 nNewVal
= pCell
->GetValue();
2832 nNewVal
= nOldVal
; // random(), jetzt() etc.
2834 OSL_ENSURE(nOldVal
== nNewVal
, "CalcAll: nOldVal != nNewVal");
2839 struct CompileAllHandler
2841 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2843 // for unconditional compilation
2844 // bCompile=true and pCode->nError=0
2845 pCell
->GetCode()->SetCodeError(0);
2846 pCell
->SetCompile(true);
2847 pCell
->CompileTokenArray();
2851 class CompileXMLHandler
2853 ScProgress
& mrProgress
;
2854 const ScColumn
& mrCol
;
2856 CompileXMLHandler(ScProgress
& rProgress
, const ScColumn
& rCol
) :
2857 mrProgress(rProgress
),
2860 void operator() (size_t nRow
, ScFormulaCell
* pCell
)
2862 sal_uInt32 nFormat
= mrCol
.GetNumberFormat(nRow
);
2863 if( (nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
) != 0)
2864 pCell
->SetNeedNumberFormat(false);
2866 pCell
->SetDirty(true);
2868 pCell
->CompileXML(mrProgress
);
2872 class CompileErrorCellsHandler
2875 sc::CellStoreType::iterator miPos
;
2876 sal_uInt16 mnErrCode
;
2877 FormulaGrammar::Grammar meGram
;
2880 CompileErrorCellsHandler(ScColumn
& rColumn
, sal_uInt16 nErrCode
, FormulaGrammar::Grammar eGram
) :
2882 miPos(mrColumn
.GetCellStore().begin()),
2883 mnErrCode(nErrCode
),
2889 void operator() (size_t nRow
, ScFormulaCell
* pCell
)
2891 sal_uInt16 nCurError
= pCell
->GetRawError();
2893 // It's not an error cell. Skip it.
2896 if (mnErrCode
&& nCurError
!= mnErrCode
)
2897 // Error code is specified, and it doesn't match. Skip it.
2900 sc::CellStoreType::position_type aPos
= mrColumn
.GetCellStore().position(miPos
, nRow
);
2902 sc::SharedFormulaUtil::unshareFormulaCell(aPos
, *pCell
);
2903 pCell
->GetCode()->SetCodeError(0);
2904 OUStringBuffer aBuf
;
2905 pCell
->GetFormula(aBuf
, meGram
);
2906 pCell
->Compile(aBuf
.makeStringAndClear(), false, meGram
);
2907 mrColumn
.JoinNewFormulaCell(aPos
, *pCell
);
2912 bool isCompiled() const { return mbCompiled
; }
2915 struct CalcAfterLoadHandler
2917 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2919 pCell
->CalcAfterLoad();
2923 struct ResetChangedHandler
2925 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
2927 pCell
->SetChanged(false);
2932 * Ambiguous script type counts as edit cell.
2934 class FindEditCellsHandler
2937 sc::CellTextAttrStoreType::iterator miAttrPos
;
2938 sc::CellStoreType::iterator miCellPos
;
2941 FindEditCellsHandler(ScColumn
& rColumn
, sc::CellTextAttrStoreType
& rAttrs
,
2942 sc::CellStoreType::iterator rCellItr
) :
2943 mrColumn(rColumn
), miAttrPos(rAttrs
.begin()), miCellPos(rCellItr
) {}
2945 bool operator() (size_t, const EditTextObject
*)
2950 bool operator() (size_t nRow
, const ScFormulaCell
* p
)
2952 sal_uInt8 nScriptType
= mrColumn
.GetRangeScriptType(miAttrPos
, nRow
, nRow
, miCellPos
);
2953 if (IsAmbiguousScriptNonZero(nScriptType
))
2956 return const_cast<ScFormulaCell
*>(p
)->IsMultilineResult();
2959 std::pair
<size_t,bool> operator() (mdds::mtv::element_t type
, size_t nTopRow
, size_t nDataSize
)
2961 typedef std::pair
<size_t,bool> RetType
;
2963 if (type
== sc::element_type_empty
)
2964 return RetType(0, false);
2966 for (size_t i
= 0; i
< nDataSize
; ++i
)
2968 SCROW nRow
= nTopRow
+ i
;
2969 sal_uInt8 nScriptType
= mrColumn
.GetRangeScriptType(miAttrPos
, nRow
, nRow
, miCellPos
);
2970 if (IsAmbiguousScriptNonZero(nScriptType
))
2971 // Return the offset from the first row.
2972 return RetType(i
, true);
2975 return RetType(0, false);
2981 void ScColumn::UpdateTranspose( const ScRange
& rSource
, const ScAddress
& rDest
,
2982 ScDocument
* pUndoDoc
)
2984 UpdateTransHandler
aFunc(*this, rSource
, rDest
, pUndoDoc
);
2985 sc::ProcessFormula(maCells
, aFunc
);
2989 void ScColumn::UpdateGrow( const ScRange
& rArea
, SCCOL nGrowX
, SCROW nGrowY
)
2991 UpdateGrowHandler
aFunc(*this, rArea
, nGrowX
, nGrowY
);
2992 sc::ProcessFormula(maCells
, aFunc
);
2996 void ScColumn::UpdateInsertTab( sc::RefUpdateInsertTabContext
& rCxt
)
2998 if (nTab
>= rCxt
.mnInsertPos
)
3000 nTab
+= rCxt
.mnSheets
;
3001 pAttrArray
->SetTab(nTab
);
3004 UpdateInsertTabOnlyCells(rCxt
);
3007 void ScColumn::UpdateInsertTabOnlyCells( sc::RefUpdateInsertTabContext
& rCxt
)
3009 InsertTabUpdater
aFunc(rCxt
, maCellTextAttrs
, nTab
);
3010 sc::ProcessFormulaEditText(maCells
, aFunc
);
3011 if (aFunc
.isModified())
3012 CellStorageModified();
3015 void ScColumn::UpdateDeleteTab( sc::RefUpdateDeleteTabContext
& rCxt
)
3017 if (nTab
> rCxt
.mnDeletePos
)
3019 nTab
-= rCxt
.mnSheets
;
3020 pAttrArray
->SetTab(nTab
);
3023 DeleteTabUpdater
aFunc(rCxt
, maCellTextAttrs
, nTab
);
3024 sc::ProcessFormulaEditText(maCells
, aFunc
);
3025 if (aFunc
.isModified())
3026 CellStorageModified();
3029 void ScColumn::UpdateInsertTabAbs(SCTAB nNewPos
)
3031 InsertAbsTabUpdater
aFunc(maCellTextAttrs
, nTab
, nNewPos
);
3032 sc::ProcessFormulaEditText(maCells
, aFunc
);
3033 if (aFunc
.isModified())
3034 CellStorageModified();
3037 void ScColumn::UpdateMoveTab( sc::RefUpdateMoveTabContext
& rCxt
, SCTAB nTabNo
)
3040 pAttrArray
->SetTab( nTabNo
);
3042 MoveTabUpdater
aFunc(rCxt
, maCellTextAttrs
, nTab
);
3043 sc::ProcessFormulaEditText(maCells
, aFunc
);
3044 if (aFunc
.isModified())
3045 CellStorageModified();
3049 void ScColumn::UpdateCompile( bool bForceIfNameInUse
)
3051 UpdateCompileHandler
aFunc(bForceIfNameInUse
);
3052 sc::ProcessFormula(maCells
, aFunc
);
3056 void ScColumn::SetTabNo(SCTAB nNewTab
)
3059 pAttrArray
->SetTab( nNewTab
);
3061 TabNoSetter
aFunc(nTab
);
3062 sc::ProcessFormula(maCells
, aFunc
);
3065 void ScColumn::FindRangeNamesInUse(SCROW nRow1
, SCROW nRow2
, std::set
<sal_uInt16
>& rIndexes
) const
3067 UsedRangeNameFinder
aFunc(rIndexes
);
3068 sc::ParseFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aFunc
);
3071 void ScColumn::SetDirtyVar()
3073 SetDirtyVarHandler aFunc
;
3074 sc::ProcessFormula(maCells
, aFunc
);
3077 bool ScColumn::IsFormulaDirty( SCROW nRow
) const
3079 if (!ValidRow(nRow
))
3082 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
= maCells
.position(nRow
);
3083 sc::CellStoreType::const_iterator it
= aPos
.first
;
3084 if (it
->type
!= sc::element_type_formula
)
3085 // This is not a formula cell block.
3088 const ScFormulaCell
* p
= sc::formula_block::at(*it
->data
, aPos
.second
);
3089 return p
->GetDirty();
3092 void ScColumn::SetDirty()
3094 // is only done documentwide, no FormulaTracking
3095 sc::AutoCalcSwitch
aSwitch(*pDocument
, false);
3096 SetDirtyHandler
aFunc(*pDocument
);
3097 sc::ProcessFormula(maCells
, aFunc
);
3100 void ScColumn::SetDirty( SCROW nRow1
, SCROW nRow2
)
3102 // broadcasts everything within the range, with FormulaTracking
3103 sc::AutoCalcSwitch
aSwitch(*pDocument
, false);
3105 SetDirtyOnRangeHandler
aHdl(*this);
3106 sc::ProcessFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aHdl
, aHdl
);
3110 void ScColumn::SetTableOpDirty( const ScRange
& rRange
)
3112 sc::AutoCalcSwitch
aSwitch(*pDocument
, false);
3114 SCROW nRow1
= rRange
.aStart
.Row(), nRow2
= rRange
.aEnd
.Row();
3115 SetTableOpDirtyOnRangeHandler
aHdl(*this);
3116 sc::ProcessFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aHdl
, aHdl
);
3120 void ScColumn::SetDirtyAfterLoad()
3122 sc::AutoCalcSwitch
aSwitch(*pDocument
, false);
3123 SetDirtyAfterLoadHandler aFunc
;
3124 sc::ProcessFormula(maCells
, aFunc
);
3129 class RecalcOnRefMoveCollector
3131 std::vector
<SCROW
> maDirtyRows
;
3133 void operator() (size_t nRow
, ScFormulaCell
* pCell
)
3135 if (pCell
->GetDirty() && pCell
->GetCode()->IsRecalcModeOnRefMove())
3136 maDirtyRows
.push_back(nRow
);
3139 const std::vector
<SCROW
>& getDirtyRows() const
3147 void ScColumn::SetDirtyIfPostponed()
3149 sc::AutoCalcSwitch
aSwitch(*pDocument
, false);
3150 SetDirtyIfPostponedHandler aFunc
;
3151 sc::ProcessFormula(maCells
, aFunc
);
3154 void ScColumn::BroadcastRecalcOnRefMove()
3156 sc::AutoCalcSwitch
aSwitch(*pDocument
, false);
3157 RecalcOnRefMoveCollector aFunc
;
3158 sc::ProcessFormula(maCells
, aFunc
);
3159 BroadcastCells(aFunc
.getDirtyRows(), SC_HINT_DATACHANGED
);
3162 void ScColumn::CalcAll()
3164 CalcAllHandler aFunc
;
3165 sc::ProcessFormula(maCells
, aFunc
);
3168 void ScColumn::CompileAll()
3170 CompileAllHandler aFunc
;
3171 sc::ProcessFormula(maCells
, aFunc
);
3174 void ScColumn::CompileXML( ScProgress
& rProgress
)
3176 CompileXMLHandler
aFunc(rProgress
, *this);
3177 sc::ProcessFormula(maCells
, aFunc
);
3178 RegroupFormulaCells();
3181 bool ScColumn::CompileErrorCells(sal_uInt16 nErrCode
)
3183 CompileErrorCellsHandler
aHdl(*this, nErrCode
, pDocument
->GetGrammar());
3184 sc::ProcessFormula(maCells
, aHdl
);
3185 return aHdl
.isCompiled();
3188 void ScColumn::CalcAfterLoad()
3190 CalcAfterLoadHandler aFunc
;
3191 sc::ProcessFormula(maCells
, aFunc
);
3194 void ScColumn::ResetChanged( SCROW nStartRow
, SCROW nEndRow
)
3196 ResetChangedHandler aFunc
;
3197 sc::ProcessFormula(maCells
.begin(), maCells
, nStartRow
, nEndRow
, aFunc
);
3200 bool ScColumn::HasEditCells(SCROW nStartRow
, SCROW nEndRow
, SCROW
& rFirst
)
3202 // used in GetOptimalHeight - ambiguous script type counts as edit cell
3204 FindEditCellsHandler
aFunc(*this, maCellTextAttrs
, maCells
.begin());
3205 std::pair
<sc::CellStoreType::const_iterator
,size_t> aPos
=
3206 sc::FindFormulaEditText(maCells
, nStartRow
, nEndRow
, aFunc
);
3208 if (aPos
.first
== maCells
.end())
3211 rFirst
= aPos
.first
->position
+ aPos
.second
;
3216 SCsROW
ScColumn::SearchStyle(
3217 SCsROW nRow
, const ScStyleSheet
* pSearchStyle
, bool bUp
, bool bInSelection
,
3218 const ScMarkData
& rMark
) const
3222 if (rMark
.IsMultiMarked())
3223 return pAttrArray
->SearchStyle(nRow
, pSearchStyle
, bUp
, rMark
.GetArray()+nCol
);
3228 return pAttrArray
->SearchStyle( nRow
, pSearchStyle
, bUp
, NULL
);
3232 bool ScColumn::SearchStyleRange(
3233 SCsROW
& rRow
, SCsROW
& rEndRow
, const ScStyleSheet
* pSearchStyle
, bool bUp
,
3234 bool bInSelection
, const ScMarkData
& rMark
) const
3238 if (rMark
.IsMultiMarked())
3239 return pAttrArray
->SearchStyleRange(
3240 rRow
, rEndRow
, pSearchStyle
, bUp
, rMark
.GetArray() + nCol
);
3245 return pAttrArray
->SearchStyleRange( rRow
, rEndRow
, pSearchStyle
, bUp
, NULL
);
3248 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */