xref: /AOO41X/main/sc/source/core/data/column.cxx (revision 707fc0d4d52eb4f69d89a98ffec6918ca5de6326)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 
27 
28 
29 // INCLUDE ---------------------------------------------------------------
30 
31 #include <map>
32 
33 #include <svl/poolcach.hxx>
34 #include <svl/zforlist.hxx>
35 #include <editeng/scripttypeitem.hxx>
36 #include <string.h>
37 
38 #include "scitems.hxx"
39 #include "column.hxx"
40 #include "cell.hxx"
41 #include "document.hxx"
42 #include "docpool.hxx"
43 #include "attarray.hxx"
44 #include "patattr.hxx"
45 #include "compiler.hxx"
46 #include "brdcst.hxx"
47 #include "markdata.hxx"
48 #include "detfunc.hxx"          // for Notes in Sort/Swap
49 #include "postit.hxx"
50 
51 //#pragma optimize ( "", off )
52 //  nur Search ohne Optimierung!
53 
54 // STATIC DATA -----------------------------------------------------------
55 using namespace formula;
56 
57 inline sal_Bool IsAmbiguousScriptNonZero( sal_uInt8 nScript )
58 {
59     //! move to a header file
60     return ( nScript != SCRIPTTYPE_LATIN &&
61              nScript != SCRIPTTYPE_ASIAN &&
62              nScript != SCRIPTTYPE_COMPLEX &&
63              nScript != 0 );
64 }
65 
66 // -----------------------------------------------------------------------------------------
67 
68 
69 ScColumn::ScColumn() :
70     nCol( 0 ),
71     nCount( 0 ),
72     nLimit( 0 ),
73     pItems( NULL ),
74     pAttrArray( NULL ),
75     pDocument( NULL )
76 {
77 }
78 
79 
80 ScColumn::~ScColumn()
81 {
82     FreeAll();
83     if (pAttrArray) delete pAttrArray;
84 }
85 
86 
87 void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc)
88 {
89     nCol = nNewCol;
90     nTab = nNewTab;
91     pDocument = pDoc;
92     pAttrArray = new ScAttrArray( nCol, nTab, pDocument );
93 }
94 
95 
96 SCsROW ScColumn::GetNextUnprotected( SCROW nRow, sal_Bool bUp ) const
97 {
98     return pAttrArray->GetNextUnprotected(nRow, bUp);
99 }
100 
101 
102 sal_uInt16 ScColumn::GetBlockMatrixEdges( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
103 {
104     // nix:0, mitte:1, unten:2, links:4, oben:8, rechts:16, offen:32
105     if ( !pItems )
106         return 0;
107     if ( nRow1 == nRow2 )
108     {
109         SCSIZE nIndex;
110         if ( Search( nRow1, nIndex ) )
111         {
112             ScBaseCell* pCell = pItems[nIndex].pCell;
113             if ( pCell->GetCellType() == CELLTYPE_FORMULA
114                 && ((ScFormulaCell*)pCell)->GetMatrixFlag() )
115             {
116                 ScAddress aOrg( ScAddress::INITIALIZE_INVALID );
117                 return ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg );
118             }
119         }
120         return 0;
121     }
122     else
123     {
124         ScAddress aOrg( ScAddress::INITIALIZE_INVALID );
125         sal_Bool bOpen = sal_False;
126         sal_uInt16 nEdges = 0;
127         SCSIZE nIndex;
128         Search( nRow1, nIndex );
129         while ( nIndex < nCount && pItems[nIndex].nRow <= nRow2 )
130         {
131             ScBaseCell* pCell = pItems[nIndex].pCell;
132             if ( pCell->GetCellType() == CELLTYPE_FORMULA
133                 && ((ScFormulaCell*)pCell)->GetMatrixFlag() )
134             {
135                 nEdges = ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg );
136                 if ( nEdges )
137                 {
138                     if ( nEdges & 8 )
139                         bOpen = sal_True;   // obere Kante oeffnet, weitersehen
140                     else if ( !bOpen )
141                         return nEdges | 32; // es gibt was, was nicht geoeffnet wurde
142                     else if ( nEdges & 1 )
143                         return nEdges;  // mittendrin
144                     // (nMask & 16 und  (4 und nicht 16)) oder
145                     // (nMask & 4  und (16 und nicht 4))
146                     if ( ((nMask & 16) && (nEdges & 4)  && !(nEdges & 16))
147                         || ((nMask & 4)  && (nEdges & 16) && !(nEdges & 4)) )
148                         return nEdges;  // nur linke/rechte Kante
149                     if ( nEdges & 2 )
150                         bOpen = sal_False;  // untere Kante schliesst
151                 }
152             }
153             nIndex++;
154         }
155         if ( bOpen )
156             nEdges |= 32;           // es geht noch weiter
157         return nEdges;
158     }
159 }
160 
161 
162 sal_Bool ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark) const
163 {
164     if ( rMark.IsMultiMarked() )
165     {
166         sal_Bool bFound = sal_False;
167 
168         ScAddress aOrg( ScAddress::INITIALIZE_INVALID );
169         ScAddress aCurOrg( ScAddress::INITIALIZE_INVALID );
170         SCROW nTop, nBottom;
171         ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
172         while ( !bFound && aMarkIter.Next( nTop, nBottom ) )
173         {
174             sal_Bool bOpen = sal_False;
175             sal_uInt16 nEdges;
176             SCSIZE nIndex;
177             Search( nTop, nIndex );
178             while ( !bFound && nIndex < nCount && pItems[nIndex].nRow <= nBottom )
179             {
180                 ScBaseCell* pCell = pItems[nIndex].pCell;
181                 if ( pCell->GetCellType() == CELLTYPE_FORMULA
182                     && ((ScFormulaCell*)pCell)->GetMatrixFlag() )
183                 {
184                     nEdges = ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg );
185                     if ( nEdges )
186                     {
187                         if ( nEdges & 8 )
188                             bOpen = sal_True;   // obere Kante oeffnet, weitersehen
189                         else if ( !bOpen )
190                             return sal_True;    // es gibt was, was nicht geoeffnet wurde
191                         else if ( nEdges & 1 )
192                             bFound = sal_True;  // mittendrin, alles selektiert?
193                         // (4 und nicht 16) oder (16 und nicht 4)
194                         if ( (((nEdges & 4) | 16) ^ ((nEdges & 16) | 4)) )
195                             bFound = sal_True;  // nur linke/rechte Kante, alles selektiert?
196                         if ( nEdges & 2 )
197                             bOpen = sal_False;  // untere Kante schliesst
198 
199                         if ( bFound )
200                         {   // alles selektiert?
201                             if ( aCurOrg != aOrg )
202                             {   // neue Matrix zu pruefen?
203                                 aCurOrg = aOrg;
204                                 ScFormulaCell* pFCell;
205                                 if ( ((ScFormulaCell*)pCell)->GetMatrixFlag()
206                                         == MM_REFERENCE )
207                                     pFCell = (ScFormulaCell*) pDocument->GetCell( aOrg );
208                                 else
209                                     pFCell = (ScFormulaCell*)pCell;
210                                 SCCOL nC;
211                                 SCROW nR;
212                                 pFCell->GetMatColsRows( nC, nR );
213                                 ScRange aRange( aOrg, ScAddress(
214                                     aOrg.Col() + nC - 1, aOrg.Row() + nR - 1,
215                                     aOrg.Tab() ) );
216                                 if ( rMark.IsAllMarked( aRange ) )
217                                     bFound = sal_False;
218                             }
219                             else
220                                 bFound = sal_False;     // war schon
221                         }
222                     }
223                 }
224                 nIndex++;
225             }
226             if ( bOpen )
227                 return sal_True;
228         }
229         return bFound;
230     }
231     else
232         return sal_False;
233 }
234 
235 
236 //UNUSED2009-05 sal_Bool ScColumn::HasLines( SCROW nRow1, SCROW nRow2, Rectangle& rSizes,
237 //UNUSED2009-05                             sal_Bool bLeft, sal_Bool bRight ) const
238 //UNUSED2009-05 {
239 //UNUSED2009-05     return pAttrArray->HasLines( nRow1, nRow2, rSizes, bLeft, bRight );
240 //UNUSED2009-05 }
241 
242 
243 bool ScColumn::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
244 {
245     return pAttrArray->HasAttrib( nRow1, nRow2, nMask );
246 }
247 
248 
249 sal_Bool ScColumn::HasAttribSelection( const ScMarkData& rMark, sal_uInt16 nMask ) const
250 {
251     sal_Bool bFound = sal_False;
252 
253     SCROW nTop;
254     SCROW nBottom;
255 
256     if (rMark.IsMultiMarked())
257     {
258         ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
259         while (aMarkIter.Next( nTop, nBottom ) && !bFound)
260         {
261             if (pAttrArray->HasAttrib( nTop, nBottom, nMask ))
262                 bFound = sal_True;
263         }
264     }
265 
266     return bFound;
267 }
268 
269 
270 sal_Bool ScColumn::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
271                             SCCOL& rPaintCol, SCROW& rPaintRow,
272                             sal_Bool bRefresh, sal_Bool bAttrs )
273 {
274     return pAttrArray->ExtendMerge( nThisCol, nStartRow, nEndRow, rPaintCol, rPaintRow, bRefresh, bAttrs );
275 }
276 
277 
278 void ScColumn::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, sal_Bool bDeep ) const
279 {
280     SCROW nTop;
281     SCROW nBottom;
282 
283     if ( rMark.IsMultiMarked() )
284     {
285         const ScMarkArray* pArray = rMark.GetArray() + nCol;
286         if ( pArray->HasMarks() )
287         {
288             ScMarkArrayIter aMarkIter( pArray );
289             while (aMarkIter.Next( nTop, nBottom ))
290                 pAttrArray->MergePatternArea( nTop, nBottom, rState, bDeep );
291         }
292     }
293 }
294 
295 
296 void ScColumn::MergePatternArea( ScMergePatternState& rState, SCROW nRow1, SCROW nRow2, sal_Bool bDeep ) const
297 {
298     pAttrArray->MergePatternArea( nRow1, nRow2, rState, bDeep );
299 }
300 
301 
302 void ScColumn::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
303                             ScLineFlags& rFlags,
304                             SCROW nStartRow, SCROW nEndRow, sal_Bool bLeft, SCCOL nDistRight ) const
305 {
306     pAttrArray->MergeBlockFrame( pLineOuter, pLineInner, rFlags, nStartRow, nEndRow, bLeft, nDistRight );
307 }
308 
309 
310 void ScColumn::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
311                             SCROW nStartRow, SCROW nEndRow, sal_Bool bLeft, SCCOL nDistRight )
312 {
313     pAttrArray->ApplyBlockFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight );
314 }
315 
316 
317 const ScPatternAttr* ScColumn::GetPattern( SCROW nRow ) const
318 {
319     return pAttrArray->GetPattern( nRow );
320 }
321 
322 
323 const SfxPoolItem* ScColumn::GetAttr( SCROW nRow, sal_uInt16 nWhich ) const
324 {
325     return &pAttrArray->GetPattern( nRow )->GetItemSet().Get(nWhich);
326 }
327 
328 
329 const ScPatternAttr* ScColumn::GetMostUsedPattern( SCROW nStartRow, SCROW nEndRow ) const
330 {
331     ::std::map< const ScPatternAttr*, size_t > aAttrMap;
332     const ScPatternAttr* pMaxPattern = 0;
333     size_t nMaxCount = 0;
334 
335     ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
336     const ScPatternAttr* pPattern;
337     SCROW nAttrRow1 = 0, nAttrRow2 = 0;
338 
339     while( (pPattern = aAttrIter.Next( nAttrRow1, nAttrRow2 )) != 0 )
340     {
341         size_t& rnCount = aAttrMap[ pPattern ];
342         rnCount += (nAttrRow2 - nAttrRow1 + 1);
343         if( rnCount > nMaxCount )
344         {
345             pMaxPattern = pPattern;
346             nMaxCount = rnCount;
347         }
348     }
349 
350     return pMaxPattern;
351 }
352 
353 
354 sal_uLong ScColumn::GetNumberFormat( SCROW nRow ) const
355 {
356     return pAttrArray->GetPattern( nRow )->GetNumberFormat( pDocument->GetFormatTable() );
357 }
358 
359 
360 SCsROW ScColumn::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark )
361 {
362     SCROW nTop = 0;
363     SCROW nBottom = 0;
364     sal_Bool bFound = sal_False;
365 
366     if ( rMark.IsMultiMarked() )
367     {
368         ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
369         while (aMarkIter.Next( nTop, nBottom ))
370         {
371             pAttrArray->ApplyCacheArea( nTop, nBottom, pCache );
372             bFound = sal_True;
373         }
374     }
375 
376     if (!bFound)
377         return -1;
378     else if (nTop==0 && nBottom==MAXROW)
379         return 0;
380     else
381         return nBottom;
382 }
383 
384 
385 void ScColumn::ChangeSelectionIndent( sal_Bool bIncrement, const ScMarkData& rMark )
386 {
387     SCROW nTop;
388     SCROW nBottom;
389 
390     if ( pAttrArray && rMark.IsMultiMarked() )
391     {
392         ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
393         while (aMarkIter.Next( nTop, nBottom ))
394             pAttrArray->ChangeIndent(nTop, nBottom, bIncrement);
395     }
396 }
397 
398 
399 void ScColumn::ClearSelectionItems( const sal_uInt16* pWhich,const ScMarkData& rMark )
400 {
401     SCROW nTop;
402     SCROW nBottom;
403 
404     if ( pAttrArray && rMark.IsMultiMarked() )
405     {
406         ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
407         while (aMarkIter.Next( nTop, nBottom ))
408             pAttrArray->ClearItems(nTop, nBottom, pWhich);
409     }
410 }
411 
412 
413 void ScColumn::DeleteSelection( sal_uInt16 nDelFlag, const ScMarkData& rMark )
414 {
415     SCROW nTop;
416     SCROW nBottom;
417 
418     if ( rMark.IsMultiMarked() )
419     {
420         ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
421         while (aMarkIter.Next( nTop, nBottom ))
422             DeleteArea(nTop, nBottom, nDelFlag);
423     }
424 }
425 
426 
427 void ScColumn::ApplyPattern( SCROW nRow, const ScPatternAttr& rPatAttr )
428 {
429     const SfxItemSet* pSet = &rPatAttr.GetItemSet();
430     SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
431 
432     const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
433 
434     //  sal_True = alten Eintrag behalten
435 
436     ScPatternAttr* pNewPattern = (ScPatternAttr*) &aCache.ApplyTo( *pPattern, sal_True );
437     ScDocumentPool::CheckRef( *pPattern );
438     ScDocumentPool::CheckRef( *pNewPattern );
439 
440     if (pNewPattern != pPattern)
441       pAttrArray->SetPattern( nRow, pNewPattern );
442 }
443 
444 
445 void ScColumn::ApplyPatternArea( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr& rPatAttr )
446 {
447     const SfxItemSet* pSet = &rPatAttr.GetItemSet();
448     SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
449     pAttrArray->ApplyCacheArea( nStartRow, nEndRow, &aCache );
450 }
451 
452 
453 void ScColumn::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
454         const ScPatternAttr& rPattern, short nNewType )
455 {
456     const SfxItemSet* pSet = &rPattern.GetItemSet();
457     SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
458     SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
459     SCROW nEndRow = rRange.aEnd.Row();
460     for ( SCROW nRow = rRange.aStart.Row(); nRow <= nEndRow; nRow++ )
461     {
462         SCROW nRow1, nRow2;
463         const ScPatternAttr* pPattern = pAttrArray->GetPatternRange(
464             nRow1, nRow2, nRow );
465         sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter );
466         short nOldType = pFormatter->GetType( nFormat );
467         if ( nOldType == nNewType || pFormatter->IsCompatible( nOldType, nNewType ) )
468             nRow = nRow2;
469         else
470         {
471             SCROW nNewRow1 = Max( nRow1, nRow );
472             SCROW nNewRow2 = Min( nRow2, nEndRow );
473             pAttrArray->ApplyCacheArea( nNewRow1, nNewRow2, &aCache );
474             nRow = nNewRow2;
475         }
476     }
477 }
478 
479 
480 void ScColumn::ApplyStyle( SCROW nRow, const ScStyleSheet& rStyle )
481 {
482     const ScPatternAttr* pPattern = pAttrArray->GetPattern(nRow);
483     ScPatternAttr* pNewPattern = new ScPatternAttr(*pPattern);
484     if (pNewPattern)
485     {
486         pNewPattern->SetStyleSheet((ScStyleSheet*)&rStyle);
487         pAttrArray->SetPattern(nRow, pNewPattern, sal_True);
488         delete pNewPattern;
489     }
490 }
491 
492 
493 void ScColumn::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleSheet& rStyle )
494 {
495     pAttrArray->ApplyStyleArea(nStartRow, nEndRow, (ScStyleSheet*)&rStyle);
496 }
497 
498 
499 void ScColumn::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
500 {
501     SCROW nTop;
502     SCROW nBottom;
503 
504     if ( rMark.IsMultiMarked() )
505     {
506         ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
507         while (aMarkIter.Next( nTop, nBottom ))
508             pAttrArray->ApplyStyleArea(nTop, nBottom, (ScStyleSheet*)&rStyle);
509     }
510 }
511 
512 
513 void ScColumn::ApplySelectionLineStyle( const ScMarkData& rMark,
514                                     const SvxBorderLine* pLine, sal_Bool bColorOnly )
515 {
516     if ( bColorOnly && !pLine )
517         return;
518 
519     SCROW nTop;
520     SCROW nBottom;
521 
522     if (rMark.IsMultiMarked())
523     {
524         ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
525         while (aMarkIter.Next( nTop, nBottom ))
526             pAttrArray->ApplyLineStyleArea(nTop, nBottom, pLine, bColorOnly );
527     }
528 }
529 
530 
531 const ScStyleSheet* ScColumn::GetStyle( SCROW nRow ) const
532 {
533     return pAttrArray->GetPattern( nRow )->GetStyleSheet();
534 }
535 
536 
537 const ScStyleSheet* ScColumn::GetSelectionStyle( const ScMarkData& rMark, sal_Bool& rFound ) const
538 {
539     rFound = sal_False;
540     if (!rMark.IsMultiMarked())
541     {
542         DBG_ERROR("ScColumn::GetSelectionStyle ohne Selektion");
543         return NULL;
544     }
545 
546     sal_Bool bEqual = sal_True;
547 
548     const ScStyleSheet* pStyle = NULL;
549     const ScStyleSheet* pNewStyle;
550 
551     ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
552     SCROW nTop;
553     SCROW nBottom;
554     while (bEqual && aMarkIter.Next( nTop, nBottom ))
555     {
556         ScAttrIterator aAttrIter( pAttrArray, nTop, nBottom );
557         SCROW nRow;
558         SCROW nDummy;
559         const ScPatternAttr* pPattern;
560         while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
561         {
562             pNewStyle = pPattern->GetStyleSheet();
563             rFound = sal_True;
564             if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
565                 bEqual = sal_False;                                             // unterschiedliche
566             pStyle = pNewStyle;
567         }
568     }
569 
570     return bEqual ? pStyle : NULL;
571 }
572 
573 
574 const ScStyleSheet* ScColumn::GetAreaStyle( sal_Bool& rFound, SCROW nRow1, SCROW nRow2 ) const
575 {
576     rFound = sal_False;
577 
578     sal_Bool bEqual = sal_True;
579 
580     const ScStyleSheet* pStyle = NULL;
581     const ScStyleSheet* pNewStyle;
582 
583     ScAttrIterator aAttrIter( pAttrArray, nRow1, nRow2 );
584     SCROW nRow;
585     SCROW nDummy;
586     const ScPatternAttr* pPattern;
587     while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
588     {
589         pNewStyle = pPattern->GetStyleSheet();
590         rFound = sal_True;
591         if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
592             bEqual = sal_False;                                             // unterschiedliche
593         pStyle = pNewStyle;
594     }
595 
596     return bEqual ? pStyle : NULL;
597 }
598 
599 void ScColumn::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
600 {
601     pAttrArray->FindStyleSheet( pStyleSheet, rUsedRows, bReset );
602 }
603 
604 sal_Bool ScColumn::IsStyleSheetUsed( const ScStyleSheet& rStyle, sal_Bool bGatherAllStyles ) const
605 {
606     return pAttrArray->IsStyleSheetUsed( rStyle, bGatherAllStyles );
607 }
608 
609 
610 sal_Bool ScColumn::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
611 {
612     return pAttrArray->ApplyFlags( nStartRow, nEndRow, nFlags );
613 }
614 
615 
616 sal_Bool ScColumn::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
617 {
618     return pAttrArray->RemoveFlags( nStartRow, nEndRow, nFlags );
619 }
620 
621 
622 void ScColumn::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
623 {
624     pAttrArray->ClearItems( nStartRow, nEndRow, pWhich );
625 }
626 
627 
628 void ScColumn::SetPattern( SCROW nRow, const ScPatternAttr& rPatAttr, sal_Bool bPutToPool )
629 {
630     pAttrArray->SetPattern( nRow, &rPatAttr, bPutToPool );
631 }
632 
633 
634 void ScColumn::SetPatternArea( SCROW nStartRow, SCROW nEndRow,
635                                 const ScPatternAttr& rPatAttr, sal_Bool bPutToPool )
636 {
637     pAttrArray->SetPatternArea( nStartRow, nEndRow, &rPatAttr, bPutToPool );
638 }
639 
640 
641 void ScColumn::ApplyAttr( SCROW nRow, const SfxPoolItem& rAttr )
642 {
643     //  um nur ein neues SetItem zu erzeugen, brauchen wir keinen SfxItemPoolCache.
644     //! Achtung: der SfxItemPoolCache scheint zuviele Refs fuer das neue SetItem zu erzeugen ??
645 
646     ScDocumentPool* pDocPool = pDocument->GetPool();
647 
648     const ScPatternAttr* pOldPattern = pAttrArray->GetPattern( nRow );
649     ScPatternAttr* pTemp = new ScPatternAttr(*pOldPattern);
650     pTemp->GetItemSet().Put(rAttr);
651     const ScPatternAttr* pNewPattern = (const ScPatternAttr*) &pDocPool->Put( *pTemp );
652 
653     if ( pNewPattern != pOldPattern )
654         pAttrArray->SetPattern( nRow, pNewPattern );
655     else
656         pDocPool->Remove( *pNewPattern );       // ausser Spesen nichts gewesen
657 
658     delete pTemp;
659 
660         // alte Version mit SfxItemPoolCache:
661 #if 0
662     SfxItemPoolCache aCache( pDocument->GetPool(), &rAttr );
663 
664     const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
665 
666     //  sal_True = alten Eintrag behalten
667 
668     ScPatternAttr* pNewPattern = (ScPatternAttr*) &aCache.ApplyTo( *pPattern, sal_True );
669     ScDocumentPool::CheckRef( *pPattern );
670     ScDocumentPool::CheckRef( *pNewPattern );
671 
672     if (pNewPattern != pPattern)
673       pAttrArray->SetPattern( nRow, pNewPattern );
674 #endif
675 }
676 
677 #ifdef _MSC_VER
678 #pragma optimize ( "", off )
679 #endif
680 
681 
682 sal_Bool ScColumn::Search( SCROW nRow, SCSIZE& nIndex ) const
683 {
684     if ( !pItems || !nCount )
685     {
686         nIndex = 0;
687         return sal_False;
688     }
689     SCROW nMinRow = pItems[0].nRow;
690     if ( nRow <= nMinRow )
691     {
692         nIndex = 0;
693         return nRow == nMinRow;
694     }
695     SCROW nMaxRow = pItems[nCount-1].nRow;
696     if ( nRow >= nMaxRow )
697     {
698         if ( nRow == nMaxRow )
699         {
700             nIndex = nCount - 1;
701             return sal_True;
702         }
703         else
704         {
705             nIndex = nCount;
706             return sal_False;
707         }
708     }
709 
710     long nOldLo, nOldHi;
711     long    nLo     = nOldLo = 0;
712     long    nHi     = nOldHi = Min(static_cast<long>(nCount)-1, static_cast<long>(nRow) );
713     long    i       = 0;
714     sal_Bool    bFound  = sal_False;
715     // quite continuous distribution? => interpolating search
716     sal_Bool    bInterpol = (static_cast<SCSIZE>(nMaxRow - nMinRow) < nCount * 2);
717     SCROW   nR;
718 
719     while ( !bFound && nLo <= nHi )
720     {
721         if ( !bInterpol || nHi - nLo < 3 )
722             i = (nLo+nHi) / 2;          // no effort, no division by zero
723         else
724         {   // interpolating search
725             long nLoRow = pItems[nLo].nRow;     // no unsigned underflow upon substraction
726             i = nLo + (long)((long)(nRow - nLoRow) * (nHi - nLo)
727                 / (pItems[nHi].nRow - nLoRow));
728             if ( i < 0 || static_cast<SCSIZE>(i) >= nCount )
729             {   // oops ...
730                 i = (nLo+nHi) / 2;
731                 bInterpol = sal_False;
732             }
733         }
734         nR = pItems[i].nRow;
735         if ( nR < nRow )
736         {
737             nLo = i+1;
738             if ( bInterpol )
739             {
740                 if ( nLo <= nOldLo )
741                     bInterpol = sal_False;
742                 else
743                     nOldLo = nLo;
744             }
745         }
746         else
747         {
748             if ( nR > nRow )
749             {
750                 nHi = i-1;
751                 if ( bInterpol )
752                 {
753                     if ( nHi >= nOldHi )
754                         bInterpol = sal_False;
755                     else
756                         nOldHi = nHi;
757                 }
758             }
759             else
760                 bFound = sal_True;
761         }
762     }
763     if (bFound)
764         nIndex = static_cast<SCSIZE>(i);
765     else
766         nIndex = static_cast<SCSIZE>(nLo); // rear index
767     return bFound;
768 }
769 
770 #ifdef _MSC_VER
771 #pragma optimize ( "", on )
772 #endif
773 
774 
775 ScBaseCell* ScColumn::GetCell( SCROW nRow ) const
776 {
777     SCSIZE nIndex;
778     if (Search(nRow, nIndex))
779         return pItems[nIndex].pCell;
780     return NULL;
781 }
782 
783 
784 void ScColumn::Resize( SCSIZE nSize )
785 {
786     if (nSize > sal::static_int_cast<SCSIZE>(MAXROWCOUNT))
787         nSize = MAXROWCOUNT;
788     if (nSize < nCount)
789         nSize = nCount;
790 
791     ColEntry* pNewItems;
792     if (nSize)
793     {
794         SCSIZE nNewSize = nSize + COLUMN_DELTA - 1;
795         nNewSize -= nNewSize % COLUMN_DELTA;
796         nLimit = nNewSize;
797         pNewItems = new ColEntry[nLimit];
798     }
799     else
800     {
801         nLimit = 0;
802         pNewItems = NULL;
803     }
804     if (pItems)
805     {
806         if (pNewItems)
807             memmove( pNewItems, pItems, nCount * sizeof(ColEntry) );
808         delete[] pItems;
809     }
810     pItems = pNewItems;
811 }
812 
813 //  SwapRow zum Sortieren
814 
815 namespace {
816 
817 /** Moves broadcaster from old cell to new cell if exists, otherwise creates a new note cell. */
818 void lclTakeBroadcaster( ScBaseCell*& rpCell, SvtBroadcaster* pBC )
819 {
820     if( pBC )
821     {
822         if( rpCell )
823             rpCell->TakeBroadcaster( pBC );
824         else
825             rpCell = new ScNoteCell( pBC );
826     }
827 }
828 
829 } // namespace
830 
831 void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
832 {
833     /*  Simple swap of cell pointers does not work if broadcasters exist (crash
834         if cell broadcasts directly or indirectly to itself). While swapping
835         the cells, broadcasters have to remain at old positions! */
836 
837     /*  While cloning cells, do not clone notes, but move note pointers to new
838         cells. This prevents creation of new caption drawing objects for every
839         swap operation while sorting. */
840 
841     ScBaseCell* pCell1 = 0;
842     SCSIZE nIndex1;
843     if ( Search( nRow1, nIndex1 ) )
844         pCell1 = pItems[nIndex1].pCell;
845 
846     ScBaseCell* pCell2 = 0;
847     SCSIZE nIndex2;
848     if ( Search( nRow2, nIndex2 ) )
849         pCell2 = pItems[nIndex2].pCell;
850 
851     // no cells found, nothing to do
852     if ( !pCell1 && !pCell2 )
853         return ;
854 
855     // swap variables if first cell is empty, to save some code below
856     if ( !pCell1 )
857     {
858         ::std::swap( nRow1, nRow2 );
859         ::std::swap( nIndex1, nIndex2 );
860         ::std::swap( pCell1, pCell2 );
861     }
862 
863     // from here: first cell (pCell1, nIndex1) exists always
864 
865     ScAddress aPos1( nCol, nRow1, nTab );
866     ScAddress aPos2( nCol, nRow2, nTab );
867 
868     CellType eType1 = pCell1->GetCellType();
869     CellType eType2 = pCell2 ? pCell2->GetCellType() : CELLTYPE_NONE;
870 
871     ScFormulaCell* pFmlaCell1 = (eType1 == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell1 ) : 0;
872     ScFormulaCell* pFmlaCell2 = (eType2 == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell2 ) : 0;
873 
874     // simple swap if no formula cells present
875     if ( !pFmlaCell1 && !pFmlaCell2 )
876     {
877         // remember cell broadcasters, must remain at old position
878         SvtBroadcaster* pBC1 = pCell1->ReleaseBroadcaster();
879 
880         if ( pCell2 )
881         {
882             /*  Both cells exist, no formula cells involved, a simple swap can
883                 be performed (but keep broadcasters and notes at old position). */
884             pItems[nIndex1].pCell = pCell2;
885             pItems[nIndex2].pCell = pCell1;
886 
887             SvtBroadcaster* pBC2 = pCell2->ReleaseBroadcaster();
888             pCell1->TakeBroadcaster( pBC2 );
889             pCell2->TakeBroadcaster( pBC1 );
890         }
891         else
892         {
893             ScNoteCell* pDummyCell = pBC1 ? new ScNoteCell( pBC1 ) : 0;
894             if ( pDummyCell )
895             {
896                 // insert dummy note cell (without note) containing old broadcaster
897                 pItems[nIndex1].pCell = pDummyCell;
898             }
899             else
900             {
901                 // remove ColEntry at old position
902                 --nCount;
903                 memmove( &pItems[nIndex1], &pItems[nIndex1 + 1], (nCount - nIndex1) * sizeof(ColEntry) );
904                 pItems[nCount].nRow = 0;
905                 pItems[nCount].pCell = 0;
906             }
907 
908             // insert ColEntry at new position
909             Insert( nRow2, pCell1 );
910         }
911 
912         return;
913     }
914 
915     // from here: at least one of the cells is a formula cell
916 
917     /*  Never move any array formulas. Disabling sort if parts of array
918         formulas are contained is done at UI. */
919     if ( (pFmlaCell1 && (pFmlaCell1->GetMatrixFlag() != 0)) || (pFmlaCell2 && (pFmlaCell2->GetMatrixFlag() != 0)) )
920         return;
921 
922     // do not swap, if formulas are equal
923     if ( pFmlaCell1 && pFmlaCell2 )
924     {
925         ScTokenArray* pCode1 = pFmlaCell1->GetCode();
926         ScTokenArray* pCode2 = pFmlaCell2->GetCode();
927 
928         if (pCode1->GetLen() == pCode2->GetLen())       // nicht-UPN
929         {
930             sal_Bool bEqual = sal_True;
931             sal_uInt16 nLen = pCode1->GetLen();
932             FormulaToken** ppToken1 = pCode1->GetArray();
933             FormulaToken** ppToken2 = pCode2->GetArray();
934             for (sal_uInt16 i=0; i<nLen; i++)
935             {
936                 if ( !ppToken1[i]->TextEqual(*(ppToken2[i])) ||
937                         ppToken1[i]->Is3DRef() || ppToken2[i]->Is3DRef() )
938                 {
939                     bEqual = sal_False;
940                     break;
941                 }
942             }
943 
944             // do not swap formula cells with equal formulas, but swap notes
945             if (bEqual)
946             {
947                 ScPostIt* pNote1 = pCell1->ReleaseNote();
948                 pCell1->TakeNote( pCell2->ReleaseNote() );
949                 pCell2->TakeNote( pNote1 );
950                 return;
951             }
952         }
953     }
954 
955     //  hier kein UpdateReference wegen #30529# - mitsortiert werden nur noch relative Referenzen
956 //  long dy = (long)nRow2 - (long)nRow1;
957 
958     /*  Create clone of pCell1 at position of pCell2 (pCell1 exists always, see
959         variable swapping above). Do not clone the note, but move pointer of
960         old note to new cell. */
961     ScBaseCell* pNew2 = pCell1->CloneWithoutNote( *pDocument, aPos2, SC_CLONECELL_ADJUST3DREL );
962     pNew2->TakeNote( pCell1->ReleaseNote() );
963 
964     /*  Create clone of pCell2 at position of pCell1. Do not clone the note,
965         but move pointer of old note to new cell. */
966     ScBaseCell* pNew1 = 0;
967     if ( pCell2 )
968     {
969         pNew1 = pCell2->CloneWithoutNote( *pDocument, aPos1, SC_CLONECELL_ADJUST3DREL );
970         pNew1->TakeNote( pCell2->ReleaseNote() );
971     }
972 
973     // move old broadcasters new cells at the same old position
974     SvtBroadcaster* pBC1 = pCell1->ReleaseBroadcaster();
975     lclTakeBroadcaster( pNew1, pBC1 );
976     SvtBroadcaster* pBC2 = pCell2 ? pCell2->ReleaseBroadcaster() : 0;
977     lclTakeBroadcaster( pNew2, pBC2 );
978 
979     /*  Insert the new cells. Old cell has to be deleted, if there is no new
980         cell (call to Insert deletes old cell by itself). */
981     if ( !pNew1 )
982         Delete( nRow1 );            // deletes pCell1
983     else
984         Insert( nRow1, pNew1 );     // deletes pCell1, inserts pNew1
985 
986     if ( pCell2 && !pNew2 )
987         Delete( nRow2 );            // deletes pCell2
988     else if ( pNew2 )
989         Insert( nRow2, pNew2 );     // deletes pCell2 (if existing), inserts pNew2
990 }
991 
992 
993 void ScColumn::SwapCell( SCROW nRow, ScColumn& rCol)
994 {
995     ScBaseCell* pCell1 = 0;
996     SCSIZE nIndex1;
997     if ( Search( nRow, nIndex1 ) )
998         pCell1 = pItems[nIndex1].pCell;
999 
1000     ScBaseCell* pCell2 = 0;
1001     SCSIZE nIndex2;
1002     if ( rCol.Search( nRow, nIndex2 ) )
1003         pCell2 = rCol.pItems[nIndex2].pCell;
1004 
1005     // reverse call if own cell is missing (ensures own existing cell in following code)
1006     if( !pCell1 )
1007     {
1008         if( pCell2 )
1009             rCol.SwapCell( nRow, *this );
1010         return;
1011     }
1012 
1013     // from here: own cell (pCell1, nIndex1) exists always
1014 
1015     ScFormulaCell* pFmlaCell1 = (pCell1->GetCellType() == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell1 ) : 0;
1016     ScFormulaCell* pFmlaCell2 = (pCell2 && (pCell2->GetCellType() == CELLTYPE_FORMULA)) ? static_cast< ScFormulaCell* >( pCell2 ) : 0;
1017 
1018     if ( pCell2 )
1019     {
1020         // Tauschen
1021         pItems[nIndex1].pCell = pCell2;
1022         rCol.pItems[nIndex2].pCell = pCell1;
1023         // Referenzen aktualisieren
1024         SCsCOL dx = rCol.nCol - nCol;
1025         if ( pFmlaCell1 )
1026         {
1027             ScRange aRange( ScAddress( rCol.nCol, 0, nTab ),
1028                             ScAddress( rCol.nCol, MAXROW, nTab ) );
1029             pFmlaCell1->aPos.SetCol( rCol.nCol );
1030             pFmlaCell1->UpdateReference(URM_MOVE, aRange, dx, 0, 0);
1031         }
1032         if ( pFmlaCell2 )
1033         {
1034             ScRange aRange( ScAddress( nCol, 0, nTab ),
1035                             ScAddress( nCol, MAXROW, nTab ) );
1036             pFmlaCell2->aPos.SetCol( nCol );
1037             pFmlaCell2->UpdateReference(URM_MOVE, aRange, -dx, 0, 0);
1038         }
1039     }
1040     else
1041     {
1042         // Loeschen
1043         --nCount;
1044         memmove( &pItems[nIndex1], &pItems[nIndex1 + 1], (nCount - nIndex1) * sizeof(ColEntry) );
1045         pItems[nCount].nRow = 0;
1046         pItems[nCount].pCell = 0;
1047         // Referenzen aktualisieren
1048         SCsCOL dx = rCol.nCol - nCol;
1049         if ( pFmlaCell1 )
1050         {
1051             ScRange aRange( ScAddress( rCol.nCol, 0, nTab ),
1052                             ScAddress( rCol.nCol, MAXROW, nTab ) );
1053             pFmlaCell1->aPos.SetCol( rCol.nCol );
1054             pFmlaCell1->UpdateReference(URM_MOVE, aRange, dx, 0, 0);
1055         }
1056         // Einfuegen
1057         rCol.Insert(nRow, pCell1);
1058     }
1059 }
1060 
1061 
1062 sal_Bool ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
1063 {
1064     if (!IsEmpty())
1065     {
1066         sal_Bool bTest = sal_True;
1067         if (pItems)
1068             for (SCSIZE i=0; (i<nCount) && bTest; i++)
1069                 bTest = (pItems[i].nRow < nStartRow) || (pItems[i].nRow > nEndRow)
1070                         || pItems[i].pCell->IsBlank();
1071 
1072         //  AttrArray testet nur zusammengefasste
1073 
1074         if ((bTest) && (pAttrArray))
1075             bTest = pAttrArray->TestInsertCol(nStartRow, nEndRow);
1076 
1077         //!     rausgeschobene Attribute bei Undo beruecksichtigen
1078 
1079         return bTest;
1080     }
1081     else
1082         return sal_True;
1083 }
1084 
1085 
1086 sal_Bool ScColumn::TestInsertRow( SCSIZE nSize ) const
1087 {
1088     //  AttrArray only looks for merged cells
1089 
1090     if ( pItems && nCount )
1091         return ( nSize <= sal::static_int_cast<SCSIZE>(MAXROW) &&
1092                  pItems[nCount-1].nRow <= MAXROW-(SCROW)nSize && pAttrArray->TestInsertRow( nSize ) );
1093     else
1094         return pAttrArray->TestInsertRow( nSize );
1095 
1096 #if 0
1097     //!     rausgeschobene Attribute bei Undo beruecksichtigen
1098 
1099     if ( nSize > static_cast<SCSIZE>(MAXROW) )
1100         return sal_False;
1101 
1102     SCSIZE nVis = nCount;
1103     while ( nVis && pItems[nVis-1].pCell->IsBlank() )
1104         --nVis;
1105 
1106     if ( nVis )
1107         return ( pItems[nVis-1].nRow <= MAXROW-nSize );
1108     else
1109         return sal_True;
1110 #endif
1111 }
1112 
1113 
1114 void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
1115 {
1116     pAttrArray->InsertRow( nStartRow, nSize );
1117 
1118     //! Search
1119 
1120     if ( !pItems || !nCount )
1121         return;
1122 
1123     SCSIZE i;
1124     Search( nStartRow, i );
1125     if ( i >= nCount )
1126         return ;
1127 
1128     sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1129     pDocument->SetAutoCalc( sal_False );    // Mehrfachberechnungen vermeiden
1130 
1131     SCSIZE nNewCount = nCount;
1132     sal_Bool bCountChanged = sal_False;
1133     ScAddress aAdr( nCol, 0, nTab );
1134     ScHint aHint( SC_HINT_DATACHANGED, aAdr, NULL );    // only areas (ScBaseCell* == NULL)
1135     ScAddress& rAddress = aHint.GetAddress();
1136     // for sparse occupation use single broadcasts, not ranges
1137     sal_Bool bSingleBroadcasts = (((pItems[nCount-1].nRow - pItems[i].nRow) /
1138                 (nCount - i)) > 1);
1139     if ( bSingleBroadcasts )
1140     {
1141         SCROW nLastBroadcast = MAXROW+1;
1142         for ( ; i < nCount; i++)
1143         {
1144             SCROW nOldRow = pItems[i].nRow;
1145             // #43940# Aenderung Quelle broadcasten
1146             if ( nLastBroadcast != nOldRow )
1147             {   // direkt aufeinanderfolgende nicht doppelt broadcasten
1148                 rAddress.SetRow( nOldRow );
1149                 pDocument->AreaBroadcast( aHint );
1150             }
1151             SCROW nNewRow = (pItems[i].nRow += nSize);
1152             // #43940# Aenderung Ziel broadcasten
1153             rAddress.SetRow( nNewRow );
1154             pDocument->AreaBroadcast( aHint );
1155             nLastBroadcast = nNewRow;
1156             ScBaseCell* pCell = pItems[i].pCell;
1157             if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1158                 ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
1159             if ( nNewRow > MAXROW && !bCountChanged )
1160             {
1161                 nNewCount = i;
1162                 bCountChanged = sal_True;
1163             }
1164         }
1165     }
1166     else
1167     {
1168         rAddress.SetRow( pItems[i].nRow );
1169         ScRange aRange( rAddress );
1170         for ( ; i < nCount; i++)
1171         {
1172             SCROW nNewRow = (pItems[i].nRow += nSize);
1173             ScBaseCell* pCell = pItems[i].pCell;
1174             if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1175                 ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
1176             if ( nNewRow > MAXROW && !bCountChanged )
1177             {
1178                 nNewCount = i;
1179                 bCountChanged = sal_True;
1180                 aRange.aEnd.SetRow( MAXROW );
1181             }
1182         }
1183         if ( !bCountChanged )
1184             aRange.aEnd.SetRow( pItems[nCount-1].nRow );
1185         pDocument->AreaBroadcastInRange( aRange, aHint );
1186     }
1187 
1188     if (bCountChanged)
1189     {
1190         SCSIZE nDelCount = nCount - nNewCount;
1191         ScBaseCell** ppDelCells = new ScBaseCell*[nDelCount];
1192         SCROW* pDelRows = new SCROW[nDelCount];
1193         for (i = 0; i < nDelCount; i++)
1194         {
1195             ppDelCells[i] = pItems[nNewCount+i].pCell;
1196             pDelRows[i] = pItems[nNewCount+i].nRow;
1197         }
1198         nCount = nNewCount;
1199 
1200         for (i = 0; i < nDelCount; i++)
1201         {
1202             ScBaseCell* pCell = ppDelCells[i];
1203             DBG_ASSERT( pCell->IsBlank(), "sichtbare Zelle weggeschoben" );
1204             SvtBroadcaster* pBC = pCell->GetBroadcaster();
1205             if (pBC)
1206             {
1207                 MoveListeners( *pBC, pDelRows[i] - nSize );
1208                 pCell->DeleteBroadcaster();
1209                 pCell->Delete();
1210             }
1211         }
1212 
1213         delete [] pDelRows;
1214         delete [] ppDelCells;
1215     }
1216 
1217     pDocument->SetAutoCalc( bOldAutoCalc );
1218 }
1219 
1220 
1221 void ScColumn::CopyToClip(SCROW nRow1, SCROW nRow2, ScColumn& rColumn, sal_Bool bKeepScenarioFlags, sal_Bool bCloneNoteCaptions)
1222 {
1223     pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray,
1224                             bKeepScenarioFlags ? (SC_MF_ALL & ~SC_MF_SCENARIO) : SC_MF_ALL );
1225 
1226     SCSIZE i;
1227     SCSIZE nBlockCount = 0;
1228     SCSIZE nStartIndex = 0, nEndIndex = 0;
1229     for (i = 0; i < nCount; i++)
1230         if ((pItems[i].nRow >= nRow1) && (pItems[i].nRow <= nRow2))
1231         {
1232             if (!nBlockCount)
1233                 nStartIndex = i;
1234             nEndIndex = i;
1235             ++nBlockCount;
1236 
1237             //  im Clipboard muessen interpretierte Zellen stehen, um andere Formate
1238             //  (Text, Grafik...) erzueugen zu koennen
1239 
1240             if ( pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA )
1241             {
1242                 ScFormulaCell* pFCell = (ScFormulaCell*) pItems[i].pCell;
1243                 if (pFCell->GetDirty() && pDocument->GetAutoCalc())
1244                     pFCell->Interpret();
1245             }
1246         }
1247 
1248     if (nBlockCount)
1249     {
1250         int nCloneFlags = bCloneNoteCaptions ? SC_CLONECELL_DEFAULT : SC_CLONECELL_NOCAPTION;
1251         rColumn.Resize( rColumn.GetCellCount() + nBlockCount );
1252         ScAddress aOwnPos( nCol, 0, nTab );
1253         ScAddress aDestPos( rColumn.nCol, 0, rColumn.nTab );
1254         for (i = nStartIndex; i <= nEndIndex; i++)
1255         {
1256             aOwnPos.SetRow( pItems[i].nRow );
1257             aDestPos.SetRow( pItems[i].nRow );
1258             ScBaseCell* pNewCell = pItems[i].pCell->CloneWithNote( aOwnPos, *rColumn.pDocument, aDestPos, nCloneFlags );
1259             rColumn.Append( aDestPos.Row(), pNewCell );
1260         }
1261     }
1262 }
1263 
1264 
1265 void ScColumn::CopyToColumn(SCROW nRow1, SCROW nRow2, sal_uInt16 nFlags, sal_Bool bMarked,
1266                                 ScColumn& rColumn, const ScMarkData* pMarkData, sal_Bool bAsLink )
1267 {
1268     if (bMarked)
1269     {
1270         SCROW nStart, nEnd;
1271         if (pMarkData && pMarkData->IsMultiMarked())
1272         {
1273             ScMarkArrayIter aIter( pMarkData->GetArray()+nCol );
1274 
1275             while ( aIter.Next( nStart, nEnd ) && nStart <= nRow2 )
1276             {
1277                 if ( nEnd >= nRow1 )
1278                     CopyToColumn( Max(nRow1,nStart), Min(nRow2,nEnd),
1279                                     nFlags, sal_False, rColumn, pMarkData, bAsLink );
1280             }
1281         }
1282         else
1283         {
1284             DBG_ERROR("CopyToColumn: bMarked, aber keine Markierung");
1285         }
1286         return;
1287     }
1288 
1289     if ( (nFlags & IDF_ATTRIB) != 0 )
1290     {
1291         if ( (nFlags & IDF_STYLES) != IDF_STYLES )
1292         {   // StyleSheets im Zieldokument bleiben erhalten
1293             // z.B. DIF und RTF Clipboard-Import
1294             for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ )
1295             {
1296                 const ScStyleSheet* pStyle =
1297                     rColumn.pAttrArray->GetPattern( nRow )->GetStyleSheet();
1298                 const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
1299                 ScPatternAttr* pNewPattern = new ScPatternAttr( *pPattern );
1300                 pNewPattern->SetStyleSheet( (ScStyleSheet*)pStyle );
1301                 rColumn.pAttrArray->SetPattern( nRow, pNewPattern, sal_True );
1302                 delete pNewPattern;
1303             }
1304         }
1305         else
1306             pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray);
1307     }
1308 
1309 
1310     if ((nFlags & IDF_CONTENTS) != 0)
1311     {
1312         SCSIZE i;
1313         SCSIZE nBlockCount = 0;
1314         SCSIZE nStartIndex = 0, nEndIndex = 0;
1315         for (i = 0; i < nCount; i++)
1316             if ((pItems[i].nRow >= nRow1) && (pItems[i].nRow <= nRow2))
1317             {
1318                 if (!nBlockCount)
1319                     nStartIndex = i;
1320                 nEndIndex = i;
1321                 ++nBlockCount;
1322             }
1323 
1324         if (nBlockCount)
1325         {
1326             rColumn.Resize( rColumn.GetCellCount() + nBlockCount );
1327             ScAddress aDestPos( rColumn.nCol, 0, rColumn.nTab );
1328             for (i = nStartIndex; i <= nEndIndex; i++)
1329             {
1330                 aDestPos.SetRow( pItems[i].nRow );
1331                 ScBaseCell* pNew = bAsLink ?
1332                     CreateRefCell( rColumn.pDocument, aDestPos, i, nFlags ) :
1333                     CloneCell( i, nFlags, *rColumn.pDocument, aDestPos );
1334 
1335                 if (pNew)
1336                     rColumn.Insert(pItems[i].nRow, pNew);
1337             }
1338         }
1339     }
1340 }
1341 
1342 
1343 void ScColumn::UndoToColumn(SCROW nRow1, SCROW nRow2, sal_uInt16 nFlags, sal_Bool bMarked,
1344                                 ScColumn& rColumn, const ScMarkData* pMarkData )
1345 {
1346     if (nRow1 > 0)
1347         CopyToColumn( 0, nRow1-1, IDF_FORMULA, sal_False, rColumn );
1348 
1349     CopyToColumn( nRow1, nRow2, nFlags, bMarked, rColumn, pMarkData );      //! bMarked ????
1350 
1351     if (nRow2 < MAXROW)
1352         CopyToColumn( nRow2+1, MAXROW, IDF_FORMULA, sal_False, rColumn );
1353 }
1354 
1355 
1356 void ScColumn::CopyUpdated( const ScColumn& rPosCol, ScColumn& rDestCol ) const
1357 {
1358     ScDocument& rDestDoc = *rDestCol.pDocument;
1359     ScAddress aOwnPos( nCol, 0, nTab );
1360     ScAddress aDestPos( rDestCol.nCol, 0, rDestCol.nTab );
1361 
1362     SCSIZE nPosCount = rPosCol.nCount;
1363     for (SCSIZE nPosIndex = 0; nPosIndex < nPosCount; nPosIndex++)
1364     {
1365         aOwnPos.SetRow( rPosCol.pItems[nPosIndex].nRow );
1366         aDestPos.SetRow( aOwnPos.Row() );
1367         SCSIZE nThisIndex;
1368         if ( Search( aDestPos.Row(), nThisIndex ) )
1369         {
1370             ScBaseCell* pNew = pItems[nThisIndex].pCell->CloneWithNote( aOwnPos, rDestDoc, aDestPos );
1371             rDestCol.Insert( aDestPos.Row(), pNew );
1372         }
1373     }
1374 
1375     //  Dummy:
1376     //  CopyToColumn( 0,MAXROW, IDF_FORMULA, sal_False, rDestCol, NULL, sal_False );
1377 }
1378 
1379 
1380 void ScColumn::CopyScenarioFrom( const ScColumn& rSrcCol )
1381 {
1382     //  Dies ist die Szenario-Tabelle, die Daten werden hineinkopiert
1383 
1384     ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1385     SCROW nStart = -1, nEnd = -1;
1386     const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1387     while (pPattern)
1388     {
1389         if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1390         {
1391             DeleteArea( nStart, nEnd, IDF_CONTENTS );
1392             ((ScColumn&)rSrcCol).
1393                 CopyToColumn( nStart, nEnd, IDF_CONTENTS, sal_False, *this );
1394 
1395             //  UpdateUsed nicht noetig, schon in TestCopyScenario passiert
1396 
1397             SCsTAB nDz = nTab - rSrcCol.nTab;
1398             UpdateReference(URM_COPY, nCol, nStart, nTab,
1399                                       nCol, nEnd,   nTab,
1400                                       0, 0, nDz, NULL);
1401             UpdateCompile();
1402         }
1403 
1404         //! CopyToColumn "const" machen !!!
1405 
1406         pPattern = aAttrIter.Next( nStart, nEnd );
1407     }
1408 }
1409 
1410 
1411 void ScColumn::CopyScenarioTo( ScColumn& rDestCol ) const
1412 {
1413     //  Dies ist die Szenario-Tabelle, die Daten werden in die andere kopiert
1414 
1415     ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1416     SCROW nStart = -1, nEnd = -1;
1417     const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1418     while (pPattern)
1419     {
1420         if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1421         {
1422             rDestCol.DeleteArea( nStart, nEnd, IDF_CONTENTS );
1423             ((ScColumn*)this)->
1424                 CopyToColumn( nStart, nEnd, IDF_CONTENTS, sal_False, rDestCol );
1425 
1426             //  UpdateUsed nicht noetig, schon in TestCopyScenario passiert
1427 
1428             SCsTAB nDz = rDestCol.nTab - nTab;
1429             rDestCol.UpdateReference(URM_COPY, rDestCol.nCol, nStart, rDestCol.nTab,
1430                                                rDestCol.nCol, nEnd,   rDestCol.nTab,
1431                                                0, 0, nDz, NULL);
1432             rDestCol.UpdateCompile();
1433         }
1434 
1435         //! CopyToColumn "const" machen !!!
1436 
1437         pPattern = aAttrIter.Next( nStart, nEnd );
1438     }
1439 }
1440 
1441 
1442 sal_Bool ScColumn::TestCopyScenarioTo( const ScColumn& rDestCol ) const
1443 {
1444     sal_Bool bOk = sal_True;
1445     ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1446     SCROW nStart = 0, nEnd = 0;
1447     const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1448     while (pPattern && bOk)
1449     {
1450         if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1451             if ( rDestCol.pAttrArray->HasAttrib( nStart, nEnd, HASATTR_PROTECTED ) )
1452                 bOk = sal_False;
1453 
1454         pPattern = aAttrIter.Next( nStart, nEnd );
1455     }
1456     return bOk;
1457 }
1458 
1459 
1460 void ScColumn::MarkScenarioIn( ScMarkData& rDestMark ) const
1461 {
1462     ScRange aRange( nCol, 0, nTab );
1463 
1464     ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
1465     SCROW nStart = -1, nEnd = -1;
1466     const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
1467     while (pPattern)
1468     {
1469         if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
1470         {
1471             aRange.aStart.SetRow( nStart );
1472             aRange.aEnd.SetRow( nEnd );
1473             rDestMark.SetMultiMarkArea( aRange, sal_True );
1474         }
1475 
1476         pPattern = aAttrIter.Next( nStart, nEnd );
1477     }
1478 }
1479 
1480 
1481 void ScColumn::SwapCol(ScColumn& rCol)
1482 {
1483     SCSIZE nTemp;
1484 
1485     nTemp = rCol.nCount;
1486     rCol.nCount  = nCount;
1487     nCount = nTemp;
1488 
1489     nTemp = rCol.nLimit;
1490     rCol.nLimit = nLimit;
1491     nLimit = nTemp;
1492 
1493     ColEntry* pTempItems = rCol.pItems;
1494     rCol.pItems = pItems;
1495     pItems = pTempItems;
1496 
1497     ScAttrArray* pTempAttr = rCol.pAttrArray;
1498     rCol.pAttrArray = pAttrArray;
1499     pAttrArray = pTempAttr;
1500 
1501     // #38415# AttrArray muss richtige Spaltennummer haben
1502     pAttrArray->SetCol(nCol);
1503     rCol.pAttrArray->SetCol(rCol.nCol);
1504 
1505     SCSIZE i;
1506     if (pItems)
1507         for (i = 0; i < nCount; i++)
1508         {
1509             ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell;
1510             if( pCell->GetCellType() == CELLTYPE_FORMULA)
1511                 pCell->aPos.SetCol(nCol);
1512         }
1513     if (rCol.pItems)
1514         for (i = 0; i < rCol.nCount; i++)
1515         {
1516             ScFormulaCell* pCell = (ScFormulaCell*) rCol.pItems[i].pCell;
1517             if( pCell->GetCellType() == CELLTYPE_FORMULA)
1518                 pCell->aPos.SetCol(rCol.nCol);
1519         }
1520 }
1521 
1522 
1523 void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol)
1524 {
1525     pAttrArray->MoveTo(nStartRow, nEndRow, *rCol.pAttrArray);
1526 
1527     if (pItems)
1528     {
1529         ::std::vector<SCROW> aRows;
1530         bool bConsecutive = true;
1531         SCSIZE i;
1532         Search( nStartRow, i);  // i points to start row or position thereafter
1533         SCSIZE nStartPos = i;
1534         for ( ; i < nCount && pItems[i].nRow <= nEndRow; ++i)
1535         {
1536             SCROW nRow = pItems[i].nRow;
1537             aRows.push_back( nRow);
1538             rCol.Insert( nRow, pItems[i].pCell);
1539             if (nRow != pItems[i].nRow)
1540             {   // Listener inserted
1541                 bConsecutive = false;
1542                 Search( nRow, i);
1543             }
1544         }
1545         SCSIZE nStopPos = i;
1546         if (nStartPos < nStopPos)
1547         {
1548             // Create list of ranges of cell entry positions
1549             typedef ::std::pair<SCSIZE,SCSIZE> PosPair;
1550             typedef ::std::vector<PosPair> EntryPosPairs;
1551             EntryPosPairs aEntries;
1552             if (bConsecutive)
1553                 aEntries.push_back( PosPair(nStartPos, nStopPos));
1554             else
1555             {
1556                 bool bFirst = true;
1557                 nStopPos = 0;
1558                 for (::std::vector<SCROW>::const_iterator it( aRows.begin());
1559                         it != aRows.end() && nStopPos < nCount; ++it,
1560                         ++nStopPos)
1561                 {
1562                     if (!bFirst && *it != pItems[nStopPos].nRow)
1563                     {
1564                         aEntries.push_back( PosPair(nStartPos, nStopPos));
1565                         bFirst = true;
1566                     }
1567                     if (bFirst && Search( *it, nStartPos))
1568                     {
1569                         bFirst = false;
1570                         nStopPos = nStartPos;
1571                     }
1572                 }
1573                 if (!bFirst && nStartPos < nStopPos)
1574                     aEntries.push_back( PosPair(nStartPos, nStopPos));
1575             }
1576             // Broadcast changes
1577             ScAddress aAdr( nCol, 0, nTab );
1578             ScHint aHint( SC_HINT_DYING, aAdr, NULL );  // areas only
1579             ScAddress& rAddress = aHint.GetAddress();
1580             ScNoteCell* pNoteCell = new ScNoteCell;     // Dummy like in DeleteRange
1581 
1582             // #121990# must iterate backwards, because indexes of following cells become invalid
1583             for (EntryPosPairs::reverse_iterator it( aEntries.rbegin());
1584                     it != aEntries.rend(); ++it)
1585             {
1586                 nStartPos = (*it).first;
1587                 nStopPos = (*it).second;
1588                 for (i=nStartPos; i<nStopPos; ++i)
1589                     pItems[i].pCell = pNoteCell;
1590                 for (i=nStartPos; i<nStopPos; ++i)
1591                 {
1592                     rAddress.SetRow( pItems[i].nRow );
1593                     pDocument->AreaBroadcast( aHint );
1594                 }
1595                 nCount -= nStopPos - nStartPos;
1596                 memmove( &pItems[nStartPos], &pItems[nStopPos],
1597                         (nCount - nStartPos) * sizeof(ColEntry) );
1598             }
1599             delete pNoteCell;
1600             pItems[nCount].nRow = 0;
1601             pItems[nCount].pCell = NULL;
1602         }
1603     }
1604 }
1605 
1606 
1607 void ScColumn::UpdateReference( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1608              SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
1609              ScDocument* pUndoDoc )
1610 {
1611     if (pItems)
1612     {
1613         ScRange aRange( ScAddress( nCol1, nRow1, nTab1 ),
1614                         ScAddress( nCol2, nRow2, nTab2 ) );
1615         if ( eUpdateRefMode == URM_COPY && nRow1 == nRow2 )
1616         {   // z.B. eine einzelne Zelle aus dem Clipboard eingefuegt
1617             SCSIZE nIndex;
1618             if ( Search( nRow1, nIndex ) )
1619             {
1620                 ScFormulaCell* pCell = (ScFormulaCell*) pItems[nIndex].pCell;
1621                 if( pCell->GetCellType() == CELLTYPE_FORMULA)
1622                     pCell->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc );
1623             }
1624         }
1625         else
1626         {
1627             // #90279# For performance reasons two loop bodies instead of
1628             // testing for update mode in each iteration.
1629             // Anyways, this is still a bottleneck on large arrays with few
1630             // formulas cells.
1631             if ( eUpdateRefMode == URM_COPY )
1632             {
1633                 SCSIZE i;
1634                 Search( nRow1, i );
1635                 for ( ; i < nCount; i++ )
1636                 {
1637                     SCROW nRow = pItems[i].nRow;
1638                     if ( nRow > nRow2 )
1639                         break;
1640                     ScBaseCell* pCell = pItems[i].pCell;
1641                     if( pCell->GetCellType() == CELLTYPE_FORMULA)
1642                     {
1643                         ((ScFormulaCell*)pCell)->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc );
1644                         if ( nRow != pItems[i].nRow )
1645                             Search( nRow, i );  // Listener removed/inserted?
1646                     }
1647                 }
1648             }
1649             else
1650             {
1651                 SCSIZE i = 0;
1652                 for ( ; i < nCount; i++ )
1653                 {
1654                     ScBaseCell* pCell = pItems[i].pCell;
1655                     if( pCell->GetCellType() == CELLTYPE_FORMULA)
1656                     {
1657                         SCROW nRow = pItems[i].nRow;
1658                         // When deleting rows on several sheets, the formula's position may be updated with the first call,
1659                         // so the undo position must be passed from here.
1660                         ScAddress aUndoPos( nCol, nRow, nTab );
1661                         ((ScFormulaCell*)pCell)->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc, &aUndoPos );
1662                         if ( nRow != pItems[i].nRow )
1663                             Search( nRow, i );  // Listener removed/inserted?
1664                     }
1665                 }
1666             }
1667         }
1668     }
1669 }
1670 
1671 
1672 void ScColumn::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
1673                                     ScDocument* pUndoDoc )
1674 {
1675     if (pItems)
1676         for (SCSIZE i=0; i<nCount; i++)
1677         {
1678             ScBaseCell* pCell = pItems[i].pCell;
1679             if (pCell->GetCellType() == CELLTYPE_FORMULA)
1680             {
1681                 SCROW nRow = pItems[i].nRow;
1682                 ((ScFormulaCell*)pCell)->UpdateTranspose( rSource, rDest, pUndoDoc );
1683                 if ( nRow != pItems[i].nRow )
1684                     Search( nRow, i );              // Listener geloescht/eingefuegt?
1685             }
1686         }
1687 }
1688 
1689 
1690 void ScColumn::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
1691 {
1692     if (pItems)
1693         for (SCSIZE i=0; i<nCount; i++)
1694         {
1695             ScBaseCell* pCell = pItems[i].pCell;
1696             if (pCell->GetCellType() == CELLTYPE_FORMULA)
1697             {
1698                 SCROW nRow = pItems[i].nRow;
1699                 ((ScFormulaCell*)pCell)->UpdateGrow( rArea, nGrowX, nGrowY );
1700                 if ( nRow != pItems[i].nRow )
1701                     Search( nRow, i );              // Listener geloescht/eingefuegt?
1702             }
1703         }
1704 }
1705 
1706 
1707 void ScColumn::UpdateInsertTab( SCTAB nTable)
1708 {
1709     if (nTab >= nTable)
1710         pAttrArray->SetTab(++nTab);
1711     if( pItems )
1712         UpdateInsertTabOnlyCells( nTable );
1713 }
1714 
1715 
1716 void ScColumn::UpdateInsertTabOnlyCells( SCTAB nTable)
1717 {
1718     if (pItems)
1719         for (SCSIZE i = 0; i < nCount; i++)
1720         {
1721             ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell;
1722             if( pCell->GetCellType() == CELLTYPE_FORMULA)
1723             {
1724                 SCROW nRow = pItems[i].nRow;
1725                 pCell->UpdateInsertTab(nTable);
1726                 if ( nRow != pItems[i].nRow )
1727                     Search( nRow, i );      // Listener geloescht/eingefuegt?
1728             }
1729         }
1730 }
1731 
1732 
1733 void ScColumn::UpdateInsertTabAbs(SCTAB nTable)
1734 {
1735     if (pItems)
1736         for (SCSIZE i = 0; i < nCount; i++)
1737         {
1738             ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell;
1739             if( pCell->GetCellType() == CELLTYPE_FORMULA)
1740             {
1741                 SCROW nRow = pItems[i].nRow;
1742                 pCell->UpdateInsertTabAbs(nTable);
1743                 if ( nRow != pItems[i].nRow )
1744                     Search( nRow, i );      // Listener geloescht/eingefuegt?
1745             }
1746         }
1747 }
1748 
1749 
1750 void ScColumn::UpdateDeleteTab( SCTAB nTable, sal_Bool bIsMove, ScColumn* pRefUndo )
1751 {
1752     if (nTab > nTable)
1753         pAttrArray->SetTab(--nTab);
1754 
1755     if (pItems)
1756         for (SCSIZE i = 0; i < nCount; i++)
1757             if ( pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA )
1758             {
1759                 SCROW nRow = pItems[i].nRow;
1760                 ScFormulaCell* pOld = (ScFormulaCell*)pItems[i].pCell;
1761 
1762                 /*  Do not copy cell note to the undo document. Undo will copy
1763                     back the formula cell while keeping the original note. */
1764                 ScBaseCell* pSave = pRefUndo ? pOld->CloneWithoutNote( *pDocument ) : 0;
1765 
1766                 sal_Bool bChanged = pOld->UpdateDeleteTab(nTable, bIsMove);
1767                 if ( nRow != pItems[i].nRow )
1768                     Search( nRow, i );      // Listener geloescht/eingefuegt?
1769 
1770                 if (pRefUndo)
1771                 {
1772                     if (bChanged)
1773                         pRefUndo->Insert( nRow, pSave );
1774                     else if(pSave)
1775                         pSave->Delete();
1776                 }
1777             }
1778 }
1779 
1780 
1781 void ScColumn::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo )
1782 {
1783     nTab = nTabNo;
1784     pAttrArray->SetTab( nTabNo );
1785     if (pItems)
1786         for (SCSIZE i = 0; i < nCount; i++)
1787         {
1788             ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell;
1789             if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1790             {
1791                 SCROW nRow = pItems[i].nRow;
1792                 pCell->UpdateMoveTab( nOldPos, nNewPos, nTabNo );
1793                 if ( nRow != pItems[i].nRow )
1794                     Search( nRow, i );      // Listener geloescht/eingefuegt?
1795             }
1796         }
1797 }
1798 
1799 
1800 void ScColumn::UpdateCompile( sal_Bool bForceIfNameInUse )
1801 {
1802     if (pItems)
1803         for (SCSIZE i = 0; i < nCount; i++)
1804         {
1805             ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
1806             if( p->GetCellType() == CELLTYPE_FORMULA )
1807             {
1808                 SCROW nRow = pItems[i].nRow;
1809                 p->UpdateCompile( bForceIfNameInUse );
1810                 if ( nRow != pItems[i].nRow )
1811                     Search( nRow, i );      // Listener geloescht/eingefuegt?
1812             }
1813         }
1814 }
1815 
1816 
1817 void ScColumn::SetTabNo(SCTAB nNewTab)
1818 {
1819     nTab = nNewTab;
1820     pAttrArray->SetTab( nNewTab );
1821     if (pItems)
1822         for (SCSIZE i = 0; i < nCount; i++)
1823         {
1824             ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
1825             if( p->GetCellType() == CELLTYPE_FORMULA )
1826                 p->aPos.SetTab( nNewTab );
1827         }
1828 }
1829 
1830 
1831 sal_Bool ScColumn::IsRangeNameInUse(SCROW nRow1, SCROW nRow2, sal_uInt16 nIndex) const
1832 {
1833     sal_Bool bInUse = sal_False;
1834     if (pItems)
1835         for (SCSIZE i = 0; !bInUse && (i < nCount); i++)
1836             if ((pItems[i].nRow >= nRow1) &&
1837                 (pItems[i].nRow <= nRow2) &&
1838                 (pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA))
1839                     bInUse = ((ScFormulaCell*)pItems[i].pCell)->IsRangeNameInUse(nIndex);
1840     return bInUse;
1841 }
1842 
1843 void ScColumn::FindRangeNamesInUse(SCROW nRow1, SCROW nRow2, std::set<sal_uInt16>& rIndexes) const
1844 {
1845     if (pItems)
1846         for (SCSIZE i = 0; i < nCount; i++)
1847             if ((pItems[i].nRow >= nRow1) &&
1848                 (pItems[i].nRow <= nRow2) &&
1849                 (pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA))
1850                     ((ScFormulaCell*)pItems[i].pCell)->FindRangeNamesInUse(rIndexes);
1851 }
1852 
1853 void ScColumn::ReplaceRangeNamesInUse(SCROW nRow1, SCROW nRow2,
1854                                      const ScRangeData::IndexMap& rMap )
1855 {
1856     if (pItems)
1857         for (SCSIZE i = 0; i < nCount; i++)
1858         {
1859             if ((pItems[i].nRow >= nRow1) &&
1860                 (pItems[i].nRow <= nRow2) &&
1861                 (pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA))
1862             {
1863                 SCROW nRow = pItems[i].nRow;
1864                 ((ScFormulaCell*)pItems[i].pCell)->ReplaceRangeNamesInUse( rMap );
1865                 if ( nRow != pItems[i].nRow )
1866                     Search( nRow, i );      // Listener geloescht/eingefuegt?
1867             }
1868         }
1869 }
1870 
1871 void ScColumn::SetDirtyVar()
1872 {
1873     for (SCSIZE i=0; i<nCount; i++)
1874     {
1875         ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
1876         if( p->GetCellType() == CELLTYPE_FORMULA )
1877             p->SetDirtyVar();
1878     }
1879 }
1880 
1881 
1882 void ScColumn::SetDirty()
1883 {
1884     // wird nur dokumentweit verwendet, kein FormulaTrack
1885     sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1886     pDocument->SetAutoCalc( sal_False );    // Mehrfachberechnungen vermeiden
1887     for (SCSIZE i=0; i<nCount; i++)
1888     {
1889         ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
1890         if( p->GetCellType() == CELLTYPE_FORMULA )
1891         {
1892             p->SetDirtyVar();
1893             if ( !pDocument->IsInFormulaTree( p ) )
1894                 pDocument->PutInFormulaTree( p );
1895         }
1896     }
1897     pDocument->SetAutoCalc( bOldAutoCalc );
1898 }
1899 
1900 
1901 void ScColumn::SetDirty( const ScRange& rRange )
1902 {   // broadcastet alles innerhalb eines Range, mit FormulaTrack
1903     if ( !pItems || !nCount )
1904         return ;
1905     sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1906     pDocument->SetAutoCalc( sal_False );    // Mehrfachberechnungen vermeiden
1907     SCROW nRow2 = rRange.aEnd.Row();
1908     ScAddress aPos( nCol, 0, nTab );
1909     ScHint aHint( SC_HINT_DATACHANGED, aPos, NULL );
1910     SCROW nRow;
1911     SCSIZE nIndex;
1912     Search( rRange.aStart.Row(), nIndex );
1913     while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRow2 )
1914     {
1915         ScBaseCell* pCell = pItems[nIndex].pCell;
1916         if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1917             ((ScFormulaCell*)pCell)->SetDirty();
1918         else
1919         {
1920             aHint.GetAddress().SetRow( nRow );
1921             aHint.SetCell( pCell );
1922             pDocument->Broadcast( aHint );
1923         }
1924         nIndex++;
1925     }
1926     pDocument->SetAutoCalc( bOldAutoCalc );
1927 }
1928 
1929 
1930 void ScColumn::SetTableOpDirty( const ScRange& rRange )
1931 {
1932     if ( !pItems || !nCount )
1933         return ;
1934     sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1935     pDocument->SetAutoCalc( sal_False );    // no multiple recalculation
1936     SCROW nRow2 = rRange.aEnd.Row();
1937     ScAddress aPos( nCol, 0, nTab );
1938     ScHint aHint( SC_HINT_TABLEOPDIRTY, aPos, NULL );
1939     SCROW nRow;
1940     SCSIZE nIndex;
1941     Search( rRange.aStart.Row(), nIndex );
1942     while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRow2 )
1943     {
1944         ScBaseCell* pCell = pItems[nIndex].pCell;
1945         if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1946             ((ScFormulaCell*)pCell)->SetTableOpDirty();
1947         else
1948         {
1949             aHint.GetAddress().SetRow( nRow );
1950             aHint.SetCell( pCell );
1951             pDocument->Broadcast( aHint );
1952         }
1953         nIndex++;
1954     }
1955     pDocument->SetAutoCalc( bOldAutoCalc );
1956 }
1957 
1958 
1959 void ScColumn::SetDirtyAfterLoad()
1960 {
1961     sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1962     pDocument->SetAutoCalc( sal_False );    // Mehrfachberechnungen vermeiden
1963     for (SCSIZE i=0; i<nCount; i++)
1964     {
1965         ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
1966 #if 1
1967         // Simply set dirty and append to FormulaTree, without broadcasting,
1968         // which is a magnitude faster. This is used to calculate the entire
1969         // document, e.g. when loading alien file formats.
1970         if ( p->GetCellType() == CELLTYPE_FORMULA )
1971             p->SetDirtyAfterLoad();
1972 #else
1973 /* This was used with the binary file format that stored results, where only
1974  * newly compiled and volatile functions and their dependents had to be
1975  * recalculated, which was faster then. Since that was moved to 'binfilter' to
1976  * convert to an XML file this isn't needed anymore, and not used for other
1977  * file formats. Kept for reference in case mechanism needs to be reactivated
1978  * for some file formats, we'd have to introduce a controlling parameter to
1979  * this method here then.
1980 */
1981 
1982         // If the cell was alsready dirty because of CalcAfterLoad,
1983         // FormulaTracking has to take place.
1984         if ( p->GetCellType() == CELLTYPE_FORMULA && p->GetDirty() )
1985             p->SetDirty();
1986 #endif
1987     }
1988     pDocument->SetAutoCalc( bOldAutoCalc );
1989 }
1990 
1991 
1992 void ScColumn::SetRelNameDirty()
1993 {
1994     sal_Bool bOldAutoCalc = pDocument->GetAutoCalc();
1995     pDocument->SetAutoCalc( sal_False );    // Mehrfachberechnungen vermeiden
1996     for (SCSIZE i=0; i<nCount; i++)
1997     {
1998         ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
1999         if( p->GetCellType() == CELLTYPE_FORMULA && p->HasRelNameReference() )
2000             p->SetDirty();
2001     }
2002     pDocument->SetAutoCalc( bOldAutoCalc );
2003 }
2004 
2005 
2006 void ScColumn::CalcAll()
2007 {
2008     if (pItems)
2009         for (SCSIZE i=0; i<nCount; i++)
2010         {
2011             ScBaseCell* pCell = pItems[i].pCell;
2012             if (pCell->GetCellType() == CELLTYPE_FORMULA)
2013             {
2014 #if OSL_DEBUG_LEVEL > 1
2015                 // nach F9 ctrl-F9: ueberprueft die Berechnung per FormulaTree
2016                 ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
2017                 double nOldVal, nNewVal;
2018                 nOldVal = pFCell->GetValue();
2019 #endif
2020                 ((ScFormulaCell*)pCell)->Interpret();
2021 #if OSL_DEBUG_LEVEL > 1
2022                 if ( pFCell->GetCode()->IsRecalcModeNormal() )
2023                     nNewVal = pFCell->GetValue();
2024                 else
2025                     nNewVal = nOldVal;  // random(), jetzt() etc.
2026                 DBG_ASSERT( nOldVal==nNewVal, "CalcAll: nOldVal != nNewVal" );
2027 #endif
2028             }
2029         }
2030 }
2031 
2032 
2033 void ScColumn::CompileAll()
2034 {
2035     if (pItems)
2036         for (SCSIZE i = 0; i < nCount; i++)
2037         {
2038             ScBaseCell* pCell = pItems[i].pCell;
2039             if ( pCell->GetCellType() == CELLTYPE_FORMULA )
2040             {
2041                 SCROW nRow = pItems[i].nRow;
2042                 // fuer unbedingtes kompilieren
2043                 // bCompile=sal_True und pCode->nError=0
2044                 ((ScFormulaCell*)pCell)->GetCode()->SetCodeError( 0 );
2045                 ((ScFormulaCell*)pCell)->SetCompile( sal_True );
2046                 ((ScFormulaCell*)pCell)->CompileTokenArray();
2047                 if ( nRow != pItems[i].nRow )
2048                     Search( nRow, i );      // Listener geloescht/eingefuegt?
2049             }
2050         }
2051 }
2052 
2053 
2054 void ScColumn::CompileXML( ScProgress& rProgress )
2055 {
2056     if (pItems)
2057         for (SCSIZE i = 0; i < nCount; i++)
2058         {
2059             ScBaseCell* pCell = pItems[i].pCell;
2060             if ( pCell->GetCellType() == CELLTYPE_FORMULA )
2061             {
2062                 SCROW nRow = pItems[i].nRow;
2063                 ((ScFormulaCell*)pCell)->CompileXML( rProgress );
2064                 if ( nRow != pItems[i].nRow )
2065                     Search( nRow, i );      // Listener geloescht/eingefuegt?
2066             }
2067         }
2068 }
2069 
2070 
2071 void ScColumn::CalcAfterLoad()
2072 {
2073     if (pItems)
2074         for (SCSIZE i = 0; i < nCount; i++)
2075         {
2076             ScBaseCell* pCell = pItems[i].pCell;
2077             if ( pCell->GetCellType() == CELLTYPE_FORMULA )
2078                 ((ScFormulaCell*)pCell)->CalcAfterLoad();
2079         }
2080 }
2081 
2082 
2083 void ScColumn::ResetChanged( SCROW nStartRow, SCROW nEndRow )
2084 {
2085     if (pItems)
2086     {
2087         SCSIZE nIndex;
2088         Search(nStartRow,nIndex);
2089         while (nIndex<nCount && pItems[nIndex].nRow <= nEndRow)
2090         {
2091             ScBaseCell* pCell = pItems[nIndex].pCell;
2092             if (pCell->GetCellType() == CELLTYPE_FORMULA)
2093                 ((ScFormulaCell*)pCell)->ResetChanged();
2094             ++nIndex;
2095         }
2096     }
2097 }
2098 
2099 
2100 sal_Bool ScColumn::HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst) const
2101 {
2102     //  used in GetOptimalHeight - ambiguous script type counts as edit cell
2103 
2104     SCROW nRow = 0;
2105     SCSIZE nIndex;
2106     Search(nStartRow,nIndex);
2107     while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEndRow) : sal_False )
2108     {
2109         ScBaseCell* pCell = pItems[nIndex].pCell;
2110         CellType eCellType = pCell->GetCellType();
2111         if ( eCellType == CELLTYPE_EDIT ||
2112              IsAmbiguousScriptNonZero( pDocument->GetScriptType(nCol, nRow, nTab, pCell) ) ||
2113              ((eCellType == CELLTYPE_FORMULA) && ((ScFormulaCell*)pCell)->IsMultilineResult()) )
2114         {
2115             rFirst = nRow;
2116             return sal_True;
2117         }
2118         ++nIndex;
2119     }
2120 
2121     return sal_False;
2122 }
2123 
2124 
2125 SCsROW ScColumn::SearchStyle( SCsROW nRow, const ScStyleSheet* pSearchStyle,
2126                                 sal_Bool bUp, sal_Bool bInSelection, const ScMarkData& rMark )
2127 {
2128     if (bInSelection)
2129     {
2130         if (rMark.IsMultiMarked())
2131             return pAttrArray->SearchStyle( nRow, pSearchStyle, bUp,
2132                                     (ScMarkArray*) rMark.GetArray()+nCol );     //! const
2133         else
2134             return -1;
2135     }
2136     else
2137         return pAttrArray->SearchStyle( nRow, pSearchStyle, bUp, NULL );
2138 }
2139 
2140 
2141 sal_Bool ScColumn::SearchStyleRange( SCsROW& rRow, SCsROW& rEndRow, const ScStyleSheet* pSearchStyle,
2142                                     sal_Bool bUp, sal_Bool bInSelection, const ScMarkData& rMark )
2143 {
2144     if (bInSelection)
2145     {
2146         if (rMark.IsMultiMarked())
2147             return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp,
2148                                     (ScMarkArray*) rMark.GetArray()+nCol );     //! const
2149         else
2150             return sal_False;
2151     }
2152     else
2153         return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp, NULL );
2154 }
2155 
2156 
2157