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