1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: column.cxx,v $
10 * $Revision: 1.31.128.9 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 // INCLUDE ---------------------------------------------------------------
40 #include <svtools/poolcach.hxx>
41 #include <svtools/zforlist.hxx>
42 #include <svx/scripttypeitem.hxx>
45 #include "scitems.hxx"
48 #include "document.hxx"
49 #include "docpool.hxx"
50 #include "attarray.hxx"
51 #include "patattr.hxx"
52 #include "compiler.hxx"
54 #include "markdata.hxx"
55 #include "detfunc.hxx" // for Notes in Sort/Swap
58 //#pragma optimize ( "", off )
59 // nur Search ohne Optimierung!
61 // STATIC DATA -----------------------------------------------------------
62 using namespace formula
;
64 inline BOOL
IsAmbiguousScriptNonZero( BYTE nScript
)
66 //! move to a header file
67 return ( nScript
!= SCRIPTTYPE_LATIN
&&
68 nScript
!= SCRIPTTYPE_ASIAN
&&
69 nScript
!= SCRIPTTYPE_COMPLEX
&&
73 // -----------------------------------------------------------------------------------------
76 ScColumn::ScColumn() :
90 if (pAttrArray
) delete pAttrArray
;
94 void ScColumn::Init(SCCOL nNewCol
, SCTAB nNewTab
, ScDocument
* pDoc
)
99 pAttrArray
= new ScAttrArray( nCol
, nTab
, pDocument
);
103 SCsROW
ScColumn::GetNextUnprotected( SCROW nRow
, BOOL bUp
) const
105 return pAttrArray
->GetNextUnprotected(nRow
, bUp
);
109 USHORT
ScColumn::GetBlockMatrixEdges( SCROW nRow1
, SCROW nRow2
, USHORT nMask
) const
111 // nix:0, mitte:1, unten:2, links:4, oben:8, rechts:16, offen:32
114 if ( nRow1
== nRow2
)
117 if ( Search( nRow1
, nIndex
) )
119 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
120 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
121 && ((ScFormulaCell
*)pCell
)->GetMatrixFlag() )
123 ScAddress
aOrg( ScAddress::INITIALIZE_INVALID
);
124 return ((ScFormulaCell
*)pCell
)->GetMatrixEdge( aOrg
);
131 ScAddress
aOrg( ScAddress::INITIALIZE_INVALID
);
135 Search( nRow1
, nIndex
);
136 while ( nIndex
< nCount
&& pItems
[nIndex
].nRow
<= nRow2
)
138 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
139 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
140 && ((ScFormulaCell
*)pCell
)->GetMatrixFlag() )
142 nEdges
= ((ScFormulaCell
*)pCell
)->GetMatrixEdge( aOrg
);
146 bOpen
= TRUE
; // obere Kante oeffnet, weitersehen
148 return nEdges
| 32; // es gibt was, was nicht geoeffnet wurde
149 else if ( nEdges
& 1 )
150 return nEdges
; // mittendrin
151 // (nMask & 16 und (4 und nicht 16)) oder
152 // (nMask & 4 und (16 und nicht 4))
153 if ( ((nMask
& 16) && (nEdges
& 4) && !(nEdges
& 16))
154 || ((nMask
& 4) && (nEdges
& 16) && !(nEdges
& 4)) )
155 return nEdges
; // nur linke/rechte Kante
157 bOpen
= FALSE
; // untere Kante schliesst
163 nEdges
|= 32; // es geht noch weiter
169 BOOL
ScColumn::HasSelectionMatrixFragment(const ScMarkData
& rMark
) const
171 if ( rMark
.IsMultiMarked() )
175 ScAddress
aOrg( ScAddress::INITIALIZE_INVALID
);
176 ScAddress
aCurOrg( ScAddress::INITIALIZE_INVALID
);
178 ScMarkArrayIter
aMarkIter( rMark
.GetArray()+nCol
);
179 while ( !bFound
&& aMarkIter
.Next( nTop
, nBottom
) )
184 Search( nTop
, nIndex
);
185 while ( !bFound
&& nIndex
< nCount
&& pItems
[nIndex
].nRow
<= nBottom
)
187 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
188 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
189 && ((ScFormulaCell
*)pCell
)->GetMatrixFlag() )
191 nEdges
= ((ScFormulaCell
*)pCell
)->GetMatrixEdge( aOrg
);
195 bOpen
= TRUE
; // obere Kante oeffnet, weitersehen
197 return TRUE
; // es gibt was, was nicht geoeffnet wurde
198 else if ( nEdges
& 1 )
199 bFound
= TRUE
; // mittendrin, alles selektiert?
200 // (4 und nicht 16) oder (16 und nicht 4)
201 if ( (((nEdges
& 4) | 16) ^ ((nEdges
& 16) | 4)) )
202 bFound
= TRUE
; // nur linke/rechte Kante, alles selektiert?
204 bOpen
= FALSE
; // untere Kante schliesst
207 { // alles selektiert?
208 if ( aCurOrg
!= aOrg
)
209 { // neue Matrix zu pruefen?
211 ScFormulaCell
* pFCell
;
212 if ( ((ScFormulaCell
*)pCell
)->GetMatrixFlag()
214 pFCell
= (ScFormulaCell
*) pDocument
->GetCell( aOrg
);
216 pFCell
= (ScFormulaCell
*)pCell
;
219 pFCell
->GetMatColsRows( nC
, nR
);
220 ScRange
aRange( aOrg
, ScAddress(
221 aOrg
.Col() + nC
- 1, aOrg
.Row() + nR
- 1,
223 if ( rMark
.IsAllMarked( aRange
) )
227 bFound
= FALSE
; // war schon
243 //UNUSED2009-05 BOOL ScColumn::HasLines( SCROW nRow1, SCROW nRow2, Rectangle& rSizes,
244 //UNUSED2009-05 BOOL bLeft, BOOL bRight ) const
246 //UNUSED2009-05 return pAttrArray->HasLines( nRow1, nRow2, rSizes, bLeft, bRight );
250 BOOL
ScColumn::HasAttrib( SCROW nRow1
, SCROW nRow2
, USHORT nMask
) const
252 return pAttrArray
->HasAttrib( nRow1
, nRow2
, nMask
);
256 BOOL
ScColumn::HasAttribSelection( const ScMarkData
& rMark
, USHORT nMask
) const
263 if (rMark
.IsMultiMarked())
265 ScMarkArrayIter
aMarkIter( rMark
.GetArray()+nCol
);
266 while (aMarkIter
.Next( nTop
, nBottom
) && !bFound
)
268 if (pAttrArray
->HasAttrib( nTop
, nBottom
, nMask
))
277 BOOL
ScColumn::ExtendMerge( SCCOL nThisCol
, SCROW nStartRow
, SCROW nEndRow
,
278 SCCOL
& rPaintCol
, SCROW
& rPaintRow
,
279 BOOL bRefresh
, BOOL bAttrs
)
281 return pAttrArray
->ExtendMerge( nThisCol
, nStartRow
, nEndRow
, rPaintCol
, rPaintRow
, bRefresh
, bAttrs
);
285 void ScColumn::MergeSelectionPattern( ScMergePatternState
& rState
, const ScMarkData
& rMark
, BOOL bDeep
) const
290 if ( rMark
.IsMultiMarked() )
292 const ScMarkArray
* pArray
= rMark
.GetArray() + nCol
;
293 if ( pArray
->HasMarks() )
295 ScMarkArrayIter
aMarkIter( pArray
);
296 while (aMarkIter
.Next( nTop
, nBottom
))
297 pAttrArray
->MergePatternArea( nTop
, nBottom
, rState
, bDeep
);
303 void ScColumn::MergePatternArea( ScMergePatternState
& rState
, SCROW nRow1
, SCROW nRow2
, BOOL bDeep
) const
305 pAttrArray
->MergePatternArea( nRow1
, nRow2
, rState
, bDeep
);
309 void ScColumn::MergeBlockFrame( SvxBoxItem
* pLineOuter
, SvxBoxInfoItem
* pLineInner
,
311 SCROW nStartRow
, SCROW nEndRow
, BOOL bLeft
, SCCOL nDistRight
) const
313 pAttrArray
->MergeBlockFrame( pLineOuter
, pLineInner
, rFlags
, nStartRow
, nEndRow
, bLeft
, nDistRight
);
317 void ScColumn::ApplyBlockFrame( const SvxBoxItem
* pLineOuter
, const SvxBoxInfoItem
* pLineInner
,
318 SCROW nStartRow
, SCROW nEndRow
, BOOL bLeft
, SCCOL nDistRight
)
320 pAttrArray
->ApplyBlockFrame( pLineOuter
, pLineInner
, nStartRow
, nEndRow
, bLeft
, nDistRight
);
324 const ScPatternAttr
* ScColumn::GetPattern( SCROW nRow
) const
326 return pAttrArray
->GetPattern( nRow
);
330 const SfxPoolItem
* ScColumn::GetAttr( SCROW nRow
, USHORT nWhich
) const
332 return &pAttrArray
->GetPattern( nRow
)->GetItemSet().Get(nWhich
);
336 const ScPatternAttr
* ScColumn::GetMostUsedPattern( SCROW nStartRow
, SCROW nEndRow
) const
338 ::std::map
< const ScPatternAttr
*, size_t > aAttrMap
;
339 const ScPatternAttr
* pMaxPattern
= 0;
340 size_t nMaxCount
= 0;
342 ScAttrIterator
aAttrIter( pAttrArray
, nStartRow
, nEndRow
);
343 const ScPatternAttr
* pPattern
;
344 SCROW nAttrRow1
= 0, nAttrRow2
= 0;
346 while( (pPattern
= aAttrIter
.Next( nAttrRow1
, nAttrRow2
)) != 0 )
348 size_t& rnCount
= aAttrMap
[ pPattern
];
349 rnCount
+= (nAttrRow2
- nAttrRow1
+ 1);
350 if( rnCount
> nMaxCount
)
352 pMaxPattern
= pPattern
;
360 sal_uInt32
ScColumn::GetNumberFormat( SCROW nStartRow
, SCROW nEndRow
) const
362 SCROW nPatStartRow
, nPatEndRow
;
363 const ScPatternAttr
* pPattern
= pAttrArray
->GetPatternRange(nPatStartRow
, nPatEndRow
, nStartRow
);
364 sal_uInt32 nFormat
= pPattern
->GetNumberFormat(pDocument
->GetFormatTable());
365 while (nEndRow
> nPatEndRow
)
367 nStartRow
= nPatEndRow
+ 1;
368 pPattern
= pAttrArray
->GetPatternRange(nPatStartRow
, nPatEndRow
, nStartRow
);
369 sal_uInt32 nTmpFormat
= pPattern
->GetNumberFormat(pDocument
->GetFormatTable());
370 if (nFormat
!= nTmpFormat
)
377 ULONG
ScColumn::GetNumberFormat( SCROW nRow
) const
379 return pAttrArray
->GetPattern( nRow
)->GetNumberFormat( pDocument
->GetFormatTable() );
383 SCsROW
ScColumn::ApplySelectionCache( SfxItemPoolCache
* pCache
, const ScMarkData
& rMark
, ScEditDataArray
* pDataArray
)
389 if ( rMark
.IsMultiMarked() )
391 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
392 while (aMarkIter
.Next( nTop
, nBottom
))
394 pAttrArray
->ApplyCacheArea( nTop
, nBottom
, pCache
, pDataArray
);
401 else if (nTop
==0 && nBottom
==MAXROW
)
408 void ScColumn::ChangeSelectionIndent( BOOL bIncrement
, const ScMarkData
& rMark
)
413 if ( pAttrArray
&& rMark
.IsMultiMarked() )
415 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
416 while (aMarkIter
.Next( nTop
, nBottom
))
417 pAttrArray
->ChangeIndent(nTop
, nBottom
, bIncrement
);
422 void ScColumn::ClearSelectionItems( const USHORT
* pWhich
,const ScMarkData
& rMark
)
427 if ( pAttrArray
&& rMark
.IsMultiMarked() )
429 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
430 while (aMarkIter
.Next( nTop
, nBottom
))
431 pAttrArray
->ClearItems(nTop
, nBottom
, pWhich
);
436 void ScColumn::DeleteSelection( USHORT nDelFlag
, const ScMarkData
& rMark
)
441 if ( rMark
.IsMultiMarked() )
443 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
444 while (aMarkIter
.Next( nTop
, nBottom
))
445 DeleteArea(nTop
, nBottom
, nDelFlag
);
450 void ScColumn::ApplyPattern( SCROW nRow
, const ScPatternAttr
& rPatAttr
)
452 const SfxItemSet
* pSet
= &rPatAttr
.GetItemSet();
453 SfxItemPoolCache
aCache( pDocument
->GetPool(), pSet
);
455 const ScPatternAttr
* pPattern
= pAttrArray
->GetPattern( nRow
);
457 // TRUE = alten Eintrag behalten
459 ScPatternAttr
* pNewPattern
= (ScPatternAttr
*) &aCache
.ApplyTo( *pPattern
, TRUE
);
460 ScDocumentPool::CheckRef( *pPattern
);
461 ScDocumentPool::CheckRef( *pNewPattern
);
463 if (pNewPattern
!= pPattern
)
464 pAttrArray
->SetPattern( nRow
, pNewPattern
);
468 void ScColumn::ApplyPatternArea( SCROW nStartRow
, SCROW nEndRow
, const ScPatternAttr
& rPatAttr
,
469 ScEditDataArray
* pDataArray
)
471 const SfxItemSet
* pSet
= &rPatAttr
.GetItemSet();
472 SfxItemPoolCache
aCache( pDocument
->GetPool(), pSet
);
473 pAttrArray
->ApplyCacheArea( nStartRow
, nEndRow
, &aCache
, pDataArray
);
477 void ScColumn::ApplyPatternIfNumberformatIncompatible( const ScRange
& rRange
,
478 const ScPatternAttr
& rPattern
, short nNewType
)
480 const SfxItemSet
* pSet
= &rPattern
.GetItemSet();
481 SfxItemPoolCache
aCache( pDocument
->GetPool(), pSet
);
482 SvNumberFormatter
* pFormatter
= pDocument
->GetFormatTable();
483 SCROW nEndRow
= rRange
.aEnd
.Row();
484 for ( SCROW nRow
= rRange
.aStart
.Row(); nRow
<= nEndRow
; nRow
++ )
487 const ScPatternAttr
* pPattern
= pAttrArray
->GetPatternRange(
488 nRow1
, nRow2
, nRow
);
489 ULONG nFormat
= pPattern
->GetNumberFormat( pFormatter
);
490 short nOldType
= pFormatter
->GetType( nFormat
);
491 if ( nOldType
== nNewType
|| pFormatter
->IsCompatible( nOldType
, nNewType
) )
495 SCROW nNewRow1
= Max( nRow1
, nRow
);
496 SCROW nNewRow2
= Min( nRow2
, nEndRow
);
497 pAttrArray
->ApplyCacheArea( nNewRow1
, nNewRow2
, &aCache
);
504 void ScColumn::ApplyStyle( SCROW nRow
, const ScStyleSheet
& rStyle
)
506 const ScPatternAttr
* pPattern
= pAttrArray
->GetPattern(nRow
);
507 ScPatternAttr
* pNewPattern
= new ScPatternAttr(*pPattern
);
510 pNewPattern
->SetStyleSheet((ScStyleSheet
*)&rStyle
);
511 pAttrArray
->SetPattern(nRow
, pNewPattern
, TRUE
);
517 void ScColumn::ApplyStyleArea( SCROW nStartRow
, SCROW nEndRow
, const ScStyleSheet
& rStyle
)
519 pAttrArray
->ApplyStyleArea(nStartRow
, nEndRow
, (ScStyleSheet
*)&rStyle
);
523 void ScColumn::ApplySelectionStyle(const ScStyleSheet
& rStyle
, const ScMarkData
& rMark
)
528 if ( rMark
.IsMultiMarked() )
530 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
531 while (aMarkIter
.Next( nTop
, nBottom
))
532 pAttrArray
->ApplyStyleArea(nTop
, nBottom
, (ScStyleSheet
*)&rStyle
);
537 void ScColumn::ApplySelectionLineStyle( const ScMarkData
& rMark
,
538 const SvxBorderLine
* pLine
, BOOL bColorOnly
)
540 if ( bColorOnly
&& !pLine
)
546 if (rMark
.IsMultiMarked())
548 ScMarkArrayIter
aMarkIter( rMark
.GetArray()+nCol
);
549 while (aMarkIter
.Next( nTop
, nBottom
))
550 pAttrArray
->ApplyLineStyleArea(nTop
, nBottom
, pLine
, bColorOnly
);
555 const ScStyleSheet
* ScColumn::GetStyle( SCROW nRow
) const
557 return pAttrArray
->GetPattern( nRow
)->GetStyleSheet();
561 const ScStyleSheet
* ScColumn::GetSelectionStyle( const ScMarkData
& rMark
, BOOL
& rFound
) const
564 if (!rMark
.IsMultiMarked())
566 DBG_ERROR("ScColumn::GetSelectionStyle ohne Selektion");
572 const ScStyleSheet
* pStyle
= NULL
;
573 const ScStyleSheet
* pNewStyle
;
575 ScMarkArrayIter
aMarkIter( rMark
.GetArray() + nCol
);
578 while (bEqual
&& aMarkIter
.Next( nTop
, nBottom
))
580 ScAttrIterator
aAttrIter( pAttrArray
, nTop
, nBottom
);
583 const ScPatternAttr
* pPattern
;
584 while (bEqual
&& ( pPattern
= aAttrIter
.Next( nRow
, nDummy
) ) != NULL
)
586 pNewStyle
= pPattern
->GetStyleSheet();
588 if ( !pNewStyle
|| ( pStyle
&& pNewStyle
!= pStyle
) )
589 bEqual
= FALSE
; // unterschiedliche
594 return bEqual
? pStyle
: NULL
;
598 const ScStyleSheet
* ScColumn::GetAreaStyle( BOOL
& rFound
, SCROW nRow1
, SCROW nRow2
) const
604 const ScStyleSheet
* pStyle
= NULL
;
605 const ScStyleSheet
* pNewStyle
;
607 ScAttrIterator
aAttrIter( pAttrArray
, nRow1
, nRow2
);
610 const ScPatternAttr
* pPattern
;
611 while (bEqual
&& ( pPattern
= aAttrIter
.Next( nRow
, nDummy
) ) != NULL
)
613 pNewStyle
= pPattern
->GetStyleSheet();
615 if ( !pNewStyle
|| ( pStyle
&& pNewStyle
!= pStyle
) )
616 bEqual
= FALSE
; // unterschiedliche
620 return bEqual
? pStyle
: NULL
;
623 void ScColumn::FindStyleSheet( const SfxStyleSheetBase
* pStyleSheet
, ScFlatBoolRowSegments
& rUsedRows
, bool bReset
)
625 pAttrArray
->FindStyleSheet( pStyleSheet
, rUsedRows
, bReset
);
628 BOOL
ScColumn::IsStyleSheetUsed( const ScStyleSheet
& rStyle
, BOOL bGatherAllStyles
) const
630 return pAttrArray
->IsStyleSheetUsed( rStyle
, bGatherAllStyles
);
634 BOOL
ScColumn::ApplyFlags( SCROW nStartRow
, SCROW nEndRow
, INT16 nFlags
)
636 return pAttrArray
->ApplyFlags( nStartRow
, nEndRow
, nFlags
);
640 BOOL
ScColumn::RemoveFlags( SCROW nStartRow
, SCROW nEndRow
, INT16 nFlags
)
642 return pAttrArray
->RemoveFlags( nStartRow
, nEndRow
, nFlags
);
646 void ScColumn::ClearItems( SCROW nStartRow
, SCROW nEndRow
, const USHORT
* pWhich
)
648 pAttrArray
->ClearItems( nStartRow
, nEndRow
, pWhich
);
652 void ScColumn::SetPattern( SCROW nRow
, const ScPatternAttr
& rPatAttr
, BOOL bPutToPool
)
654 pAttrArray
->SetPattern( nRow
, &rPatAttr
, bPutToPool
);
658 void ScColumn::SetPatternArea( SCROW nStartRow
, SCROW nEndRow
,
659 const ScPatternAttr
& rPatAttr
, BOOL bPutToPool
)
661 pAttrArray
->SetPatternArea( nStartRow
, nEndRow
, &rPatAttr
, bPutToPool
);
665 void ScColumn::ApplyAttr( SCROW nRow
, const SfxPoolItem
& rAttr
)
667 // um nur ein neues SetItem zu erzeugen, brauchen wir keinen SfxItemPoolCache.
668 //! Achtung: der SfxItemPoolCache scheint zuviele Refs fuer das neue SetItem zu erzeugen ??
670 ScDocumentPool
* pDocPool
= pDocument
->GetPool();
672 const ScPatternAttr
* pOldPattern
= pAttrArray
->GetPattern( nRow
);
673 ScPatternAttr
* pTemp
= new ScPatternAttr(*pOldPattern
);
674 pTemp
->GetItemSet().Put(rAttr
);
675 const ScPatternAttr
* pNewPattern
= (const ScPatternAttr
*) &pDocPool
->Put( *pTemp
);
677 if ( pNewPattern
!= pOldPattern
)
678 pAttrArray
->SetPattern( nRow
, pNewPattern
);
680 pDocPool
->Remove( *pNewPattern
); // ausser Spesen nichts gewesen
684 // alte Version mit SfxItemPoolCache:
686 SfxItemPoolCache
aCache( pDocument
->GetPool(), &rAttr
);
688 const ScPatternAttr
* pPattern
= pAttrArray
->GetPattern( nRow
);
690 // TRUE = alten Eintrag behalten
692 ScPatternAttr
* pNewPattern
= (ScPatternAttr
*) &aCache
.ApplyTo( *pPattern
, TRUE
);
693 ScDocumentPool::CheckRef( *pPattern
);
694 ScDocumentPool::CheckRef( *pNewPattern
);
696 if (pNewPattern
!= pPattern
)
697 pAttrArray
->SetPattern( nRow
, pNewPattern
);
702 #pragma optimize ( "", off )
706 BOOL
ScColumn::Search( SCROW nRow
, SCSIZE
& nIndex
) const
708 if ( !pItems
|| !nCount
)
713 SCROW nMinRow
= pItems
[0].nRow
;
714 if ( nRow
<= nMinRow
)
717 return nRow
== nMinRow
;
719 SCROW nMaxRow
= pItems
[nCount
-1].nRow
;
720 if ( nRow
>= nMaxRow
)
722 if ( nRow
== nMaxRow
)
735 long nLo
= nOldLo
= 0;
736 long nHi
= nOldHi
= Min(static_cast<long>(nCount
)-1, static_cast<long>(nRow
) );
739 // quite continuous distribution? => interpolating search
740 BOOL bInterpol
= (static_cast<SCSIZE
>(nMaxRow
- nMinRow
) < nCount
* 2);
743 while ( !bFound
&& nLo
<= nHi
)
745 if ( !bInterpol
|| nHi
- nLo
< 3 )
746 i
= (nLo
+nHi
) / 2; // no effort, no division by zero
748 { // interpolating search
749 long nLoRow
= pItems
[nLo
].nRow
; // no unsigned underflow upon substraction
750 i
= nLo
+ (long)((long)(nRow
- nLoRow
) * (nHi
- nLo
)
751 / (pItems
[nHi
].nRow
- nLoRow
));
752 if ( i
< 0 || static_cast<SCSIZE
>(i
) >= nCount
)
788 nIndex
= static_cast<SCSIZE
>(i
);
790 nIndex
= static_cast<SCSIZE
>(nLo
); // rear index
795 #pragma optimize ( "", on )
799 ScBaseCell
* ScColumn::GetCell( SCROW nRow
) const
802 if (Search(nRow
, nIndex
))
803 return pItems
[nIndex
].pCell
;
808 void ScColumn::Resize( SCSIZE nSize
)
810 if (nSize
> sal::static_int_cast
<SCSIZE
>(MAXROWCOUNT
))
818 SCSIZE nNewSize
= nSize
+ COLUMN_DELTA
- 1;
819 nNewSize
-= nNewSize
% COLUMN_DELTA
;
821 pNewItems
= new ColEntry
[nLimit
];
831 memmove( pNewItems
, pItems
, nCount
* sizeof(ColEntry
) );
837 // SwapRow zum Sortieren
841 /** Moves broadcaster from old cell to new cell if exists, otherwise creates a new note cell. */
842 void lclTakeBroadcaster( ScBaseCell
*& rpCell
, SvtBroadcaster
* pBC
)
847 rpCell
->TakeBroadcaster( pBC
);
849 rpCell
= new ScNoteCell( pBC
);
855 void ScColumn::SwapRow(SCROW nRow1
, SCROW nRow2
)
857 // TODO: We probably don't need to broadcast value changes here since
858 // deleting and inserting cells do it.
859 bool bBroadcast
= false;
861 /* Simple swap of cell pointers does not work if broadcasters exist (crash
862 if cell broadcasts directly or indirectly to itself). While swapping
863 the cells, broadcasters have to remain at old positions! */
865 /* While cloning cells, do not clone notes, but move note pointers to new
866 cells. This prevents creation of new caption drawing objects for every
867 swap operation while sorting. */
869 ScBaseCell
* pCell1
= 0;
871 if ( Search( nRow1
, nIndex1
) )
872 pCell1
= pItems
[nIndex1
].pCell
;
874 ScBaseCell
* pCell2
= 0;
876 if ( Search( nRow2
, nIndex2
) )
877 pCell2
= pItems
[nIndex2
].pCell
;
879 // no cells found, nothing to do
880 if ( !pCell1
&& !pCell2
)
883 // swap variables if first cell is empty, to save some code below
886 ::std::swap( nRow1
, nRow2
);
887 ::std::swap( nIndex1
, nIndex2
);
888 ::std::swap( pCell1
, pCell2
);
891 // from here: first cell (pCell1, nIndex1) exists always
893 ScAddress
aPos1( nCol
, nRow1
, nTab
);
894 ScAddress
aPos2( nCol
, nRow2
, nTab
);
896 CellType eType1
= pCell1
->GetCellType();
897 CellType eType2
= pCell2
? pCell2
->GetCellType() : CELLTYPE_NONE
;
899 ScFormulaCell
* pFmlaCell1
= (eType1
== CELLTYPE_FORMULA
) ? static_cast< ScFormulaCell
* >( pCell1
) : 0;
900 ScFormulaCell
* pFmlaCell2
= (eType2
== CELLTYPE_FORMULA
) ? static_cast< ScFormulaCell
* >( pCell2
) : 0;
902 // simple swap if no formula cells present
903 if ( !pFmlaCell1
&& !pFmlaCell2
)
905 // remember cell broadcasters, must remain at old position
906 SvtBroadcaster
* pBC1
= pCell1
->ReleaseBroadcaster();
910 /* Both cells exist, no formula cells involved, a simple swap can
911 be performed (but keep broadcasters and notes at old position). */
912 pItems
[nIndex1
].pCell
= pCell2
;
913 pItems
[nIndex2
].pCell
= pCell1
;
915 SvtBroadcaster
* pBC2
= pCell2
->ReleaseBroadcaster();
916 pCell1
->TakeBroadcaster( pBC2
);
917 pCell2
->TakeBroadcaster( pBC1
);
921 ScHint
aHint1( SC_HINT_DATACHANGED
, aPos1
, pCell2
);
922 pDocument
->Broadcast( aHint1
);
923 ScHint
aHint2( SC_HINT_DATACHANGED
, aPos2
, pCell1
);
924 pDocument
->Broadcast( aHint2
);
929 ScNoteCell
* pDummyCell
= pBC1
? new ScNoteCell( pBC1
) : 0;
932 // insert dummy note cell (without note) containing old broadcaster
933 pItems
[nIndex1
].pCell
= pDummyCell
;
937 // remove ColEntry at old position
939 memmove( &pItems
[nIndex1
], &pItems
[nIndex1
+ 1], (nCount
- nIndex1
) * sizeof(ColEntry
) );
940 pItems
[nCount
].nRow
= 0;
941 pItems
[nCount
].pCell
= 0;
944 // insert ColEntry at new position
945 Insert( nRow2
, pCell1
);
947 pDocument
->Broadcast( ScHint( SC_HINT_DATACHANGED
, aPos1
, pDummyCell
) );
953 // from here: at least one of the cells is a formula cell
955 /* Never move any array formulas. Disabling sort if parts of array
956 formulas are contained is done at UI. */
957 if ( (pFmlaCell1
&& (pFmlaCell1
->GetMatrixFlag() != 0)) || (pFmlaCell2
&& (pFmlaCell2
->GetMatrixFlag() != 0)) )
960 // do not swap, if formulas are equal
961 if ( pFmlaCell1
&& pFmlaCell2
)
963 ScTokenArray
* pCode1
= pFmlaCell1
->GetCode();
964 ScTokenArray
* pCode2
= pFmlaCell2
->GetCode();
966 if (pCode1
->GetLen() == pCode2
->GetLen()) // nicht-UPN
969 USHORT nLen
= pCode1
->GetLen();
970 FormulaToken
** ppToken1
= pCode1
->GetArray();
971 FormulaToken
** ppToken2
= pCode2
->GetArray();
972 for (USHORT i
=0; i
<nLen
; i
++)
974 if ( !ppToken1
[i
]->TextEqual(*(ppToken2
[i
])) ||
975 ppToken1
[i
]->Is3DRef() || ppToken2
[i
]->Is3DRef() )
982 // do not swap formula cells with equal formulas, but swap notes
985 ScPostIt
* pNote1
= pCell1
->ReleaseNote();
986 pCell1
->TakeNote( pCell2
->ReleaseNote() );
987 pCell2
->TakeNote( pNote1
);
993 // hier kein UpdateReference wegen #30529# - mitsortiert werden nur noch relative Referenzen
994 // long dy = (long)nRow2 - (long)nRow1;
996 /* Create clone of pCell1 at position of pCell2 (pCell1 exists always, see
997 variable swapping above). Do not clone the note, but move pointer of
998 old note to new cell. */
999 ScBaseCell
* pNew2
= pCell1
->CloneWithoutNote( *pDocument
, aPos2
, SC_CLONECELL_ADJUST3DREL
);
1000 pNew2
->TakeNote( pCell1
->ReleaseNote() );
1002 /* Create clone of pCell2 at position of pCell1. Do not clone the note,
1003 but move pointer of old note to new cell. */
1004 ScBaseCell
* pNew1
= 0;
1007 pNew1
= pCell2
->CloneWithoutNote( *pDocument
, aPos1
, SC_CLONECELL_ADJUST3DREL
);
1008 pNew1
->TakeNote( pCell2
->ReleaseNote() );
1011 // move old broadcasters new cells at the same old position
1012 SvtBroadcaster
* pBC1
= pCell1
->ReleaseBroadcaster();
1013 lclTakeBroadcaster( pNew1
, pBC1
);
1014 SvtBroadcaster
* pBC2
= pCell2
? pCell2
->ReleaseBroadcaster() : 0;
1015 lclTakeBroadcaster( pNew2
, pBC2
);
1017 /* Insert the new cells. Old cell has to be deleted, if there is no new
1018 cell (call to Insert deletes old cell by itself). */
1020 Delete( nRow1
); // deletes pCell1
1022 Insert( nRow1
, pNew1
); // deletes pCell1, inserts pNew1
1024 if ( pCell2
&& !pNew2
)
1025 Delete( nRow2
); // deletes pCell2
1027 Insert( nRow2
, pNew2
); // deletes pCell2 (if existing), inserts pNew2
1029 // #64122# Bei Formeln hinterher nochmal broadcasten, damit die Formel nicht in irgendwelchen
1030 // FormulaTrack-Listen landet, ohne die Broadcaster beruecksichtigt zu haben
1031 // (erst hier, wenn beide Zellen eingefuegt sind)
1034 if ( pBC1
&& pFmlaCell2
)
1035 pDocument
->Broadcast( ScHint( SC_HINT_DATACHANGED
, aPos1
, pNew1
) );
1036 if ( pBC2
&& pFmlaCell1
)
1037 pDocument
->Broadcast( ScHint( SC_HINT_DATACHANGED
, aPos2
, pNew2
) );
1042 void ScColumn::SwapCell( SCROW nRow
, ScColumn
& rCol
)
1044 ScBaseCell
* pCell1
= 0;
1046 if ( Search( nRow
, nIndex1
) )
1047 pCell1
= pItems
[nIndex1
].pCell
;
1049 ScBaseCell
* pCell2
= 0;
1051 if ( rCol
.Search( nRow
, nIndex2
) )
1052 pCell2
= rCol
.pItems
[nIndex2
].pCell
;
1054 // reverse call if own cell is missing (ensures own existing cell in following code)
1058 rCol
.SwapCell( nRow
, *this );
1062 // from here: own cell (pCell1, nIndex1) exists always
1064 ScFormulaCell
* pFmlaCell1
= (pCell1
->GetCellType() == CELLTYPE_FORMULA
) ? static_cast< ScFormulaCell
* >( pCell1
) : 0;
1065 ScFormulaCell
* pFmlaCell2
= (pCell2
&& (pCell2
->GetCellType() == CELLTYPE_FORMULA
)) ? static_cast< ScFormulaCell
* >( pCell2
) : 0;
1070 pItems
[nIndex1
].pCell
= pCell2
;
1071 rCol
.pItems
[nIndex2
].pCell
= pCell1
;
1072 // Referenzen aktualisieren
1073 SCsCOL dx
= rCol
.nCol
- nCol
;
1076 ScRange
aRange( ScAddress( rCol
.nCol
, 0, nTab
),
1077 ScAddress( rCol
.nCol
, MAXROW
, nTab
) );
1078 pFmlaCell1
->aPos
.SetCol( rCol
.nCol
);
1079 pFmlaCell1
->UpdateReference(URM_MOVE
, aRange
, dx
, 0, 0);
1083 ScRange
aRange( ScAddress( nCol
, 0, nTab
),
1084 ScAddress( nCol
, MAXROW
, nTab
) );
1085 pFmlaCell2
->aPos
.SetCol( nCol
);
1086 pFmlaCell2
->UpdateReference(URM_MOVE
, aRange
, -dx
, 0, 0);
1093 memmove( &pItems
[nIndex1
], &pItems
[nIndex1
+ 1], (nCount
- nIndex1
) * sizeof(ColEntry
) );
1094 pItems
[nCount
].nRow
= 0;
1095 pItems
[nCount
].pCell
= 0;
1096 // Referenzen aktualisieren
1097 SCsCOL dx
= rCol
.nCol
- nCol
;
1100 ScRange
aRange( ScAddress( rCol
.nCol
, 0, nTab
),
1101 ScAddress( rCol
.nCol
, MAXROW
, nTab
) );
1102 pFmlaCell1
->aPos
.SetCol( rCol
.nCol
);
1103 pFmlaCell1
->UpdateReference(URM_MOVE
, aRange
, dx
, 0, 0);
1106 rCol
.Insert(nRow
, pCell1
);
1111 BOOL
ScColumn::TestInsertCol( SCROW nStartRow
, SCROW nEndRow
) const
1117 for (SCSIZE i
=0; (i
<nCount
) && bTest
; i
++)
1118 bTest
= (pItems
[i
].nRow
< nStartRow
) || (pItems
[i
].nRow
> nEndRow
)
1119 || pItems
[i
].pCell
->IsBlank();
1121 // AttrArray testet nur zusammengefasste
1123 if ((bTest
) && (pAttrArray
))
1124 bTest
= pAttrArray
->TestInsertCol(nStartRow
, nEndRow
);
1126 //! rausgeschobene Attribute bei Undo beruecksichtigen
1135 BOOL
ScColumn::TestInsertRow( SCSIZE nSize
) const
1137 // AttrArray only looks for merged cells
1139 if ( pItems
&& nCount
)
1140 return ( nSize
<= sal::static_int_cast
<SCSIZE
>(MAXROW
) &&
1141 pItems
[nCount
-1].nRow
<= MAXROW
-(SCROW
)nSize
&& pAttrArray
->TestInsertRow( nSize
) );
1143 return pAttrArray
->TestInsertRow( nSize
);
1146 //! rausgeschobene Attribute bei Undo beruecksichtigen
1148 if ( nSize
> static_cast<SCSIZE
>(MAXROW
) )
1151 SCSIZE nVis
= nCount
;
1152 while ( nVis
&& pItems
[nVis
-1].pCell
->IsBlank() )
1156 return ( pItems
[nVis
-1].nRow
<= MAXROW
-nSize
);
1163 void ScColumn::InsertRow( SCROW nStartRow
, SCSIZE nSize
)
1165 pAttrArray
->InsertRow( nStartRow
, nSize
);
1169 if ( !pItems
|| !nCount
)
1173 Search( nStartRow
, i
);
1177 BOOL bOldAutoCalc
= pDocument
->GetAutoCalc();
1178 pDocument
->SetAutoCalc( FALSE
); // Mehrfachberechnungen vermeiden
1180 SCSIZE nNewCount
= nCount
;
1181 BOOL bCountChanged
= FALSE
;
1182 ScAddress
aAdr( nCol
, 0, nTab
);
1183 ScHint
aHint( SC_HINT_DATACHANGED
, aAdr
, NULL
); // only areas (ScBaseCell* == NULL)
1184 ScAddress
& rAddress
= aHint
.GetAddress();
1185 // for sparse occupation use single broadcasts, not ranges
1186 BOOL bSingleBroadcasts
= (((pItems
[nCount
-1].nRow
- pItems
[i
].nRow
) /
1188 if ( bSingleBroadcasts
)
1190 SCROW nLastBroadcast
= MAXROW
+1;
1191 for ( ; i
< nCount
; i
++)
1193 SCROW nOldRow
= pItems
[i
].nRow
;
1194 // #43940# Aenderung Quelle broadcasten
1195 if ( nLastBroadcast
!= nOldRow
)
1196 { // direkt aufeinanderfolgende nicht doppelt broadcasten
1197 rAddress
.SetRow( nOldRow
);
1198 pDocument
->AreaBroadcast( aHint
);
1200 SCROW nNewRow
= (pItems
[i
].nRow
+= nSize
);
1201 // #43940# Aenderung Ziel broadcasten
1202 rAddress
.SetRow( nNewRow
);
1203 pDocument
->AreaBroadcast( aHint
);
1204 nLastBroadcast
= nNewRow
;
1205 ScBaseCell
* pCell
= pItems
[i
].pCell
;
1206 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1207 ((ScFormulaCell
*)pCell
)->aPos
.SetRow( nNewRow
);
1208 if ( nNewRow
> MAXROW
&& !bCountChanged
)
1211 bCountChanged
= TRUE
;
1217 rAddress
.SetRow( pItems
[i
].nRow
);
1218 ScRange
aRange( rAddress
);
1219 for ( ; i
< nCount
; i
++)
1221 SCROW nNewRow
= (pItems
[i
].nRow
+= nSize
);
1222 ScBaseCell
* pCell
= pItems
[i
].pCell
;
1223 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1224 ((ScFormulaCell
*)pCell
)->aPos
.SetRow( nNewRow
);
1225 if ( nNewRow
> MAXROW
&& !bCountChanged
)
1228 bCountChanged
= TRUE
;
1229 aRange
.aEnd
.SetRow( MAXROW
);
1232 if ( !bCountChanged
)
1233 aRange
.aEnd
.SetRow( pItems
[nCount
-1].nRow
);
1234 pDocument
->AreaBroadcastInRange( aRange
, aHint
);
1239 SCSIZE nDelCount
= nCount
- nNewCount
;
1240 ScBaseCell
** ppDelCells
= new ScBaseCell
*[nDelCount
];
1241 SCROW
* pDelRows
= new SCROW
[nDelCount
];
1242 for (i
= 0; i
< nDelCount
; i
++)
1244 ppDelCells
[i
] = pItems
[nNewCount
+i
].pCell
;
1245 pDelRows
[i
] = pItems
[nNewCount
+i
].nRow
;
1249 for (i
= 0; i
< nDelCount
; i
++)
1251 ScBaseCell
* pCell
= ppDelCells
[i
];
1252 DBG_ASSERT( pCell
->IsBlank(), "sichtbare Zelle weggeschoben" );
1253 SvtBroadcaster
* pBC
= pCell
->GetBroadcaster();
1256 MoveListeners( *pBC
, pDelRows
[i
] - nSize
);
1257 pCell
->DeleteBroadcaster();
1266 pDocument
->SetAutoCalc( bOldAutoCalc
);
1270 void ScColumn::CopyToClip(SCROW nRow1
, SCROW nRow2
, ScColumn
& rColumn
, BOOL bKeepScenarioFlags
, BOOL bCloneNoteCaptions
)
1272 pAttrArray
->CopyArea( nRow1
, nRow2
, 0, *rColumn
.pAttrArray
,
1273 bKeepScenarioFlags
? (SC_MF_ALL
& ~SC_MF_SCENARIO
) : SC_MF_ALL
);
1276 SCSIZE nBlockCount
= 0;
1277 SCSIZE nStartIndex
= 0, nEndIndex
= 0;
1278 for (i
= 0; i
< nCount
; i
++)
1279 if ((pItems
[i
].nRow
>= nRow1
) && (pItems
[i
].nRow
<= nRow2
))
1286 // im Clipboard muessen interpretierte Zellen stehen, um andere Formate
1287 // (Text, Grafik...) erzueugen zu koennen
1289 if ( pItems
[i
].pCell
->GetCellType() == CELLTYPE_FORMULA
)
1291 ScFormulaCell
* pFCell
= (ScFormulaCell
*) pItems
[i
].pCell
;
1292 if (pFCell
->GetDirty() && pDocument
->GetAutoCalc())
1293 pFCell
->Interpret();
1299 int nCloneFlags
= bCloneNoteCaptions
? SC_CLONECELL_DEFAULT
: SC_CLONECELL_NOCAPTION
;
1300 rColumn
.Resize( rColumn
.GetCellCount() + nBlockCount
);
1301 ScAddress
aOwnPos( nCol
, 0, nTab
);
1302 ScAddress
aDestPos( rColumn
.nCol
, 0, rColumn
.nTab
);
1303 for (i
= nStartIndex
; i
<= nEndIndex
; i
++)
1305 aOwnPos
.SetRow( pItems
[i
].nRow
);
1306 aDestPos
.SetRow( pItems
[i
].nRow
);
1307 ScBaseCell
* pNewCell
= pItems
[i
].pCell
->CloneWithNote( aOwnPos
, *rColumn
.pDocument
, aDestPos
, nCloneFlags
);
1308 rColumn
.Append( aDestPos
.Row(), pNewCell
);
1314 void ScColumn::CopyToColumn(SCROW nRow1
, SCROW nRow2
, USHORT nFlags
, BOOL bMarked
,
1315 ScColumn
& rColumn
, const ScMarkData
* pMarkData
, BOOL bAsLink
)
1320 if (pMarkData
&& pMarkData
->IsMultiMarked())
1322 ScMarkArrayIter
aIter( pMarkData
->GetArray()+nCol
);
1324 while ( aIter
.Next( nStart
, nEnd
) && nStart
<= nRow2
)
1326 if ( nEnd
>= nRow1
)
1327 CopyToColumn( Max(nRow1
,nStart
), Min(nRow2
,nEnd
),
1328 nFlags
, FALSE
, rColumn
, pMarkData
, bAsLink
);
1333 DBG_ERROR("CopyToColumn: bMarked, aber keine Markierung");
1338 if ( (nFlags
& IDF_ATTRIB
) != 0 )
1340 if ( (nFlags
& IDF_STYLES
) != IDF_STYLES
)
1341 { // StyleSheets im Zieldokument bleiben erhalten
1342 // z.B. DIF und RTF Clipboard-Import
1343 for ( SCROW nRow
= nRow1
; nRow
<= nRow2
; nRow
++ )
1345 const ScStyleSheet
* pStyle
=
1346 rColumn
.pAttrArray
->GetPattern( nRow
)->GetStyleSheet();
1347 const ScPatternAttr
* pPattern
= pAttrArray
->GetPattern( nRow
);
1348 ScPatternAttr
* pNewPattern
= new ScPatternAttr( *pPattern
);
1349 pNewPattern
->SetStyleSheet( (ScStyleSheet
*)pStyle
);
1350 rColumn
.pAttrArray
->SetPattern( nRow
, pNewPattern
, TRUE
);
1355 pAttrArray
->CopyArea( nRow1
, nRow2
, 0, *rColumn
.pAttrArray
);
1359 if ((nFlags
& IDF_CONTENTS
) != 0)
1362 SCSIZE nBlockCount
= 0;
1363 SCSIZE nStartIndex
= 0, nEndIndex
= 0;
1364 for (i
= 0; i
< nCount
; i
++)
1365 if ((pItems
[i
].nRow
>= nRow1
) && (pItems
[i
].nRow
<= nRow2
))
1375 rColumn
.Resize( rColumn
.GetCellCount() + nBlockCount
);
1376 ScAddress
aDestPos( rColumn
.nCol
, 0, rColumn
.nTab
);
1377 for (i
= nStartIndex
; i
<= nEndIndex
; i
++)
1379 aDestPos
.SetRow( pItems
[i
].nRow
);
1380 ScBaseCell
* pNew
= bAsLink
?
1381 CreateRefCell( rColumn
.pDocument
, aDestPos
, i
, nFlags
) :
1382 CloneCell( i
, nFlags
, *rColumn
.pDocument
, aDestPos
);
1386 // Special case to allow removing of cell instances. A
1387 // string cell with empty content is used to indicate an
1389 if (pNew
->GetCellType() == CELLTYPE_STRING
)
1392 static_cast<ScStringCell
*>(pNew
)->GetString(aStr
);
1393 if (aStr
.Len() == 0)
1394 // A string cell with empty string. Delete the cell itself.
1395 rColumn
.Delete(pItems
[i
].nRow
);
1397 // non-empty string cell
1398 rColumn
.Insert(pItems
[i
].nRow
, pNew
);
1401 rColumn
.Insert(pItems
[i
].nRow
, pNew
);
1409 void ScColumn::UndoToColumn(SCROW nRow1
, SCROW nRow2
, USHORT nFlags
, BOOL bMarked
,
1410 ScColumn
& rColumn
, const ScMarkData
* pMarkData
)
1413 CopyToColumn( 0, nRow1
-1, IDF_FORMULA
, FALSE
, rColumn
);
1415 CopyToColumn( nRow1
, nRow2
, nFlags
, bMarked
, rColumn
, pMarkData
); //! bMarked ????
1418 CopyToColumn( nRow2
+1, MAXROW
, IDF_FORMULA
, FALSE
, rColumn
);
1422 void ScColumn::CopyUpdated( const ScColumn
& rPosCol
, ScColumn
& rDestCol
) const
1424 ScDocument
& rDestDoc
= *rDestCol
.pDocument
;
1425 ScAddress
aOwnPos( nCol
, 0, nTab
);
1426 ScAddress
aDestPos( rDestCol
.nCol
, 0, rDestCol
.nTab
);
1428 SCSIZE nPosCount
= rPosCol
.nCount
;
1429 for (SCSIZE nPosIndex
= 0; nPosIndex
< nPosCount
; nPosIndex
++)
1431 aOwnPos
.SetRow( rPosCol
.pItems
[nPosIndex
].nRow
);
1432 aDestPos
.SetRow( aOwnPos
.Row() );
1434 if ( Search( aDestPos
.Row(), nThisIndex
) )
1436 ScBaseCell
* pNew
= pItems
[nThisIndex
].pCell
->CloneWithNote( aOwnPos
, rDestDoc
, aDestPos
);
1437 rDestCol
.Insert( aDestPos
.Row(), pNew
);
1442 // CopyToColumn( 0,MAXROW, IDF_FORMULA, FALSE, rDestCol, NULL, FALSE );
1446 void ScColumn::CopyScenarioFrom( const ScColumn
& rSrcCol
)
1448 // Dies ist die Szenario-Tabelle, die Daten werden hineinkopiert
1450 ScAttrIterator
aAttrIter( pAttrArray
, 0, MAXROW
);
1452 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1455 if ( ((ScMergeFlagAttr
&)pPattern
->GetItem( ATTR_MERGE_FLAG
)).IsScenario() )
1457 DeleteArea( nStart
, nEnd
, IDF_CONTENTS
);
1458 ((ScColumn
&)rSrcCol
).
1459 CopyToColumn( nStart
, nEnd
, IDF_CONTENTS
, FALSE
, *this );
1461 // UpdateUsed nicht noetig, schon in TestCopyScenario passiert
1463 SCsTAB nDz
= nTab
- rSrcCol
.nTab
;
1464 UpdateReference(URM_COPY
, nCol
, nStart
, nTab
,
1470 //! CopyToColumn "const" machen !!!
1472 pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1477 void ScColumn::CopyScenarioTo( ScColumn
& rDestCol
) const
1479 // Dies ist die Szenario-Tabelle, die Daten werden in die andere kopiert
1481 ScAttrIterator
aAttrIter( pAttrArray
, 0, MAXROW
);
1483 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1486 if ( ((ScMergeFlagAttr
&)pPattern
->GetItem( ATTR_MERGE_FLAG
)).IsScenario() )
1488 rDestCol
.DeleteArea( nStart
, nEnd
, IDF_CONTENTS
);
1490 CopyToColumn( nStart
, nEnd
, IDF_CONTENTS
, FALSE
, rDestCol
);
1492 // UpdateUsed nicht noetig, schon in TestCopyScenario passiert
1494 SCsTAB nDz
= rDestCol
.nTab
- nTab
;
1495 rDestCol
.UpdateReference(URM_COPY
, rDestCol
.nCol
, nStart
, rDestCol
.nTab
,
1496 rDestCol
.nCol
, nEnd
, rDestCol
.nTab
,
1498 rDestCol
.UpdateCompile();
1501 //! CopyToColumn "const" machen !!!
1503 pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1508 BOOL
ScColumn::TestCopyScenarioTo( const ScColumn
& rDestCol
) const
1511 ScAttrIterator
aAttrIter( pAttrArray
, 0, MAXROW
);
1512 SCROW nStart
= 0, nEnd
= 0;
1513 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1514 while (pPattern
&& bOk
)
1516 if ( ((ScMergeFlagAttr
&)pPattern
->GetItem( ATTR_MERGE_FLAG
)).IsScenario() )
1517 if ( rDestCol
.pAttrArray
->HasAttrib( nStart
, nEnd
, HASATTR_PROTECTED
) )
1520 pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1526 void ScColumn::MarkScenarioIn( ScMarkData
& rDestMark
) const
1528 ScRange
aRange( nCol
, 0, nTab
);
1530 ScAttrIterator
aAttrIter( pAttrArray
, 0, MAXROW
);
1532 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1535 if ( ((ScMergeFlagAttr
&)pPattern
->GetItem( ATTR_MERGE_FLAG
)).IsScenario() )
1537 aRange
.aStart
.SetRow( nStart
);
1538 aRange
.aEnd
.SetRow( nEnd
);
1539 rDestMark
.SetMultiMarkArea( aRange
, TRUE
);
1542 pPattern
= aAttrIter
.Next( nStart
, nEnd
);
1547 void ScColumn::SwapCol(ScColumn
& rCol
)
1551 nTemp
= rCol
.nCount
;
1552 rCol
.nCount
= nCount
;
1555 nTemp
= rCol
.nLimit
;
1556 rCol
.nLimit
= nLimit
;
1559 ColEntry
* pTempItems
= rCol
.pItems
;
1560 rCol
.pItems
= pItems
;
1561 pItems
= pTempItems
;
1563 ScAttrArray
* pTempAttr
= rCol
.pAttrArray
;
1564 rCol
.pAttrArray
= pAttrArray
;
1565 pAttrArray
= pTempAttr
;
1567 // #38415# AttrArray muss richtige Spaltennummer haben
1568 pAttrArray
->SetCol(nCol
);
1569 rCol
.pAttrArray
->SetCol(rCol
.nCol
);
1573 for (i
= 0; i
< nCount
; i
++)
1575 ScFormulaCell
* pCell
= (ScFormulaCell
*) pItems
[i
].pCell
;
1576 if( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1577 pCell
->aPos
.SetCol(nCol
);
1580 for (i
= 0; i
< rCol
.nCount
; i
++)
1582 ScFormulaCell
* pCell
= (ScFormulaCell
*) rCol
.pItems
[i
].pCell
;
1583 if( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1584 pCell
->aPos
.SetCol(rCol
.nCol
);
1589 void ScColumn::MoveTo(SCROW nStartRow
, SCROW nEndRow
, ScColumn
& rCol
)
1591 pAttrArray
->MoveTo(nStartRow
, nEndRow
, *rCol
.pAttrArray
);
1595 ::std::vector
<SCROW
> aRows
;
1596 bool bConsecutive
= true;
1598 Search( nStartRow
, i
); // i points to start row or position thereafter
1599 SCSIZE nStartPos
= i
;
1600 for ( ; i
< nCount
&& pItems
[i
].nRow
<= nEndRow
; ++i
)
1602 SCROW nRow
= pItems
[i
].nRow
;
1603 aRows
.push_back( nRow
);
1604 rCol
.Insert( nRow
, pItems
[i
].pCell
);
1605 if (nRow
!= pItems
[i
].nRow
)
1606 { // Listener inserted
1607 bConsecutive
= false;
1611 SCSIZE nStopPos
= i
;
1612 if (nStartPos
< nStopPos
)
1614 // Create list of ranges of cell entry positions
1615 typedef ::std::pair
<SCSIZE
,SCSIZE
> PosPair
;
1616 typedef ::std::vector
<PosPair
> EntryPosPairs
;
1617 EntryPosPairs aEntries
;
1619 aEntries
.push_back( PosPair(nStartPos
, nStopPos
));
1624 for (::std::vector
<SCROW
>::const_iterator
it( aRows
.begin());
1625 it
!= aRows
.end() && nStopPos
< nCount
; ++it
,
1628 if (!bFirst
&& *it
!= pItems
[nStopPos
].nRow
)
1630 aEntries
.push_back( PosPair(nStartPos
, nStopPos
));
1633 if (bFirst
&& Search( *it
, nStartPos
))
1636 nStopPos
= nStartPos
;
1639 if (!bFirst
&& nStartPos
< nStopPos
)
1640 aEntries
.push_back( PosPair(nStartPos
, nStopPos
));
1642 // Broadcast changes
1643 ScAddress
aAdr( nCol
, 0, nTab
);
1644 ScHint
aHint( SC_HINT_DYING
, aAdr
, NULL
); // areas only
1645 ScAddress
& rAddress
= aHint
.GetAddress();
1646 ScNoteCell
* pNoteCell
= new ScNoteCell
; // Dummy like in DeleteRange
1648 // #121990# must iterate backwards, because indexes of following cells become invalid
1649 for (EntryPosPairs::reverse_iterator
it( aEntries
.rbegin());
1650 it
!= aEntries
.rend(); ++it
)
1652 nStartPos
= (*it
).first
;
1653 nStopPos
= (*it
).second
;
1654 for (i
=nStartPos
; i
<nStopPos
; ++i
)
1655 pItems
[i
].pCell
= pNoteCell
;
1656 for (i
=nStartPos
; i
<nStopPos
; ++i
)
1658 rAddress
.SetRow( pItems
[i
].nRow
);
1659 pDocument
->AreaBroadcast( aHint
);
1661 nCount
-= nStopPos
- nStartPos
;
1662 memmove( &pItems
[nStartPos
], &pItems
[nStopPos
],
1663 (nCount
- nStartPos
) * sizeof(ColEntry
) );
1666 pItems
[nCount
].nRow
= 0;
1667 pItems
[nCount
].pCell
= NULL
;
1673 void ScColumn::UpdateReference( UpdateRefMode eUpdateRefMode
, SCCOL nCol1
, SCROW nRow1
, SCTAB nTab1
,
1674 SCCOL nCol2
, SCROW nRow2
, SCTAB nTab2
, SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
,
1675 ScDocument
* pUndoDoc
)
1679 ScRange
aRange( ScAddress( nCol1
, nRow1
, nTab1
),
1680 ScAddress( nCol2
, nRow2
, nTab2
) );
1681 if ( eUpdateRefMode
== URM_COPY
&& nRow1
== nRow2
)
1682 { // z.B. eine einzelne Zelle aus dem Clipboard eingefuegt
1684 if ( Search( nRow1
, nIndex
) )
1686 ScFormulaCell
* pCell
= (ScFormulaCell
*) pItems
[nIndex
].pCell
;
1687 if( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1688 pCell
->UpdateReference( eUpdateRefMode
, aRange
, nDx
, nDy
, nDz
, pUndoDoc
);
1693 // #90279# For performance reasons two loop bodies instead of
1694 // testing for update mode in each iteration.
1695 // Anyways, this is still a bottleneck on large arrays with few
1697 if ( eUpdateRefMode
== URM_COPY
)
1701 for ( ; i
< nCount
; i
++ )
1703 SCROW nRow
= pItems
[i
].nRow
;
1706 ScBaseCell
* pCell
= pItems
[i
].pCell
;
1707 if( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1709 ((ScFormulaCell
*)pCell
)->UpdateReference( eUpdateRefMode
, aRange
, nDx
, nDy
, nDz
, pUndoDoc
);
1710 if ( nRow
!= pItems
[i
].nRow
)
1711 Search( nRow
, i
); // Listener removed/inserted?
1718 for ( ; i
< nCount
; i
++ )
1720 ScBaseCell
* pCell
= pItems
[i
].pCell
;
1721 if( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1723 SCROW nRow
= pItems
[i
].nRow
;
1724 // When deleting rows on several sheets, the formula's position may be updated with the first call,
1725 // so the undo position must be passed from here.
1726 ScAddress
aUndoPos( nCol
, nRow
, nTab
);
1727 ((ScFormulaCell
*)pCell
)->UpdateReference( eUpdateRefMode
, aRange
, nDx
, nDy
, nDz
, pUndoDoc
, &aUndoPos
);
1728 if ( nRow
!= pItems
[i
].nRow
)
1729 Search( nRow
, i
); // Listener removed/inserted?
1738 void ScColumn::UpdateTranspose( const ScRange
& rSource
, const ScAddress
& rDest
,
1739 ScDocument
* pUndoDoc
)
1742 for (SCSIZE i
=0; i
<nCount
; i
++)
1744 ScBaseCell
* pCell
= pItems
[i
].pCell
;
1745 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
1747 SCROW nRow
= pItems
[i
].nRow
;
1748 ((ScFormulaCell
*)pCell
)->UpdateTranspose( rSource
, rDest
, pUndoDoc
);
1749 if ( nRow
!= pItems
[i
].nRow
)
1750 Search( nRow
, i
); // Listener geloescht/eingefuegt?
1756 void ScColumn::UpdateGrow( const ScRange
& rArea
, SCCOL nGrowX
, SCROW nGrowY
)
1759 for (SCSIZE i
=0; i
<nCount
; i
++)
1761 ScBaseCell
* pCell
= pItems
[i
].pCell
;
1762 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
1764 SCROW nRow
= pItems
[i
].nRow
;
1765 ((ScFormulaCell
*)pCell
)->UpdateGrow( rArea
, nGrowX
, nGrowY
);
1766 if ( nRow
!= pItems
[i
].nRow
)
1767 Search( nRow
, i
); // Listener geloescht/eingefuegt?
1773 void ScColumn::UpdateInsertTab( SCTAB nTable
)
1776 pAttrArray
->SetTab(++nTab
);
1778 UpdateInsertTabOnlyCells( nTable
);
1782 void ScColumn::UpdateInsertTabOnlyCells( SCTAB nTable
)
1785 for (SCSIZE i
= 0; i
< nCount
; i
++)
1787 ScFormulaCell
* pCell
= (ScFormulaCell
*) pItems
[i
].pCell
;
1788 if( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1790 SCROW nRow
= pItems
[i
].nRow
;
1791 pCell
->UpdateInsertTab(nTable
);
1792 if ( nRow
!= pItems
[i
].nRow
)
1793 Search( nRow
, i
); // Listener geloescht/eingefuegt?
1799 void ScColumn::UpdateInsertTabAbs(SCTAB nTable
)
1802 for (SCSIZE i
= 0; i
< nCount
; i
++)
1804 ScFormulaCell
* pCell
= (ScFormulaCell
*) pItems
[i
].pCell
;
1805 if( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1807 SCROW nRow
= pItems
[i
].nRow
;
1808 pCell
->UpdateInsertTabAbs(nTable
);
1809 if ( nRow
!= pItems
[i
].nRow
)
1810 Search( nRow
, i
); // Listener geloescht/eingefuegt?
1816 void ScColumn::UpdateDeleteTab( SCTAB nTable
, BOOL bIsMove
, ScColumn
* pRefUndo
)
1819 pAttrArray
->SetTab(--nTab
);
1822 for (SCSIZE i
= 0; i
< nCount
; i
++)
1823 if ( pItems
[i
].pCell
->GetCellType() == CELLTYPE_FORMULA
)
1825 SCROW nRow
= pItems
[i
].nRow
;
1826 ScFormulaCell
* pOld
= (ScFormulaCell
*)pItems
[i
].pCell
;
1828 /* Do not copy cell note to the undo document. Undo will copy
1829 back the formula cell while keeping the original note. */
1830 ScBaseCell
* pSave
= pRefUndo
? pOld
->CloneWithoutNote( *pDocument
) : 0;
1832 BOOL bChanged
= pOld
->UpdateDeleteTab(nTable
, bIsMove
);
1833 if ( nRow
!= pItems
[i
].nRow
)
1834 Search( nRow
, i
); // Listener geloescht/eingefuegt?
1839 pRefUndo
->Insert( nRow
, pSave
);
1847 void ScColumn::UpdateMoveTab( SCTAB nOldPos
, SCTAB nNewPos
, SCTAB nTabNo
)
1850 pAttrArray
->SetTab( nTabNo
);
1852 for (SCSIZE i
= 0; i
< nCount
; i
++)
1854 ScFormulaCell
* pCell
= (ScFormulaCell
*) pItems
[i
].pCell
;
1855 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
1857 SCROW nRow
= pItems
[i
].nRow
;
1858 pCell
->UpdateMoveTab( nOldPos
, nNewPos
, nTabNo
);
1859 if ( nRow
!= pItems
[i
].nRow
)
1860 Search( nRow
, i
); // Listener geloescht/eingefuegt?
1866 void ScColumn::UpdateCompile( BOOL bForceIfNameInUse
)
1869 for (SCSIZE i
= 0; i
< nCount
; i
++)
1871 ScFormulaCell
* p
= (ScFormulaCell
*) pItems
[i
].pCell
;
1872 if( p
->GetCellType() == CELLTYPE_FORMULA
)
1874 SCROW nRow
= pItems
[i
].nRow
;
1875 p
->UpdateCompile( bForceIfNameInUse
);
1876 if ( nRow
!= pItems
[i
].nRow
)
1877 Search( nRow
, i
); // Listener geloescht/eingefuegt?
1883 void ScColumn::SetTabNo(SCTAB nNewTab
)
1886 pAttrArray
->SetTab( nNewTab
);
1888 for (SCSIZE i
= 0; i
< nCount
; i
++)
1890 ScFormulaCell
* p
= (ScFormulaCell
*) pItems
[i
].pCell
;
1891 if( p
->GetCellType() == CELLTYPE_FORMULA
)
1892 p
->aPos
.SetTab( nNewTab
);
1897 BOOL
ScColumn::IsRangeNameInUse(SCROW nRow1
, SCROW nRow2
, USHORT nIndex
) const
1899 BOOL bInUse
= FALSE
;
1901 for (SCSIZE i
= 0; !bInUse
&& (i
< nCount
); i
++)
1902 if ((pItems
[i
].nRow
>= nRow1
) &&
1903 (pItems
[i
].nRow
<= nRow2
) &&
1904 (pItems
[i
].pCell
->GetCellType() == CELLTYPE_FORMULA
))
1905 bInUse
= ((ScFormulaCell
*)pItems
[i
].pCell
)->IsRangeNameInUse(nIndex
);
1909 void ScColumn::FindRangeNamesInUse(SCROW nRow1
, SCROW nRow2
, std::set
<USHORT
>& rIndexes
) const
1912 for (SCSIZE i
= 0; i
< nCount
; i
++)
1913 if ((pItems
[i
].nRow
>= nRow1
) &&
1914 (pItems
[i
].nRow
<= nRow2
) &&
1915 (pItems
[i
].pCell
->GetCellType() == CELLTYPE_FORMULA
))
1916 ((ScFormulaCell
*)pItems
[i
].pCell
)->FindRangeNamesInUse(rIndexes
);
1919 void ScColumn::ReplaceRangeNamesInUse(SCROW nRow1
, SCROW nRow2
,
1920 const ScIndexMap
& rMap
)
1923 for (SCSIZE i
= 0; i
< nCount
; i
++)
1925 if ((pItems
[i
].nRow
>= nRow1
) &&
1926 (pItems
[i
].nRow
<= nRow2
) &&
1927 (pItems
[i
].pCell
->GetCellType() == CELLTYPE_FORMULA
))
1929 SCROW nRow
= pItems
[i
].nRow
;
1930 ((ScFormulaCell
*)pItems
[i
].pCell
)->ReplaceRangeNamesInUse( rMap
);
1931 if ( nRow
!= pItems
[i
].nRow
)
1932 Search( nRow
, i
); // Listener geloescht/eingefuegt?
1937 void ScColumn::ReplaceRangeNamesInUse(SCROW nRow1
, SCROW nRow2
,
1938 const ScRangeData::IndexMap
& rMap
)
1941 for (SCSIZE i
= 0; i
< nCount
; i
++)
1943 if ((pItems
[i
].nRow
>= nRow1
) &&
1944 (pItems
[i
].nRow
<= nRow2
) &&
1945 (pItems
[i
].pCell
->GetCellType() == CELLTYPE_FORMULA
))
1947 SCROW nRow
= pItems
[i
].nRow
;
1948 ((ScFormulaCell
*)pItems
[i
].pCell
)->ReplaceRangeNamesInUse( rMap
);
1949 if ( nRow
!= pItems
[i
].nRow
)
1950 Search( nRow
, i
); // Listener geloescht/eingefuegt?
1955 void ScColumn::SetDirtyVar()
1957 for (SCSIZE i
=0; i
<nCount
; i
++)
1959 ScFormulaCell
* p
= (ScFormulaCell
*) pItems
[i
].pCell
;
1960 if( p
->GetCellType() == CELLTYPE_FORMULA
)
1966 void ScColumn::SetDirty()
1968 // wird nur dokumentweit verwendet, kein FormulaTrack
1969 BOOL bOldAutoCalc
= pDocument
->GetAutoCalc();
1970 pDocument
->SetAutoCalc( FALSE
); // Mehrfachberechnungen vermeiden
1971 for (SCSIZE i
=0; i
<nCount
; i
++)
1973 ScFormulaCell
* p
= (ScFormulaCell
*) pItems
[i
].pCell
;
1974 if( p
->GetCellType() == CELLTYPE_FORMULA
)
1977 if ( !pDocument
->IsInFormulaTree( p
) )
1978 pDocument
->PutInFormulaTree( p
);
1981 pDocument
->SetAutoCalc( bOldAutoCalc
);
1985 void ScColumn::SetDirty( const ScRange
& rRange
)
1986 { // broadcastet alles innerhalb eines Range, mit FormulaTrack
1987 if ( !pItems
|| !nCount
)
1989 BOOL bOldAutoCalc
= pDocument
->GetAutoCalc();
1990 pDocument
->SetAutoCalc( FALSE
); // Mehrfachberechnungen vermeiden
1991 SCROW nRow2
= rRange
.aEnd
.Row();
1992 ScAddress
aPos( nCol
, 0, nTab
);
1993 ScHint
aHint( SC_HINT_DATACHANGED
, aPos
, NULL
);
1996 Search( rRange
.aStart
.Row(), nIndex
);
1997 while ( nIndex
< nCount
&& (nRow
= pItems
[nIndex
].nRow
) <= nRow2
)
1999 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
2000 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
2001 ((ScFormulaCell
*)pCell
)->SetDirty();
2004 aHint
.GetAddress().SetRow( nRow
);
2005 aHint
.SetCell( pCell
);
2006 pDocument
->Broadcast( aHint
);
2010 pDocument
->SetAutoCalc( bOldAutoCalc
);
2014 void ScColumn::SetTableOpDirty( const ScRange
& rRange
)
2016 if ( !pItems
|| !nCount
)
2018 BOOL bOldAutoCalc
= pDocument
->GetAutoCalc();
2019 pDocument
->SetAutoCalc( FALSE
); // no multiple recalculation
2020 SCROW nRow2
= rRange
.aEnd
.Row();
2021 ScAddress
aPos( nCol
, 0, nTab
);
2022 ScHint
aHint( SC_HINT_TABLEOPDIRTY
, aPos
, NULL
);
2025 Search( rRange
.aStart
.Row(), nIndex
);
2026 while ( nIndex
< nCount
&& (nRow
= pItems
[nIndex
].nRow
) <= nRow2
)
2028 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
2029 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
2030 ((ScFormulaCell
*)pCell
)->SetTableOpDirty();
2033 aHint
.GetAddress().SetRow( nRow
);
2034 aHint
.SetCell( pCell
);
2035 pDocument
->Broadcast( aHint
);
2039 pDocument
->SetAutoCalc( bOldAutoCalc
);
2043 void ScColumn::SetDirtyAfterLoad()
2045 BOOL bOldAutoCalc
= pDocument
->GetAutoCalc();
2046 pDocument
->SetAutoCalc( FALSE
); // Mehrfachberechnungen vermeiden
2047 for (SCSIZE i
=0; i
<nCount
; i
++)
2049 ScFormulaCell
* p
= (ScFormulaCell
*) pItems
[i
].pCell
;
2051 // Simply set dirty and append to FormulaTree, without broadcasting,
2052 // which is a magnitude faster. This is used to calculate the entire
2053 // document, e.g. when loading alien file formats.
2054 if ( p
->GetCellType() == CELLTYPE_FORMULA
)
2055 p
->SetDirtyAfterLoad();
2057 /* This was used with the binary file format that stored results, where only
2058 * newly compiled and volatile functions and their dependents had to be
2059 * recalculated, which was faster then. Since that was moved to 'binfilter' to
2060 * convert to an XML file this isn't needed anymore, and not used for other
2061 * file formats. Kept for reference in case mechanism needs to be reactivated
2062 * for some file formats, we'd have to introduce a controlling parameter to
2063 * this method here then.
2066 // If the cell was alsready dirty because of CalcAfterLoad,
2067 // FormulaTracking has to take place.
2068 if ( p
->GetCellType() == CELLTYPE_FORMULA
&& p
->GetDirty() )
2072 pDocument
->SetAutoCalc( bOldAutoCalc
);
2076 void ScColumn::SetRelNameDirty()
2078 BOOL bOldAutoCalc
= pDocument
->GetAutoCalc();
2079 pDocument
->SetAutoCalc( FALSE
); // Mehrfachberechnungen vermeiden
2080 for (SCSIZE i
=0; i
<nCount
; i
++)
2082 ScFormulaCell
* p
= (ScFormulaCell
*) pItems
[i
].pCell
;
2083 if( p
->GetCellType() == CELLTYPE_FORMULA
&& p
->HasRelNameReference() )
2086 pDocument
->SetAutoCalc( bOldAutoCalc
);
2090 void ScColumn::CalcAll()
2093 for (SCSIZE i
=0; i
<nCount
; i
++)
2095 ScBaseCell
* pCell
= pItems
[i
].pCell
;
2096 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
2098 #if OSL_DEBUG_LEVEL > 1
2099 // nach F9 ctrl-F9: ueberprueft die Berechnung per FormulaTree
2100 ScFormulaCell
* pFCell
= (ScFormulaCell
*)pCell
;
2101 double nOldVal
, nNewVal
;
2102 nOldVal
= pFCell
->GetValue();
2104 ((ScFormulaCell
*)pCell
)->Interpret();
2105 #if OSL_DEBUG_LEVEL > 1
2106 if ( pFCell
->GetCode()->IsRecalcModeNormal() )
2107 nNewVal
= pFCell
->GetValue();
2109 nNewVal
= nOldVal
; // random(), jetzt() etc.
2110 DBG_ASSERT( nOldVal
==nNewVal
, "CalcAll: nOldVal != nNewVal" );
2117 void ScColumn::CompileAll()
2120 for (SCSIZE i
= 0; i
< nCount
; i
++)
2122 ScBaseCell
* pCell
= pItems
[i
].pCell
;
2123 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
2125 SCROW nRow
= pItems
[i
].nRow
;
2126 // fuer unbedingtes kompilieren
2127 // bCompile=TRUE und pCode->nError=0
2128 ((ScFormulaCell
*)pCell
)->GetCode()->SetCodeError( 0 );
2129 ((ScFormulaCell
*)pCell
)->SetCompile( TRUE
);
2130 ((ScFormulaCell
*)pCell
)->CompileTokenArray();
2131 if ( nRow
!= pItems
[i
].nRow
)
2132 Search( nRow
, i
); // Listener geloescht/eingefuegt?
2138 void ScColumn::CompileXML( ScProgress
& rProgress
)
2141 for (SCSIZE i
= 0; i
< nCount
; i
++)
2143 ScBaseCell
* pCell
= pItems
[i
].pCell
;
2144 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
2146 SCROW nRow
= pItems
[i
].nRow
;
2147 ((ScFormulaCell
*)pCell
)->CompileXML( rProgress
);
2148 if ( nRow
!= pItems
[i
].nRow
)
2149 Search( nRow
, i
); // Listener geloescht/eingefuegt?
2155 void ScColumn::CalcAfterLoad()
2158 for (SCSIZE i
= 0; i
< nCount
; i
++)
2160 ScBaseCell
* pCell
= pItems
[i
].pCell
;
2161 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
2162 ((ScFormulaCell
*)pCell
)->CalcAfterLoad();
2167 bool ScColumn::MarkUsedExternalReferences()
2169 bool bAllMarked
= false;
2172 for (SCSIZE i
= 0; i
< nCount
&& !bAllMarked
; ++i
)
2174 ScBaseCell
* pCell
= pItems
[i
].pCell
;
2175 if ( pCell
->GetCellType() == CELLTYPE_FORMULA
)
2176 bAllMarked
= ((ScFormulaCell
*)pCell
)->MarkUsedExternalReferences();
2183 void ScColumn::ResetChanged( SCROW nStartRow
, SCROW nEndRow
)
2188 Search(nStartRow
,nIndex
);
2189 while (nIndex
<nCount
&& pItems
[nIndex
].nRow
<= nEndRow
)
2191 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
2192 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
2193 ((ScFormulaCell
*)pCell
)->ResetChanged();
2200 BOOL
ScColumn::HasEditCells(SCROW nStartRow
, SCROW nEndRow
, SCROW
& rFirst
) const
2202 // used in GetOptimalHeight - ambiguous script type counts as edit cell
2206 Search(nStartRow
,nIndex
);
2207 while ( (nIndex
< nCount
) ? ((nRow
=pItems
[nIndex
].nRow
) <= nEndRow
) : FALSE
)
2209 ScBaseCell
* pCell
= pItems
[nIndex
].pCell
;
2210 CellType eCellType
= pCell
->GetCellType();
2211 if ( eCellType
== CELLTYPE_EDIT
||
2212 IsAmbiguousScriptNonZero( pDocument
->GetScriptType(nCol
, nRow
, nTab
, pCell
) ) ||
2213 ((eCellType
== CELLTYPE_FORMULA
) && ((ScFormulaCell
*)pCell
)->IsMultilineResult()) )
2225 SCsROW
ScColumn::SearchStyle( SCsROW nRow
, const ScStyleSheet
* pSearchStyle
,
2226 BOOL bUp
, BOOL bInSelection
, const ScMarkData
& rMark
)
2230 if (rMark
.IsMultiMarked())
2231 return pAttrArray
->SearchStyle( nRow
, pSearchStyle
, bUp
,
2232 (ScMarkArray
*) rMark
.GetArray()+nCol
); //! const
2237 return pAttrArray
->SearchStyle( nRow
, pSearchStyle
, bUp
, NULL
);
2241 BOOL
ScColumn::SearchStyleRange( SCsROW
& rRow
, SCsROW
& rEndRow
, const ScStyleSheet
* pSearchStyle
,
2242 BOOL bUp
, BOOL bInSelection
, const ScMarkData
& rMark
)
2246 if (rMark
.IsMultiMarked())
2247 return pAttrArray
->SearchStyleRange( rRow
, rEndRow
, pSearchStyle
, bUp
,
2248 (ScMarkArray
*) rMark
.GetArray()+nCol
); //! const
2253 return pAttrArray
->SearchStyleRange( rRow
, rEndRow
, pSearchStyle
, bUp
, NULL
);