update dev300-m57
[ooovba.git] / sc / source / core / data / column.cxx
blob0fdc706cbc7d05768a8f2ea721eaafd47a1c4bcd
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 ---------------------------------------------------------------
38 #include <map>
40 #include <svtools/poolcach.hxx>
41 #include <svtools/zforlist.hxx>
42 #include <svx/scripttypeitem.hxx>
43 #include <string.h>
45 #include "scitems.hxx"
46 #include "column.hxx"
47 #include "cell.hxx"
48 #include "document.hxx"
49 #include "docpool.hxx"
50 #include "attarray.hxx"
51 #include "patattr.hxx"
52 #include "compiler.hxx"
53 #include "brdcst.hxx"
54 #include "markdata.hxx"
55 #include "detfunc.hxx" // for Notes in Sort/Swap
56 #include "postit.hxx"
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 &&
70 nScript != 0 );
73 // -----------------------------------------------------------------------------------------
76 ScColumn::ScColumn() :
77 nCol( 0 ),
78 nCount( 0 ),
79 nLimit( 0 ),
80 pItems( NULL ),
81 pAttrArray( NULL ),
82 pDocument( NULL )
87 ScColumn::~ScColumn()
89 FreeAll();
90 if (pAttrArray) delete pAttrArray;
94 void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc)
96 nCol = nNewCol;
97 nTab = nNewTab;
98 pDocument = 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
112 if ( !pItems )
113 return 0;
114 if ( nRow1 == nRow2 )
116 SCSIZE nIndex;
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 );
127 return 0;
129 else
131 ScAddress aOrg( ScAddress::INITIALIZE_INVALID );
132 BOOL bOpen = FALSE;
133 USHORT nEdges = 0;
134 SCSIZE nIndex;
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 );
143 if ( nEdges )
145 if ( nEdges & 8 )
146 bOpen = TRUE; // obere Kante oeffnet, weitersehen
147 else if ( !bOpen )
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
156 if ( nEdges & 2 )
157 bOpen = FALSE; // untere Kante schliesst
160 nIndex++;
162 if ( bOpen )
163 nEdges |= 32; // es geht noch weiter
164 return nEdges;
169 BOOL ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark) const
171 if ( rMark.IsMultiMarked() )
173 BOOL bFound = FALSE;
175 ScAddress aOrg( ScAddress::INITIALIZE_INVALID );
176 ScAddress aCurOrg( ScAddress::INITIALIZE_INVALID );
177 SCROW nTop, nBottom;
178 ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
179 while ( !bFound && aMarkIter.Next( nTop, nBottom ) )
181 BOOL bOpen = FALSE;
182 USHORT nEdges;
183 SCSIZE nIndex;
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 );
192 if ( nEdges )
194 if ( nEdges & 8 )
195 bOpen = TRUE; // obere Kante oeffnet, weitersehen
196 else if ( !bOpen )
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?
203 if ( nEdges & 2 )
204 bOpen = FALSE; // untere Kante schliesst
206 if ( bFound )
207 { // alles selektiert?
208 if ( aCurOrg != aOrg )
209 { // neue Matrix zu pruefen?
210 aCurOrg = aOrg;
211 ScFormulaCell* pFCell;
212 if ( ((ScFormulaCell*)pCell)->GetMatrixFlag()
213 == MM_REFERENCE )
214 pFCell = (ScFormulaCell*) pDocument->GetCell( aOrg );
215 else
216 pFCell = (ScFormulaCell*)pCell;
217 SCCOL nC;
218 SCROW nR;
219 pFCell->GetMatColsRows( nC, nR );
220 ScRange aRange( aOrg, ScAddress(
221 aOrg.Col() + nC - 1, aOrg.Row() + nR - 1,
222 aOrg.Tab() ) );
223 if ( rMark.IsAllMarked( aRange ) )
224 bFound = FALSE;
226 else
227 bFound = FALSE; // war schon
231 nIndex++;
233 if ( bOpen )
234 return TRUE;
236 return bFound;
238 else
239 return FALSE;
243 //UNUSED2009-05 BOOL ScColumn::HasLines( SCROW nRow1, SCROW nRow2, Rectangle& rSizes,
244 //UNUSED2009-05 BOOL bLeft, BOOL bRight ) const
245 //UNUSED2009-05 {
246 //UNUSED2009-05 return pAttrArray->HasLines( nRow1, nRow2, rSizes, bLeft, bRight );
247 //UNUSED2009-05 }
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
258 BOOL bFound = FALSE;
260 SCROW nTop;
261 SCROW nBottom;
263 if (rMark.IsMultiMarked())
265 ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
266 while (aMarkIter.Next( nTop, nBottom ) && !bFound)
268 if (pAttrArray->HasAttrib( nTop, nBottom, nMask ))
269 bFound = TRUE;
273 return bFound;
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
287 SCROW nTop;
288 SCROW nBottom;
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,
310 ScLineFlags& rFlags,
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;
353 nMaxCount = rnCount;
357 return pMaxPattern;
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)
371 return 0;
373 return nFormat;
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 )
385 SCROW nTop = 0;
386 SCROW nBottom = 0;
387 BOOL bFound = FALSE;
389 if ( rMark.IsMultiMarked() )
391 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
392 while (aMarkIter.Next( nTop, nBottom ))
394 pAttrArray->ApplyCacheArea( nTop, nBottom, pCache, pDataArray );
395 bFound = TRUE;
399 if (!bFound)
400 return -1;
401 else if (nTop==0 && nBottom==MAXROW)
402 return 0;
403 else
404 return nBottom;
408 void ScColumn::ChangeSelectionIndent( BOOL bIncrement, const ScMarkData& rMark )
410 SCROW nTop;
411 SCROW nBottom;
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 )
424 SCROW nTop;
425 SCROW nBottom;
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 )
438 SCROW nTop;
439 SCROW nBottom;
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++ )
486 SCROW nRow1, nRow2;
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 ) )
492 nRow = nRow2;
493 else
495 SCROW nNewRow1 = Max( nRow1, nRow );
496 SCROW nNewRow2 = Min( nRow2, nEndRow );
497 pAttrArray->ApplyCacheArea( nNewRow1, nNewRow2, &aCache );
498 nRow = nNewRow2;
504 void ScColumn::ApplyStyle( SCROW nRow, const ScStyleSheet& rStyle )
506 const ScPatternAttr* pPattern = pAttrArray->GetPattern(nRow);
507 ScPatternAttr* pNewPattern = new ScPatternAttr(*pPattern);
508 if (pNewPattern)
510 pNewPattern->SetStyleSheet((ScStyleSheet*)&rStyle);
511 pAttrArray->SetPattern(nRow, pNewPattern, TRUE);
512 delete pNewPattern;
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)
525 SCROW nTop;
526 SCROW nBottom;
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 )
541 return;
543 SCROW nTop;
544 SCROW nBottom;
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
563 rFound = FALSE;
564 if (!rMark.IsMultiMarked())
566 DBG_ERROR("ScColumn::GetSelectionStyle ohne Selektion");
567 return NULL;
570 BOOL bEqual = TRUE;
572 const ScStyleSheet* pStyle = NULL;
573 const ScStyleSheet* pNewStyle;
575 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
576 SCROW nTop;
577 SCROW nBottom;
578 while (bEqual && aMarkIter.Next( nTop, nBottom ))
580 ScAttrIterator aAttrIter( pAttrArray, nTop, nBottom );
581 SCROW nRow;
582 SCROW nDummy;
583 const ScPatternAttr* pPattern;
584 while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
586 pNewStyle = pPattern->GetStyleSheet();
587 rFound = TRUE;
588 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
589 bEqual = FALSE; // unterschiedliche
590 pStyle = pNewStyle;
594 return bEqual ? pStyle : NULL;
598 const ScStyleSheet* ScColumn::GetAreaStyle( BOOL& rFound, SCROW nRow1, SCROW nRow2 ) const
600 rFound = FALSE;
602 BOOL bEqual = TRUE;
604 const ScStyleSheet* pStyle = NULL;
605 const ScStyleSheet* pNewStyle;
607 ScAttrIterator aAttrIter( pAttrArray, nRow1, nRow2 );
608 SCROW nRow;
609 SCROW nDummy;
610 const ScPatternAttr* pPattern;
611 while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
613 pNewStyle = pPattern->GetStyleSheet();
614 rFound = TRUE;
615 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
616 bEqual = FALSE; // unterschiedliche
617 pStyle = pNewStyle;
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 );
679 else
680 pDocPool->Remove( *pNewPattern ); // ausser Spesen nichts gewesen
682 delete pTemp;
684 // alte Version mit SfxItemPoolCache:
685 #if 0
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 );
698 #endif
701 #ifdef _MSC_VER
702 #pragma optimize ( "", off )
703 #endif
706 BOOL ScColumn::Search( SCROW nRow, SCSIZE& nIndex ) const
708 if ( !pItems || !nCount )
710 nIndex = 0;
711 return FALSE;
713 SCROW nMinRow = pItems[0].nRow;
714 if ( nRow <= nMinRow )
716 nIndex = 0;
717 return nRow == nMinRow;
719 SCROW nMaxRow = pItems[nCount-1].nRow;
720 if ( nRow >= nMaxRow )
722 if ( nRow == nMaxRow )
724 nIndex = nCount - 1;
725 return TRUE;
727 else
729 nIndex = nCount;
730 return FALSE;
734 long nOldLo, nOldHi;
735 long nLo = nOldLo = 0;
736 long nHi = nOldHi = Min(static_cast<long>(nCount)-1, static_cast<long>(nRow) );
737 long i = 0;
738 BOOL bFound = FALSE;
739 // quite continuous distribution? => interpolating search
740 BOOL bInterpol = (static_cast<SCSIZE>(nMaxRow - nMinRow) < nCount * 2);
741 SCROW nR;
743 while ( !bFound && nLo <= nHi )
745 if ( !bInterpol || nHi - nLo < 3 )
746 i = (nLo+nHi) / 2; // no effort, no division by zero
747 else
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 )
753 { // oops ...
754 i = (nLo+nHi) / 2;
755 bInterpol = FALSE;
758 nR = pItems[i].nRow;
759 if ( nR < nRow )
761 nLo = i+1;
762 if ( bInterpol )
764 if ( nLo <= nOldLo )
765 bInterpol = FALSE;
766 else
767 nOldLo = nLo;
770 else
772 if ( nR > nRow )
774 nHi = i-1;
775 if ( bInterpol )
777 if ( nHi >= nOldHi )
778 bInterpol = FALSE;
779 else
780 nOldHi = nHi;
783 else
784 bFound = TRUE;
787 if (bFound)
788 nIndex = static_cast<SCSIZE>(i);
789 else
790 nIndex = static_cast<SCSIZE>(nLo); // rear index
791 return bFound;
794 #ifdef _MSC_VER
795 #pragma optimize ( "", on )
796 #endif
799 ScBaseCell* ScColumn::GetCell( SCROW nRow ) const
801 SCSIZE nIndex;
802 if (Search(nRow, nIndex))
803 return pItems[nIndex].pCell;
804 return NULL;
808 void ScColumn::Resize( SCSIZE nSize )
810 if (nSize > sal::static_int_cast<SCSIZE>(MAXROWCOUNT))
811 nSize = MAXROWCOUNT;
812 if (nSize < nCount)
813 nSize = nCount;
815 ColEntry* pNewItems;
816 if (nSize)
818 SCSIZE nNewSize = nSize + COLUMN_DELTA - 1;
819 nNewSize -= nNewSize % COLUMN_DELTA;
820 nLimit = nNewSize;
821 pNewItems = new ColEntry[nLimit];
823 else
825 nLimit = 0;
826 pNewItems = NULL;
828 if (pItems)
830 if (pNewItems)
831 memmove( pNewItems, pItems, nCount * sizeof(ColEntry) );
832 delete[] pItems;
834 pItems = pNewItems;
837 // SwapRow zum Sortieren
839 namespace {
841 /** Moves broadcaster from old cell to new cell if exists, otherwise creates a new note cell. */
842 void lclTakeBroadcaster( ScBaseCell*& rpCell, SvtBroadcaster* pBC )
844 if( pBC )
846 if( rpCell )
847 rpCell->TakeBroadcaster( pBC );
848 else
849 rpCell = new ScNoteCell( pBC );
853 } // namespace
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;
870 SCSIZE nIndex1;
871 if ( Search( nRow1, nIndex1 ) )
872 pCell1 = pItems[nIndex1].pCell;
874 ScBaseCell* pCell2 = 0;
875 SCSIZE nIndex2;
876 if ( Search( nRow2, nIndex2 ) )
877 pCell2 = pItems[nIndex2].pCell;
879 // no cells found, nothing to do
880 if ( !pCell1 && !pCell2 )
881 return ;
883 // swap variables if first cell is empty, to save some code below
884 if ( !pCell1 )
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();
908 if ( pCell2 )
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 );
919 if (bBroadcast)
921 ScHint aHint1( SC_HINT_DATACHANGED, aPos1, pCell2 );
922 pDocument->Broadcast( aHint1 );
923 ScHint aHint2( SC_HINT_DATACHANGED, aPos2, pCell1 );
924 pDocument->Broadcast( aHint2 );
927 else
929 ScNoteCell* pDummyCell = pBC1 ? new ScNoteCell( pBC1 ) : 0;
930 if ( pDummyCell )
932 // insert dummy note cell (without note) containing old broadcaster
933 pItems[nIndex1].pCell = pDummyCell;
935 else
937 // remove ColEntry at old position
938 --nCount;
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 );
946 if (bBroadcast)
947 pDocument->Broadcast( ScHint( SC_HINT_DATACHANGED, aPos1, pDummyCell ) );
950 return;
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)) )
958 return;
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
968 BOOL bEqual = TRUE;
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() )
977 bEqual = FALSE;
978 break;
982 // do not swap formula cells with equal formulas, but swap notes
983 if (bEqual)
985 ScPostIt* pNote1 = pCell1->ReleaseNote();
986 pCell1->TakeNote( pCell2->ReleaseNote() );
987 pCell2->TakeNote( pNote1 );
988 return;
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;
1005 if ( pCell2 )
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). */
1019 if ( !pNew1 )
1020 Delete( nRow1 ); // deletes pCell1
1021 else
1022 Insert( nRow1, pNew1 ); // deletes pCell1, inserts pNew1
1024 if ( pCell2 && !pNew2 )
1025 Delete( nRow2 ); // deletes pCell2
1026 else if ( pNew2 )
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)
1032 if (bBroadcast)
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;
1045 SCSIZE nIndex1;
1046 if ( Search( nRow, nIndex1 ) )
1047 pCell1 = pItems[nIndex1].pCell;
1049 ScBaseCell* pCell2 = 0;
1050 SCSIZE nIndex2;
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)
1055 if( !pCell1 )
1057 if( pCell2 )
1058 rCol.SwapCell( nRow, *this );
1059 return;
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;
1067 if ( pCell2 )
1069 // Tauschen
1070 pItems[nIndex1].pCell = pCell2;
1071 rCol.pItems[nIndex2].pCell = pCell1;
1072 // Referenzen aktualisieren
1073 SCsCOL dx = rCol.nCol - nCol;
1074 if ( pFmlaCell1 )
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);
1081 if ( pFmlaCell2 )
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);
1089 else
1091 // Loeschen
1092 --nCount;
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;
1098 if ( pFmlaCell1 )
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);
1105 // Einfuegen
1106 rCol.Insert(nRow, pCell1);
1111 BOOL ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
1113 if (!IsEmpty())
1115 BOOL bTest = TRUE;
1116 if (pItems)
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
1128 return bTest;
1130 else
1131 return TRUE;
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 ) );
1142 else
1143 return pAttrArray->TestInsertRow( nSize );
1145 #if 0
1146 //! rausgeschobene Attribute bei Undo beruecksichtigen
1148 if ( nSize > static_cast<SCSIZE>(MAXROW) )
1149 return FALSE;
1151 SCSIZE nVis = nCount;
1152 while ( nVis && pItems[nVis-1].pCell->IsBlank() )
1153 --nVis;
1155 if ( nVis )
1156 return ( pItems[nVis-1].nRow <= MAXROW-nSize );
1157 else
1158 return TRUE;
1159 #endif
1163 void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
1165 pAttrArray->InsertRow( nStartRow, nSize );
1167 //! Search
1169 if ( !pItems || !nCount )
1170 return;
1172 SCSIZE i;
1173 Search( nStartRow, i );
1174 if ( i >= nCount )
1175 return ;
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) /
1187 (nCount - i)) > 1);
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 )
1210 nNewCount = i;
1211 bCountChanged = TRUE;
1215 else
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 )
1227 nNewCount = i;
1228 bCountChanged = TRUE;
1229 aRange.aEnd.SetRow( MAXROW );
1232 if ( !bCountChanged )
1233 aRange.aEnd.SetRow( pItems[nCount-1].nRow );
1234 pDocument->AreaBroadcastInRange( aRange, aHint );
1237 if (bCountChanged)
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;
1247 nCount = nNewCount;
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();
1254 if (pBC)
1256 MoveListeners( *pBC, pDelRows[i] - nSize );
1257 pCell->DeleteBroadcaster();
1258 pCell->Delete();
1262 delete pDelRows;
1263 delete ppDelCells;
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 );
1275 SCSIZE i;
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))
1281 if (!nBlockCount)
1282 nStartIndex = i;
1283 nEndIndex = i;
1284 ++nBlockCount;
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();
1297 if (nBlockCount)
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 )
1317 if (bMarked)
1319 SCROW nStart, nEnd;
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 );
1331 else
1333 DBG_ERROR("CopyToColumn: bMarked, aber keine Markierung");
1335 return;
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 );
1351 delete pNewPattern;
1354 else
1355 pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray);
1359 if ((nFlags & IDF_CONTENTS) != 0)
1361 SCSIZE i;
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))
1367 if (!nBlockCount)
1368 nStartIndex = i;
1369 nEndIndex = i;
1370 ++nBlockCount;
1373 if (nBlockCount)
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 );
1384 if (pNew)
1386 // Special case to allow removing of cell instances. A
1387 // string cell with empty content is used to indicate an
1388 // empty cell.
1389 if (pNew->GetCellType() == CELLTYPE_STRING)
1391 String aStr;
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);
1396 else
1397 // non-empty string cell
1398 rColumn.Insert(pItems[i].nRow, pNew);
1400 else
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 )
1412 if (nRow1 > 0)
1413 CopyToColumn( 0, nRow1-1, IDF_FORMULA, FALSE, rColumn );
1415 CopyToColumn( nRow1, nRow2, nFlags, bMarked, rColumn, pMarkData ); //! bMarked ????
1417 if (nRow2 < MAXROW)
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() );
1433 SCSIZE nThisIndex;
1434 if ( Search( aDestPos.Row(), nThisIndex ) )
1436 ScBaseCell* pNew = pItems[nThisIndex].pCell->CloneWithNote( aOwnPos, rDestDoc, aDestPos );
1437 rDestCol.Insert( aDestPos.Row(), pNew );
1441 // Dummy:
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 );
1451 SCROW nStart, nEnd;
1452 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1453 while (pPattern)
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,
1465 nCol, nEnd, nTab,
1466 0, 0, nDz, NULL);
1467 UpdateCompile();
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 );
1482 SCROW nStart, nEnd;
1483 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1484 while (pPattern)
1486 if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1488 rDestCol.DeleteArea( nStart, nEnd, IDF_CONTENTS );
1489 ((ScColumn*)this)->
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,
1497 0, 0, nDz, NULL);
1498 rDestCol.UpdateCompile();
1501 //! CopyToColumn "const" machen !!!
1503 pPattern = aAttrIter.Next( nStart, nEnd );
1508 BOOL ScColumn::TestCopyScenarioTo( const ScColumn& rDestCol ) const
1510 BOOL bOk = TRUE;
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 ) )
1518 bOk = FALSE;
1520 pPattern = aAttrIter.Next( nStart, nEnd );
1522 return bOk;
1526 void ScColumn::MarkScenarioIn( ScMarkData& rDestMark ) const
1528 ScRange aRange( nCol, 0, nTab );
1530 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1531 SCROW nStart, nEnd;
1532 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1533 while (pPattern)
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)
1549 SCSIZE nTemp;
1551 nTemp = rCol.nCount;
1552 rCol.nCount = nCount;
1553 nCount = nTemp;
1555 nTemp = rCol.nLimit;
1556 rCol.nLimit = nLimit;
1557 nLimit = nTemp;
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);
1571 SCSIZE i;
1572 if (pItems)
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);
1579 if (rCol.pItems)
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);
1593 if (pItems)
1595 ::std::vector<SCROW> aRows;
1596 bool bConsecutive = true;
1597 SCSIZE i;
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;
1608 Search( nRow, i);
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;
1618 if (bConsecutive)
1619 aEntries.push_back( PosPair(nStartPos, nStopPos));
1620 else
1622 bool bFirst = true;
1623 nStopPos = 0;
1624 for (::std::vector<SCROW>::const_iterator it( aRows.begin());
1625 it != aRows.end() && nStopPos < nCount; ++it,
1626 ++nStopPos)
1628 if (!bFirst && *it != pItems[nStopPos].nRow)
1630 aEntries.push_back( PosPair(nStartPos, nStopPos));
1631 bFirst = true;
1633 if (bFirst && Search( *it, nStartPos))
1635 bFirst = false;
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) );
1665 delete pNoteCell;
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 )
1677 if (pItems)
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
1683 SCSIZE nIndex;
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 );
1691 else
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
1696 // formulas cells.
1697 if ( eUpdateRefMode == URM_COPY )
1699 SCSIZE i;
1700 Search( nRow1, i );
1701 for ( ; i < nCount; i++ )
1703 SCROW nRow = pItems[i].nRow;
1704 if ( nRow > nRow2 )
1705 break;
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?
1715 else
1717 SCSIZE i = 0;
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 )
1741 if (pItems)
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 )
1758 if (pItems)
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)
1775 if (nTab >= nTable)
1776 pAttrArray->SetTab(++nTab);
1777 if( pItems )
1778 UpdateInsertTabOnlyCells( nTable );
1782 void ScColumn::UpdateInsertTabOnlyCells( SCTAB nTable)
1784 if (pItems)
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)
1801 if (pItems)
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 )
1818 if (nTab > nTable)
1819 pAttrArray->SetTab(--nTab);
1821 if (pItems)
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?
1836 if (pRefUndo)
1838 if (bChanged)
1839 pRefUndo->Insert( nRow, pSave );
1840 else if(pSave)
1841 pSave->Delete();
1847 void ScColumn::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo )
1849 nTab = nTabNo;
1850 pAttrArray->SetTab( nTabNo );
1851 if (pItems)
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 )
1868 if (pItems)
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)
1885 nTab = nNewTab;
1886 pAttrArray->SetTab( nNewTab );
1887 if (pItems)
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;
1900 if (pItems)
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);
1906 return bInUse;
1909 void ScColumn::FindRangeNamesInUse(SCROW nRow1, SCROW nRow2, std::set<USHORT>& rIndexes) const
1911 if (pItems)
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 )
1922 if (pItems)
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 )
1940 if (pItems)
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 )
1961 p->SetDirtyVar();
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 )
1976 p->SetDirtyVar();
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 )
1988 return ;
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 );
1994 SCROW nRow;
1995 SCSIZE nIndex;
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();
2002 else
2004 aHint.GetAddress().SetRow( nRow );
2005 aHint.SetCell( pCell );
2006 pDocument->Broadcast( aHint );
2008 nIndex++;
2010 pDocument->SetAutoCalc( bOldAutoCalc );
2014 void ScColumn::SetTableOpDirty( const ScRange& rRange )
2016 if ( !pItems || !nCount )
2017 return ;
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 );
2023 SCROW nRow;
2024 SCSIZE nIndex;
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();
2031 else
2033 aHint.GetAddress().SetRow( nRow );
2034 aHint.SetCell( pCell );
2035 pDocument->Broadcast( aHint );
2037 nIndex++;
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;
2050 #if 1
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();
2056 #else
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() )
2069 p->SetDirty();
2070 #endif
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() )
2084 p->SetDirty();
2086 pDocument->SetAutoCalc( bOldAutoCalc );
2090 void ScColumn::CalcAll()
2092 if (pItems)
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();
2103 #endif
2104 ((ScFormulaCell*)pCell)->Interpret();
2105 #if OSL_DEBUG_LEVEL > 1
2106 if ( pFCell->GetCode()->IsRecalcModeNormal() )
2107 nNewVal = pFCell->GetValue();
2108 else
2109 nNewVal = nOldVal; // random(), jetzt() etc.
2110 DBG_ASSERT( nOldVal==nNewVal, "CalcAll: nOldVal != nNewVal" );
2111 #endif
2117 void ScColumn::CompileAll()
2119 if (pItems)
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 )
2140 if (pItems)
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()
2157 if (pItems)
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;
2170 if (pItems)
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();
2179 return bAllMarked;
2183 void ScColumn::ResetChanged( SCROW nStartRow, SCROW nEndRow )
2185 if (pItems)
2187 SCSIZE nIndex;
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();
2194 ++nIndex;
2200 BOOL ScColumn::HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst) const
2202 // used in GetOptimalHeight - ambiguous script type counts as edit cell
2204 SCROW nRow = 0;
2205 SCSIZE nIndex;
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()) )
2215 rFirst = nRow;
2216 return TRUE;
2218 ++nIndex;
2221 return FALSE;
2225 SCsROW ScColumn::SearchStyle( SCsROW nRow, const ScStyleSheet* pSearchStyle,
2226 BOOL bUp, BOOL bInSelection, const ScMarkData& rMark )
2228 if (bInSelection)
2230 if (rMark.IsMultiMarked())
2231 return pAttrArray->SearchStyle( nRow, pSearchStyle, bUp,
2232 (ScMarkArray*) rMark.GetArray()+nCol ); //! const
2233 else
2234 return -1;
2236 else
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 )
2244 if (bInSelection)
2246 if (rMark.IsMultiMarked())
2247 return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp,
2248 (ScMarkArray*) rMark.GetArray()+nCol ); //! const
2249 else
2250 return FALSE;
2252 else
2253 return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp, NULL );