xref: /aoo41x/main/sc/source/core/data/olinetab.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 // System - Includes -----------------------------------------------------
32 
33 
34 
35 #include <tools/debug.hxx>
36 #include <limits.h>
37 
38 // INCLUDE ---------------------------------------------------------------
39 
40 #include "olinetab.hxx"
41 #include "global.hxx"
42 #include "rechead.hxx"
43 #include "address.hxx"
44 #include "table.hxx"
45 
46 //------------------------------------------------------------------------
47 
48 ScOutlineEntry::ScOutlineEntry( SCCOLROW nNewStart, SCCOLROW nNewSize, bool bNewHidden ) :
49     nStart  ( nNewStart ),
50     nSize   ( nNewSize ),
51     bHidden ( bNewHidden ),
52     bVisible( sal_True )
53 {
54 }
55 
56 ScOutlineEntry::ScOutlineEntry( const ScOutlineEntry& rEntry ) :
57     ScDataObject(),
58     nStart  ( rEntry.nStart ),
59     nSize   ( rEntry.nSize ),
60     bHidden ( rEntry.bHidden ),
61     bVisible( rEntry.bVisible )
62 {
63 }
64 
65 ScDataObject* ScOutlineEntry::Clone() const
66 {
67     return new ScOutlineEntry( *this );
68 }
69 
70 void ScOutlineEntry::Move( SCsCOLROW nDelta )
71 {
72     SCCOLROW nNewPos = nStart + nDelta;
73     if (nNewPos<0)
74     {
75         DBG_ERROR("OutlineEntry < 0");
76         nNewPos = 0;
77     }
78     nStart = nNewPos;
79 }
80 
81 void ScOutlineEntry::SetSize( SCSIZE nNewSize )
82 {
83     if (nNewSize>0)
84         nSize = nNewSize;
85     else
86     {
87         DBG_ERROR("ScOutlineEntry Size == 0");
88     }
89 }
90 
91 void ScOutlineEntry::SetPosSize( SCCOLROW nNewPos, SCSIZE nNewSize )
92 {
93     nStart = nNewPos;
94     SetSize( nNewSize );
95 }
96 
97 void ScOutlineEntry::SetHidden( bool bNewHidden )
98 {
99     bHidden = bNewHidden;
100 }
101 
102 void ScOutlineEntry::SetVisible( bool bNewVisible )
103 {
104     bVisible = bNewVisible;
105 }
106 
107 //------------------------------------------------------------------------
108 
109 ScOutlineCollection::ScOutlineCollection() :
110     ScSortedCollection( 4,4,sal_False )
111 {
112 }
113 
114 inline short IntCompare( SCCOLROW nX, SCCOLROW nY )
115 {
116     if ( nX==nY ) return 0;
117     else if ( nX<nY ) return -1;
118     else return 1;
119 }
120 
121 short ScOutlineCollection::Compare(ScDataObject* pKey1, ScDataObject* pKey2) const
122 {
123     return IntCompare( ((ScOutlineEntry*)pKey1)->GetStart(),
124                         ((ScOutlineEntry*)pKey2)->GetStart() );
125 }
126 
127 sal_uInt16 ScOutlineCollection::FindStart( SCCOLROW nMinStart )
128 {
129     //!                 binaer suchen ?
130 
131     sal_uInt16 nPos = 0;
132     sal_uInt16 nLocalCount = GetCount();
133     while ( (nPos<nLocalCount) ? (((ScOutlineEntry*)At(nPos))->GetStart() < nMinStart) : sal_False )
134         ++nPos;
135 
136     return nPos;
137 }
138 
139 //------------------------------------------------------------------------
140 
141 ScOutlineArray::ScOutlineArray() :
142     nDepth( 0 )
143 {
144 }
145 
146 ScOutlineArray::ScOutlineArray( const ScOutlineArray& rArray ) :
147     nDepth( rArray.nDepth )
148 {
149     for (sal_uInt16 nLevel=0; nLevel<nDepth; nLevel++)
150     {
151         sal_uInt16 nCount = rArray.aCollections[nLevel].GetCount();
152         for (sal_uInt16 nEntry=0; nEntry<nCount; nEntry++)
153         {
154             ScOutlineEntry* pEntry = (ScOutlineEntry*) rArray.aCollections[nLevel].At(nEntry);
155             aCollections[nLevel].Insert( new ScOutlineEntry( *pEntry ) );
156         }
157     }
158 }
159 
160 void ScOutlineArray::FindEntry( SCCOLROW nSearchPos, sal_uInt16& rFindLevel, sal_uInt16& rFindIndex,
161                                 sal_uInt16 nMaxLevel )
162 {
163     rFindLevel = rFindIndex = 0;
164 
165     if (nMaxLevel > nDepth)
166         nMaxLevel = nDepth;
167 
168     for (sal_uInt16 nLevel=0; nLevel<nMaxLevel; nLevel++)               //! rueckwaerts suchen ?
169     {
170         ScOutlineCollection* pCollect = &aCollections[nLevel];
171         sal_uInt16 nCount = pCollect->GetCount();
172         for (sal_uInt16 i=0; i<nCount; i++)
173         {
174             ScOutlineEntry* pEntry = (ScOutlineEntry*) pCollect->At(i);
175             if ( pEntry->GetStart() <= nSearchPos && pEntry->GetEnd() >= nSearchPos )
176             {
177                 rFindLevel = nLevel + 1;            // naechster Level (zum Einfuegen)
178                 rFindIndex = i;
179             }
180         }
181     }
182 }
183 
184 sal_Bool ScOutlineArray::Insert( SCCOLROW nStartCol, SCCOLROW nEndCol, sal_Bool& rSizeChanged,
185                                 sal_Bool bHidden, sal_Bool bVisible )
186 {
187     rSizeChanged = sal_False;
188 
189     sal_uInt16 nStartLevel;
190     sal_uInt16 nStartIndex;
191     sal_uInt16 nEndLevel;
192     sal_uInt16 nEndIndex;
193     sal_Bool bFound = sal_False;
194 
195     sal_Bool bCont;
196     sal_uInt16 nFindMax;
197     FindEntry( nStartCol, nStartLevel, nStartIndex );       // nLevel = neuer Level (alter+1) !!!
198     FindEntry( nEndCol, nEndLevel, nEndIndex );
199     nFindMax = Max(nStartLevel,nEndLevel);
200     do
201     {
202         bCont = sal_False;
203 
204         if ( nStartLevel == nEndLevel && nStartIndex == nEndIndex && nStartLevel < SC_OL_MAXDEPTH )
205             bFound = sal_True;
206 
207         if (!bFound)
208         {
209             if (nFindMax>0)
210             {
211                 --nFindMax;
212                 if (nStartLevel)
213                     if ( ((ScOutlineEntry*)aCollections[nStartLevel-1].At(nStartIndex))->
214                                 GetStart() == nStartCol )
215                         FindEntry( nStartCol, nStartLevel, nStartIndex, nFindMax );
216                 if (nEndLevel)
217                     if ( ((ScOutlineEntry*)aCollections[nEndLevel-1].At(nEndIndex))->
218                                 GetEnd() == nEndCol )
219                         FindEntry( nEndCol, nEndLevel, nEndIndex, nFindMax );
220                 bCont = sal_True;
221             }
222         }
223     }
224     while ( !bFound && bCont );
225 
226     if (!bFound)
227         return sal_False;
228 
229     sal_uInt16 nLevel = nStartLevel;
230 
231     //  untere verschieben
232 
233     sal_Bool bNeedSize = sal_False;
234     for ( short nMoveLevel = nDepth-1; nMoveLevel >= (short) nLevel; nMoveLevel-- )
235     {
236         sal_uInt16 nCount = aCollections[nMoveLevel].GetCount();
237         sal_Bool bMoved = sal_False;
238         for ( sal_uInt16 i=0; i<nCount; i += bMoved ? 0 : 1 )
239         {
240             ScOutlineEntry* pEntry = (ScOutlineEntry*) aCollections[nMoveLevel].At(i);
241             SCCOLROW nEntryStart = pEntry->GetStart();
242             if ( nEntryStart >= nStartCol && nEntryStart <= nEndCol )
243             {
244                 if (nMoveLevel >= SC_OL_MAXDEPTH - 1)
245                 {
246                     rSizeChanged = sal_False;               // kein Platz
247                     return sal_False;
248                 }
249                 aCollections[nMoveLevel+1].Insert( new ScOutlineEntry( *pEntry ) );
250                 aCollections[nMoveLevel].AtFree( i );
251                 nCount = aCollections[nMoveLevel].GetCount();
252                 bMoved = sal_True;
253                 if (nMoveLevel == (short) nDepth - 1)
254                     bNeedSize = sal_True;
255             }
256             else
257                 bMoved = sal_False;
258         }
259     }
260 
261     if (bNeedSize)
262     {
263         ++nDepth;
264         rSizeChanged = sal_True;
265     }
266 
267     if (nDepth <= nLevel)
268     {
269         nDepth = nLevel+1;
270         rSizeChanged = sal_True;
271     }
272 
273 /*          nicht zusammenfassen!
274 
275     //  zusammenfassen
276 
277     sal_uInt16 nCount = aCollections[nLevel].GetCount();
278     sal_uInt16 nIndex;
279     bFound = sal_False;
280     for ( nIndex=0; nIndex<nCount && !bFound; nIndex++ )
281     {
282         if ( ((ScOutlineEntry*) aCollections[nLevel].At(nIndex))->GetEnd() + 1 == nStartCol )
283         {
284             nStartCol = ((ScOutlineEntry*) aCollections[nLevel].At(nIndex))->GetStart();
285             aCollections[nLevel].AtFree(nIndex);
286             nCount = aCollections[nLevel].GetCount();       // Daten geaendert
287             bFound = sal_True;
288         }
289     }
290 
291     bFound = sal_False;
292     for ( nIndex=0; nIndex<nCount && !bFound; nIndex++ )
293     {
294         if ( ((ScOutlineEntry*) aCollections[nLevel].At(nIndex))->GetStart() == nEndCol + 1 )
295         {
296             nEndCol = ((ScOutlineEntry*) aCollections[nLevel].At(nIndex))->GetEnd();
297             aCollections[nLevel].AtFree(nIndex);
298             bFound = sal_True;
299         }
300     }
301 */
302     ScOutlineEntry* pNewEntry = new ScOutlineEntry( nStartCol, nEndCol+1-nStartCol, bHidden );
303     pNewEntry->SetVisible( bVisible );
304     aCollections[nLevel].Insert( pNewEntry );
305 
306     return sal_True;
307 }
308 
309 sal_Bool ScOutlineArray::FindTouchedLevel( SCCOLROW nBlockStart, SCCOLROW nBlockEnd, sal_uInt16& rFindLevel ) const
310 {
311     sal_Bool bFound = sal_False;
312     rFindLevel = 0;
313 
314     for (sal_uInt16 nLevel=0; nLevel<nDepth; nLevel++)
315     {
316         const ScOutlineCollection* pCollect = &aCollections[nLevel];
317         sal_uInt16 nCount = pCollect->GetCount();
318         for (sal_uInt16 i=0; i<nCount; i++)
319         {
320             ScOutlineEntry* pEntry = (ScOutlineEntry*) pCollect->At(i);
321             SCCOLROW nStart = pEntry->GetStart();
322             SCCOLROW nEnd   = pEntry->GetEnd();
323 
324             if ( ( nBlockStart>=nStart && nBlockStart<=nEnd ) ||
325                  ( nBlockEnd  >=nStart && nBlockEnd  <=nEnd ) )
326             {
327                 rFindLevel = nLevel;            // wirklicher Level
328                 bFound = sal_True;
329             }
330         }
331     }
332 
333     return bFound;
334 }
335 
336 void ScOutlineArray::RemoveSub( SCCOLROW nStartPos, SCCOLROW nEndPos, sal_uInt16 nLevel )
337 {
338     if ( nLevel >= nDepth )
339         return;
340     ScOutlineCollection* pCollect = &aCollections[nLevel];
341     sal_uInt16 nCount = pCollect->GetCount();
342     sal_Bool bFound = sal_False;
343     for ( sal_uInt16 i=0; i<nCount; i += ( bFound ? 0 : 1 ) )
344     {
345         bFound = sal_False;
346         ScOutlineEntry* pEntry = (ScOutlineEntry*) pCollect->At(i);
347         SCCOLROW nStart = pEntry->GetStart();
348         SCCOLROW nEnd   = pEntry->GetEnd();
349 
350         if ( nStart>=nStartPos && nEnd<=nEndPos )
351         {
352             RemoveSub( nStart, nEnd, nLevel+1 );
353             pCollect->AtFree(i);
354             nCount = pCollect->GetCount();
355             bFound = sal_True;
356         }
357     }
358 }
359 
360 void ScOutlineArray::PromoteSub( SCCOLROW nStartPos, SCCOLROW nEndPos, sal_uInt16 nStartLevel )
361 {
362     if (nStartLevel==0)
363     {
364         DBG_ERROR("PromoteSub mit Level 0");
365         return;
366     }
367 
368     for (sal_uInt16 nLevel = nStartLevel; nLevel < nDepth; nLevel++)
369     {
370         ScOutlineCollection* pCollect = &aCollections[nLevel];
371         sal_uInt16 nCount = pCollect->GetCount();
372         sal_Bool bFound = sal_False;
373         for ( sal_uInt16 i=0; i<nCount; i += ( bFound ? 0 : 1 ) )
374         {
375             bFound = sal_False;
376             ScOutlineEntry* pEntry = (ScOutlineEntry*) pCollect->At(i);
377             SCCOLROW nStart = pEntry->GetStart();
378             SCCOLROW nEnd   = pEntry->GetEnd();
379 
380             if ( nStart>=nStartPos && nEnd<=nEndPos )
381             {
382                 aCollections[nLevel-1].Insert( new ScOutlineEntry( *pEntry ) );
383                 pCollect->AtFree(i);
384                 nCount = pCollect->GetCount();
385                 bFound = sal_True;
386             }
387         }
388     }
389 }
390 
391 sal_Bool ScOutlineArray::DecDepth()                         // nDepth auf leere Levels anpassen
392 {
393     sal_Bool bChanged = sal_False;
394     sal_Bool bCont;
395     do
396     {
397         bCont = sal_False;
398         if (nDepth)
399             if (aCollections[nDepth-1].GetCount() == 0)
400             {
401                 --nDepth;
402                 bChanged = sal_True;
403                 bCont = sal_True;
404             }
405     }
406     while (bCont);
407     return bChanged;
408 }
409 
410 sal_Bool ScOutlineArray::Remove( SCCOLROW nBlockStart, SCCOLROW nBlockEnd, sal_Bool& rSizeChanged )
411 {
412     sal_uInt16 nLevel;
413     FindTouchedLevel( nBlockStart, nBlockEnd, nLevel );
414 
415     ScOutlineCollection* pCollect = &aCollections[nLevel];
416     sal_uInt16 nCount = pCollect->GetCount();
417     sal_Bool bFound = sal_False;
418     sal_Bool bAny = sal_False;
419     for ( sal_uInt16 i=0; i<nCount; i += ( bFound ? 0 : 1 ) )
420     {
421         bFound = sal_False;
422         ScOutlineEntry* pEntry = (ScOutlineEntry*) pCollect->At(i);
423         SCCOLROW nStart = pEntry->GetStart();
424         SCCOLROW nEnd   = pEntry->GetEnd();
425 
426         if ( nBlockStart<=nEnd && nBlockEnd>=nStart )
427         {
428 //          RemoveSub( nStart, nEnd, nLevel+1 );
429             pCollect->AtFree(i);
430             PromoteSub( nStart, nEnd, nLevel+1 );
431             nCount = pCollect->GetCount();
432             i = pCollect->FindStart( nEnd+1 );
433             bFound = sal_True;
434             bAny = sal_True;
435         }
436     }
437 
438     if (bAny)                                   // Depth anpassen
439         if (DecDepth())
440             rSizeChanged = sal_True;
441 
442     return bAny;
443 }
444 
445 ScOutlineEntry* ScOutlineArray::GetEntry( sal_uInt16 nLevel, sal_uInt16 nIndex ) const
446 {
447     return (ScOutlineEntry*)((nLevel < nDepth) ? aCollections[nLevel].At(nIndex) : NULL);
448 }
449 
450 sal_uInt16 ScOutlineArray::GetCount( sal_uInt16 nLevel ) const
451 {
452     return (nLevel < nDepth) ? aCollections[nLevel].GetCount() : 0;
453 }
454 
455 ScOutlineEntry* ScOutlineArray::GetEntryByPos( sal_uInt16 nLevel, SCCOLROW nPos ) const
456 {
457     sal_uInt16          nCount  = GetCount( nLevel );
458     ScOutlineEntry* pEntry;
459 
460     for (sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++)
461     {
462         pEntry = GetEntry( nLevel, nIndex );
463         if ((pEntry->GetStart() <= nPos) && (nPos <= pEntry->GetEnd()))
464             return pEntry;
465     }
466     return NULL;
467 }
468 
469 sal_Bool ScOutlineArray::GetEntryIndex( sal_uInt16 nLevel, SCCOLROW nPos, sal_uInt16& rnIndex ) const
470 {
471     // found entry contains passed position
472     sal_uInt16 nCount  = GetCount( nLevel );
473     for ( rnIndex = 0; rnIndex < nCount; ++rnIndex )
474     {
475         const ScOutlineEntry* pEntry = GetEntry( nLevel, rnIndex );
476         if ( (pEntry->GetStart() <= nPos) && (nPos <= pEntry->GetEnd()) )
477             return sal_True;
478     }
479     return sal_False;
480 }
481 
482 sal_Bool ScOutlineArray::GetEntryIndexInRange(
483         sal_uInt16 nLevel, SCCOLROW nBlockStart, SCCOLROW nBlockEnd, sal_uInt16& rnIndex ) const
484 {
485     // found entry will be completely inside of passed range
486     sal_uInt16 nCount  = GetCount( nLevel );
487     for ( rnIndex = 0; rnIndex < nCount; ++rnIndex )
488     {
489         const ScOutlineEntry* pEntry = GetEntry( nLevel, rnIndex );
490         if ( (nBlockStart <= pEntry->GetStart()) && (pEntry->GetEnd() <= nBlockEnd) )
491             return sal_True;
492     }
493     return sal_False;
494 }
495 
496 void ScOutlineArray::SetVisibleBelow( sal_uInt16 nLevel, sal_uInt16 nEntry, sal_Bool bValue, sal_Bool bSkipHidden )
497 {
498     ScOutlineEntry* pEntry = GetEntry( nLevel, nEntry );
499     if( pEntry )
500     {
501         SCCOLROW nStart = pEntry->GetStart();
502         SCCOLROW nEnd   = pEntry->GetEnd();
503 
504         for (sal_uInt16 nSubLevel=nLevel+1; nSubLevel<nDepth; nSubLevel++)
505         {
506             sal_uInt16 i = 0;
507             pEntry = (ScOutlineEntry*) aCollections[nSubLevel].At(i);
508             while (pEntry)
509             {
510                 if (pEntry->GetStart() >= nStart && pEntry->GetEnd() <= nEnd)
511                 {
512                     pEntry->SetVisible(bValue);
513 
514                     if (bSkipHidden)
515                         if (!pEntry->IsHidden())
516                             SetVisibleBelow( nSubLevel, i, bValue, sal_True );
517                 }
518 
519                 ++i;
520                 pEntry = (ScOutlineEntry*) aCollections[nSubLevel].At(i);
521             }
522 
523             if (bSkipHidden)
524                 nSubLevel = nDepth;             // Abbruch
525         }
526     }
527 }
528 
529 void ScOutlineArray::GetRange( SCCOLROW& rStart, SCCOLROW& rEnd ) const
530 {
531     sal_uInt16 nCount = aCollections[0].GetCount();
532     if (nCount)
533     {
534         rStart = ((ScOutlineEntry*) aCollections[0].At(0))->GetStart();
535         rEnd   = ((ScOutlineEntry*) aCollections[0].At(nCount-1))->GetEnd();
536     }
537     else
538         rStart = rEnd = 0;
539 }
540 
541 void ScOutlineArray::ExtendBlock( sal_uInt16 nLevel, SCCOLROW& rBlkStart, SCCOLROW& rBlkEnd )
542 {
543     sal_uInt16  nCount;
544     SCCOLROW    nStart;
545     SCCOLROW    nEnd;
546     sal_uInt16  i;
547     ScOutlineEntry* pEntry;
548 
549     nCount = GetCount(nLevel);
550     for ( i=0; i<nCount; i++ )
551     {
552         pEntry = (ScOutlineEntry*) aCollections[nLevel].At(i);
553         nStart = pEntry->GetStart();
554         nEnd   = pEntry->GetEnd();
555 
556         if ( rBlkStart<=nEnd && rBlkEnd>=nStart )
557         {
558             if (nStart<rBlkStart) rBlkStart = nStart;
559             if (nEnd>rBlkEnd) rBlkEnd = nEnd;
560         }
561     }
562 }
563 
564 sal_Bool ScOutlineArray::TestInsertSpace( SCSIZE nSize, SCCOLROW nMaxVal ) const
565 {
566     sal_uInt16 nCount = aCollections[0].GetCount();
567     if (nCount)
568     {
569         SCCOLROW nEnd = ((ScOutlineEntry*) aCollections[0].At(nCount-1))->GetEnd();
570         return ( sal::static_int_cast<SCCOLROW>(nEnd+nSize) <= nMaxVal );
571     }
572 
573     return sal_True;
574 }
575 
576 void ScOutlineArray::InsertSpace( SCCOLROW nStartPos, SCSIZE nSize )
577 {
578     ScSubOutlineIterator aIter( this );
579     ScOutlineEntry* pEntry;
580     while((pEntry=aIter.GetNext())!=NULL)
581     {
582         if ( pEntry->GetStart() >= nStartPos )
583             pEntry->Move(static_cast<SCsCOLROW>(nSize));
584         else
585         {
586             SCCOLROW nEnd = pEntry->GetEnd();
587             //  immer erweitern, wenn innerhalb der Gruppe eingefuegt
588             //  beim Einfuegen am Ende nur, wenn die Gruppe nicht ausgeblendet ist
589             if ( nEnd >= nStartPos || ( nEnd+1 >= nStartPos && !pEntry->IsHidden() ) )
590             {
591                 SCSIZE nEntrySize = pEntry->GetSize();
592                 nEntrySize += nSize;
593                 pEntry->SetSize( nEntrySize );
594             }
595         }
596     }
597 }
598 
599 sal_Bool ScOutlineArray::DeleteSpace( SCCOLROW nStartPos, SCSIZE nSize )
600 {
601     SCCOLROW nEndPos = nStartPos + nSize - 1;
602     sal_Bool bNeedSave = sal_False;                         // Original fuer Undo benoetigt?
603     sal_Bool bChanged = sal_False;                          // fuer Test auf Level
604 
605     ScSubOutlineIterator aIter( this );
606     ScOutlineEntry* pEntry;
607     while((pEntry=aIter.GetNext())!=NULL)
608     {
609         SCCOLROW nEntryStart = pEntry->GetStart();
610         SCCOLROW nEntryEnd   = pEntry->GetEnd();
611         SCSIZE nEntrySize    = pEntry->GetSize();
612 
613         if ( nEntryEnd >= nStartPos )
614         {
615             if ( nEntryStart > nEndPos )                                        // rechts
616                 pEntry->Move(-(static_cast<SCsCOLROW>(nSize)));
617             else if ( nEntryStart < nStartPos && nEntryEnd >= nEndPos )         // aussen
618                 pEntry->SetSize( nEntrySize-nSize );
619             else
620             {
621                 bNeedSave = sal_True;
622                 if ( nEntryStart >= nStartPos && nEntryEnd <= nEndPos )             // innen
623                 {
624                     aIter.DeleteLast();
625                     bChanged = sal_True;
626                 }
627                 else if ( nEntryStart >= nStartPos )                                // rechts ueber
628                     pEntry->SetPosSize( nStartPos, static_cast<SCSIZE>(nEntryEnd-nEndPos) );
629                 else                                                                // links ueber
630                     pEntry->SetSize( static_cast<SCSIZE>(nStartPos-nEntryStart) );
631             }
632         }
633     }
634 
635     if (bChanged)
636         DecDepth();
637 
638     return bNeedSave;
639 }
640 
641 bool ScOutlineArray::ManualAction( SCCOLROW nStartPos, SCCOLROW nEndPos, bool bShow, ScTable& rTable, bool bCol )
642 {
643     bool bModified = false;
644     ScSubOutlineIterator aIter( this );
645     ScOutlineEntry* pEntry;
646     while((pEntry=aIter.GetNext())!=NULL)
647     {
648         SCCOLROW nEntryStart = pEntry->GetStart();
649         SCCOLROW nEntryEnd   = pEntry->GetEnd();
650 
651         if (nEntryEnd>=nStartPos && nEntryStart<=nEndPos)
652         {
653             if ( pEntry->IsHidden() == bShow )
654             {
655                 //  #i12341# hide if all columns/rows are hidden, show if at least one
656                 //  is visible
657                 SCCOLROW nEnd = rTable.LastHiddenColRow(nEntryStart, bCol);
658                 bool bAllHidden = (nEntryEnd <= nEnd && nEnd <
659                         ::std::numeric_limits<SCCOLROW>::max());
660 
661                 bool bToggle = ( bShow != bAllHidden );
662                 if ( bToggle )
663                 {
664                     pEntry->SetHidden( !bShow );
665                     SetVisibleBelow( aIter.LastLevel(), aIter.LastEntry(), bShow, bShow );
666                     bModified = true;
667                 }
668             }
669         }
670     }
671     return bModified;
672 }
673 
674 void ScOutlineArray::RemoveAll()
675 {
676     for (sal_uInt16 nLevel=0; nLevel<nDepth; nLevel++)
677         aCollections[nLevel].FreeAll();
678 
679     nDepth = 0;
680 }
681 
682 //------------------------------------------------------------------------
683 
684 ScOutlineTable::ScOutlineTable()
685 {
686 }
687 
688 ScOutlineTable::ScOutlineTable( const ScOutlineTable& rOutline ) :
689     aColOutline( rOutline.aColOutline ),
690     aRowOutline( rOutline.aRowOutline )
691 {
692 }
693 
694 sal_Bool ScOutlineTable::TestInsertCol( SCSIZE nSize )
695 {
696     return aColOutline.TestInsertSpace( nSize, MAXCOL );
697 }
698 
699 void ScOutlineTable::InsertCol( SCCOL nStartCol, SCSIZE nSize )
700 {
701     aColOutline.InsertSpace( nStartCol, nSize );
702 }
703 
704 sal_Bool ScOutlineTable::DeleteCol( SCCOL nStartCol, SCSIZE nSize )
705 {
706     return aColOutline.DeleteSpace( nStartCol, nSize );
707 }
708 
709 sal_Bool ScOutlineTable::TestInsertRow( SCSIZE nSize )
710 {
711     return aRowOutline.TestInsertSpace( nSize, MAXROW );
712 }
713 
714 void ScOutlineTable::InsertRow( SCROW nStartRow, SCSIZE nSize )
715 {
716     aRowOutline.InsertSpace( nStartRow, nSize );
717 }
718 
719 sal_Bool ScOutlineTable::DeleteRow( SCROW nStartRow, SCSIZE nSize )
720 {
721     return aRowOutline.DeleteSpace( nStartRow, nSize );
722 }
723 
724 //------------------------------------------------------------------------
725 
726 ScSubOutlineIterator::ScSubOutlineIterator( ScOutlineArray* pOutlineArray ) :
727         pArray( pOutlineArray ),
728         nStart( 0 ),
729         nEnd( SCCOLROW_MAX ),                           // alle durchgehen
730         nSubLevel( 0 ),
731         nSubEntry( 0 )
732 {
733     nDepth = pArray->nDepth;
734 }
735 
736 ScSubOutlineIterator::ScSubOutlineIterator( ScOutlineArray* pOutlineArray,
737                                             sal_uInt16 nLevel, sal_uInt16 nEntry ) :
738         pArray( pOutlineArray )
739 {
740     ScOutlineEntry* pEntry = (ScOutlineEntry*) pArray->aCollections[nLevel].At(nEntry);
741     nStart = pEntry->GetStart();
742     nEnd   = pEntry->GetEnd();
743     nSubLevel = nLevel + 1;
744     nSubEntry = 0;
745     nDepth = pArray->nDepth;
746 }
747 
748 ScOutlineEntry* ScSubOutlineIterator::GetNext()
749 {
750     ScOutlineEntry* pEntry;
751     sal_Bool bFound = sal_False;
752     do
753     {
754         if (nSubLevel >= nDepth)
755             return NULL;
756 
757         pEntry = (ScOutlineEntry*) pArray->aCollections[nSubLevel].At(nSubEntry);
758         if (!pEntry)
759         {
760             nSubEntry = 0;
761             ++nSubLevel;
762         }
763         else
764         {
765             if ( pEntry->GetStart() >= nStart && pEntry->GetEnd() <= nEnd )
766                 bFound = sal_True;
767             ++nSubEntry;
768         }
769     }
770     while (!bFound);
771     return pEntry;                  // nSubLevel gueltig, wenn pEntry != 0
772 }
773 
774 sal_uInt16 ScSubOutlineIterator::LastLevel() const
775 {
776     return nSubLevel;
777 }
778 
779 sal_uInt16 ScSubOutlineIterator::LastEntry() const
780 {
781     if (nSubEntry == 0)
782     {
783         DBG_ERROR("ScSubOutlineIterator::LastEntry vor GetNext");
784         return 0;
785     }
786     return nSubEntry-1;
787 }
788 
789 void ScSubOutlineIterator::DeleteLast()
790 {
791     if (nSubLevel >= nDepth)
792     {
793         DBG_ERROR("ScSubOutlineIterator::DeleteLast nach Ende");
794         return;
795     }
796     if (nSubEntry == 0)
797     {
798         DBG_ERROR("ScSubOutlineIterator::DeleteLast vor GetNext");
799         return;
800     }
801 
802     --nSubEntry;
803     pArray->aCollections[nSubLevel].AtFree(nSubEntry);
804 }
805 
806 
807