xref: /AOO41X/main/sc/source/core/data/table1.cxx (revision 707fc0d4d52eb4f69d89a98ffec6918ca5de6326)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 
27 // INCLUDE ---------------------------------------------------------------
28 
29 #include "scitems.hxx"
30 #include <svx/algitem.hxx>
31 #include <unotools/textsearch.hxx>
32 #include <sfx2/objsh.hxx>
33 
34 #include "attrib.hxx"
35 #include "patattr.hxx"
36 #include "cell.hxx"
37 #include "table.hxx"
38 #include "document.hxx"
39 #include "drwlayer.hxx"
40 #include "olinetab.hxx"
41 #include "stlsheet.hxx"
42 #include "global.hxx"
43 #include "globstr.hrc"
44 #include "refupdat.hxx"
45 #include "markdata.hxx"
46 #include "progress.hxx"
47 #include "hints.hxx"        // fuer Paint-Broadcast
48 #include "prnsave.hxx"
49 #include "tabprotection.hxx"
50 #include "sheetevents.hxx"
51 #include "segmenttree.hxx"
52 
53 // -----------------------------------------------------------------------
54 
55 ScTable::ScTable( ScDocument* pDoc, SCTAB nNewTab, const String& rNewName,
56                     sal_Bool bColInfo, sal_Bool bRowInfo ) :
57     aName( rNewName ),
58     aCodeName( rNewName ),
59     bScenario( sal_False ),
60     bLayoutRTL( sal_False ),
61     bLoadingRTL( sal_False ),
62     nLinkMode( 0 ),
63     aPageStyle( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) ),
64     bPageSizeValid( sal_False ),
65     nRepeatStartX( SCCOL_REPEAT_NONE ),
66     nRepeatStartY( SCROW_REPEAT_NONE ),
67     pTabProtection( NULL ),
68     pColWidth( NULL ),
69     mpRowHeights( static_cast<ScFlatUInt16RowSegments*>(NULL) ),
70     pColFlags( NULL ),
71     pRowFlags( NULL ),
72     mpHiddenCols(new ScFlatBoolColSegments),
73     mpHiddenRows(new ScFlatBoolRowSegments),
74     mpFilteredCols(new ScFlatBoolColSegments),
75     mpFilteredRows(new ScFlatBoolRowSegments),
76     pOutlineTable( NULL ),
77     pSheetEvents( NULL ),
78     bTableAreaValid( sal_False ),
79     bVisible( sal_True ),
80     bStreamValid( sal_False ),
81     bPendingRowHeights( sal_False ),
82     bCalcNotification( sal_False ),
83     nTab( nNewTab ),
84     nRecalcLvl( 0 ),
85     pDocument( pDoc ),
86     pSearchParam( NULL ),
87     pSearchText ( NULL ),
88     pSortCollator( NULL ),
89     bPrintEntireSheet( sal_False ),
90     pRepeatColRange( NULL ),
91     pRepeatRowRange( NULL ),
92     nLockCount( 0 ),
93     pScenarioRanges( NULL ),
94     aScenarioColor( COL_LIGHTGRAY ),
95     aTabBgColor( COL_AUTO ),
96     nScenarioFlags( 0 ),
97     bActiveScenario( sal_False ),
98     mbPageBreaksValid(false)
99 {
100 
101     if (bColInfo)
102     {
103         pColWidth  = new sal_uInt16[ MAXCOL+1 ];
104         pColFlags  = new sal_uInt8[ MAXCOL+1 ];
105 
106         for (SCCOL i=0; i<=MAXCOL; i++)
107         {
108             pColWidth[i] = STD_COL_WIDTH;
109             pColFlags[i] = 0;
110         }
111     }
112 
113     if (bRowInfo)
114     {
115         mpRowHeights.reset(new ScFlatUInt16RowSegments(ScGlobal::nStdRowHeight));
116         pRowFlags  = new ScBitMaskCompressedArray< SCROW, sal_uInt8>( MAXROW, 0);
117     }
118 
119     if ( pDocument->IsDocVisible() )
120     {
121         //  when a sheet is added to a visible document,
122         //  initialize its RTL flag from the system locale
123         bLayoutRTL = ScGlobal::IsSystemRTL();
124     }
125 
126     ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
127     if (pDrawLayer)
128     {
129         if ( pDrawLayer->ScAddPage( nTab ) )    // sal_False (not inserted) during Undo
130         {
131             pDrawLayer->ScRenamePage( nTab, aName );
132             sal_uLong nx = (sal_uLong) ((double) (MAXCOL+1) * STD_COL_WIDTH           * HMM_PER_TWIPS );
133             sal_uLong ny = (sal_uLong) ((double) (MAXROW+1) * ScGlobal::nStdRowHeight * HMM_PER_TWIPS );
134             pDrawLayer->SetPageSize( static_cast<sal_uInt16>(nTab), Size( nx, ny ), false );
135         }
136     }
137 
138     for (SCCOL k=0; k<=MAXCOL; k++)
139         aCol[k].Init( k, nTab, pDocument );
140 }
141 
142 ScTable::~ScTable()
143 {
144     if (!pDocument->IsInDtorClear())
145     {
146         //  nicht im dtor die Pages in der falschen Reihenfolge loeschen
147         //  (nTab stimmt dann als Page-Number nicht!)
148         //  In ScDocument::Clear wird hinterher per Clear am Draw Layer alles geloescht.
149 
150         ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
151         if (pDrawLayer)
152             pDrawLayer->ScRemovePage( nTab );
153     }
154 
155     delete[] pColWidth;
156     delete[] pColFlags;
157     delete pRowFlags;
158     delete pSheetEvents;
159     delete pOutlineTable;
160     delete pSearchParam;
161     delete pSearchText;
162     delete pRepeatColRange;
163     delete pRepeatRowRange;
164     delete pScenarioRanges;
165     DestroySortCollator();
166 }
167 
168 void ScTable::GetName( String& rName ) const
169 {
170     rName = aName;
171 }
172 
173 void ScTable::SetName( const String& rNewName )
174 {
175     aName = rNewName;
176     aUpperName.Erase();         // invalidated if the name is changed
177 
178     // SetStreamValid is handled in ScDocument::RenameTab
179 }
180 
181 const String& ScTable::GetUpperName() const
182 {
183     if ( !aUpperName.Len() && aName.Len() )
184         aUpperName = ScGlobal::pCharClass->upper( aName );
185     return aUpperName;
186 }
187 
188 void ScTable::SetVisible( sal_Bool bVis )
189 {
190     if (bVisible != bVis && IsStreamValid())
191         SetStreamValid(sal_False);
192 
193     bVisible = bVis;
194 }
195 
196 void ScTable::SetStreamValid( sal_Bool bSet, sal_Bool bIgnoreLock )
197 {
198     if ( bIgnoreLock || !pDocument->IsStreamValidLocked() )
199         bStreamValid = bSet;
200 }
201 
202 void ScTable::SetPendingRowHeights( sal_Bool bSet )
203 {
204     bPendingRowHeights = bSet;
205 }
206 
207 void ScTable::SetLayoutRTL( sal_Bool bSet )
208 {
209     bLayoutRTL = bSet;
210 }
211 
212 void ScTable::SetLoadingRTL( sal_Bool bSet )
213 {
214     bLoadingRTL = bSet;
215 }
216 
217 const Color& ScTable::GetTabBgColor() const
218 {
219     return aTabBgColor;
220 }
221 
222 void ScTable::SetTabBgColor(const Color& rColor)
223 {
224     if (aTabBgColor != rColor)
225     {
226         // The tab color has changed.  Set this table 'modified'.
227         aTabBgColor = rColor;
228         if (IsStreamValid())
229             SetStreamValid(false);
230     }
231 }
232 
233 void ScTable::SetScenario( sal_Bool bFlag )
234 {
235     bScenario = bFlag;
236 }
237 
238 void ScTable::SetLink( sal_uInt8 nMode,
239                         const String& rDoc, const String& rFlt, const String& rOpt,
240                         const String& rTab, sal_uLong nRefreshDelay )
241 {
242     nLinkMode = nMode;
243     aLinkDoc = rDoc;        // Datei
244     aLinkFlt = rFlt;        // Filter
245     aLinkOpt = rOpt;        // Filter-Optionen
246     aLinkTab = rTab;        // Tabellenname in Quelldatei
247     nLinkRefreshDelay = nRefreshDelay;  // refresh delay in seconds, 0==off
248 
249     if (IsStreamValid())
250         SetStreamValid(sal_False);
251 }
252 
253 sal_uInt16 ScTable::GetOptimalColWidth( SCCOL nCol, OutputDevice* pDev,
254                                     double nPPTX, double nPPTY,
255                                     const Fraction& rZoomX, const Fraction& rZoomY,
256                                     sal_Bool bFormula, const ScMarkData* pMarkData,
257                                     sal_Bool bSimpleTextImport )
258 {
259     return aCol[nCol].GetOptimalColWidth( pDev, nPPTX, nPPTY, rZoomX, rZoomY,
260         bFormula, STD_COL_WIDTH - STD_EXTRA_WIDTH, pMarkData, bSimpleTextImport );
261 }
262 
263 long ScTable::GetNeededSize( SCCOL nCol, SCROW nRow,
264                                 OutputDevice* pDev,
265                                 double nPPTX, double nPPTY,
266                                 const Fraction& rZoomX, const Fraction& rZoomY,
267                                 sal_Bool bWidth, sal_Bool bTotalSize )
268 {
269     ScNeededSizeOptions aOptions;
270     aOptions.bSkipMerged = sal_False;       // zusammengefasste mitzaehlen
271     aOptions.bTotalSize  = bTotalSize;
272 
273     return aCol[nCol].GetNeededSize
274         ( nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, aOptions );
275 }
276 
277 sal_Bool ScTable::SetOptimalHeight( SCROW nStartRow, SCROW nEndRow, sal_uInt16 nExtra,
278                                 OutputDevice* pDev,
279                                 double nPPTX, double nPPTY,
280                                 const Fraction& rZoomX, const Fraction& rZoomY,
281                                 sal_Bool bForce, ScProgress* pOuterProgress, sal_uLong nProgressStart )
282 {
283     DBG_ASSERT( nExtra==0 || bForce, "autom. OptimalHeight mit Extra" );
284 
285     if ( !pDocument->IsAdjustHeightEnabled() )
286     {
287         return sal_False;
288     }
289 
290     sal_Bool    bChanged = sal_False;
291     SCSIZE  nCount = static_cast<SCSIZE>(nEndRow-nStartRow+1);
292 
293     ScProgress* pProgress = NULL;
294     if ( pOuterProgress )
295         pProgress = pOuterProgress;
296     else if ( nCount > 1 )
297         pProgress = new ScProgress( pDocument->GetDocumentShell(),
298                             ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), GetWeightedCount() );
299 
300     sal_uInt16* pHeight = new sal_uInt16[nCount];                   // Twips !
301     memset( pHeight, 0, sizeof(sal_uInt16) * nCount );
302 
303     //  zuerst einmal ueber den ganzen Bereich
304     //  (mit der letzten Spalte in der Hoffnung, dass die am ehesten noch auf
305     //   Standard formatiert ist)
306 
307     aCol[MAXCOL].GetOptimalHeight(
308             nStartRow, nEndRow, pHeight, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bForce, 0, 0 );
309 
310     //  daraus Standardhoehe suchen, die im unteren Bereich gilt
311 
312     sal_uInt16 nMinHeight = pHeight[nCount-1];
313     SCSIZE nPos = nCount-1;
314     while ( nPos && pHeight[nPos-1] >= nMinHeight )
315         --nPos;
316     SCROW nMinStart = nStartRow + nPos;
317 
318     sal_uLong nWeightedCount = 0;
319     for (SCCOL nCol=0; nCol<MAXCOL; nCol++)     // MAXCOL schon oben
320     {
321         aCol[nCol].GetOptimalHeight(
322             nStartRow, nEndRow, pHeight, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bForce,
323             nMinHeight, nMinStart );
324 
325         if (pProgress)
326         {
327             sal_uLong nWeight = aCol[nCol].GetWeightedCount();
328             if (nWeight)        // nochmal denselben Status muss auch nicht sein
329             {
330                 nWeightedCount += nWeight;
331                 pProgress->SetState( nWeightedCount + nProgressStart );
332             }
333         }
334     }
335 
336     IncRecalcLevel();       // #i116460# avoid problems with Excel files
337 
338     SCROW nRngStart = 0;
339     SCROW nRngEnd = 0;
340     sal_uInt16 nLast = 0;
341     for (SCSIZE i=0; i<nCount; i++)
342     {
343         size_t nIndex;
344         SCROW nRegionEndRow;
345         sal_uInt8 nRowFlag = pRowFlags->GetValue( nStartRow+i, nIndex, nRegionEndRow );
346         if ( nRegionEndRow > nEndRow )
347             nRegionEndRow = nEndRow;
348         SCSIZE nMoreRows = nRegionEndRow - ( nStartRow+i );     // additional equal rows after first
349 
350         bool bAutoSize = ((nRowFlag & CR_MANUALSIZE) == 0);
351         if ( bAutoSize || bForce )
352         {
353             if (nExtra)
354             {
355                 if (bAutoSize)
356                     pRowFlags->SetValue( nStartRow+i, nRegionEndRow, nRowFlag | CR_MANUALSIZE);
357             }
358             else if (!bAutoSize)
359                 pRowFlags->SetValue( nStartRow+i, nRegionEndRow, nRowFlag & ~CR_MANUALSIZE);
360 
361             for (SCSIZE nInner = i; nInner <= i + nMoreRows; ++nInner)
362             {
363                 if (nLast)
364                 {
365                     if (pHeight[nInner]+nExtra == nLast)
366                         nRngEnd = nStartRow+nInner;
367                     else
368                     {
369                         bChanged |= SetRowHeightRange( nRngStart, nRngEnd, nLast, nPPTX, nPPTY );
370                         nLast = 0;
371                     }
372                 }
373                 if (!nLast)
374                 {
375                     nLast = pHeight[nInner]+nExtra;
376                     nRngStart = nStartRow+nInner;
377                     nRngEnd = nStartRow+nInner;
378                 }
379             }
380         }
381         else
382         {
383             if (nLast)
384                 bChanged |= SetRowHeightRange( nRngStart, nRngEnd, nLast, nPPTX, nPPTY );
385             nLast = 0;
386         }
387         i += nMoreRows;     // already handled - skip
388     }
389     if (nLast)
390         bChanged |= SetRowHeightRange( nRngStart, nRngEnd, nLast, nPPTX, nPPTY );
391 
392     DecRecalcLevel();       // #i116460# avoid problems with Excel files
393 
394     delete[] pHeight;
395     if ( pProgress != pOuterProgress )
396         delete pProgress;
397 
398     return bChanged;
399 }
400 
401 sal_Bool ScTable::GetCellArea( SCCOL& rEndCol, SCROW& rEndRow ) const
402 {
403     sal_Bool bFound = sal_False;
404     SCCOL nMaxX = 0;
405     SCROW nMaxY = 0;
406     for (SCCOL i=0; i<=MAXCOL; i++)
407         if (!aCol[i].IsEmptyVisData(sal_True))      // sal_True = Notizen zaehlen auch
408         {
409             bFound = sal_True;
410             nMaxX = i;
411             SCROW nColY = aCol[i].GetLastVisDataPos(sal_True);
412             if (nColY > nMaxY)
413                 nMaxY = nColY;
414         }
415 
416     rEndCol = nMaxX;
417     rEndRow = nMaxY;
418     return bFound;
419 }
420 
421 sal_Bool ScTable::GetTableArea( SCCOL& rEndCol, SCROW& rEndRow ) const
422 {
423     sal_Bool bRet = sal_True;               //! merken?
424     if (!bTableAreaValid)
425     {
426         bRet = GetPrintArea( ((ScTable*)this)->nTableAreaX,
427                                 ((ScTable*)this)->nTableAreaY, sal_True );
428         ((ScTable*)this)->bTableAreaValid = sal_True;
429     }
430     rEndCol = nTableAreaX;
431     rEndRow = nTableAreaY;
432     return bRet;
433 }
434 
435 /*      vorher:
436 
437     sal_Bool bFound = sal_False;
438     SCCOL nMaxX = 0;
439     SCROW nMaxY = 0;
440     for (SCCOL i=0; i<=MAXCOL; i++)
441         if (!aCol[i].IsEmpty())
442         {
443             bFound = sal_True;
444             nMaxX = i;
445             SCCOL nColY = aCol[i].GetLastEntryPos();
446             if (nColY > nMaxY)
447                 nMaxY = nColY;
448         }
449 
450     rEndCol = nMaxX;
451     rEndRow = nMaxY;
452     return bFound;
453 */
454 
455 const SCCOL SC_COLUMNS_STOP = 30;
456 
457 sal_Bool ScTable::GetPrintArea( SCCOL& rEndCol, SCROW& rEndRow, sal_Bool bNotes ) const
458 {
459     sal_Bool bFound = sal_False;
460     SCCOL nMaxX = 0;
461     SCROW nMaxY = 0;
462     SCCOL i;
463 
464     for (i=0; i<=MAXCOL; i++)               // Daten testen
465         if (!aCol[i].IsEmptyVisData(bNotes))
466         {
467             bFound = sal_True;
468             if (i>nMaxX)
469                 nMaxX = i;
470             SCROW nColY = aCol[i].GetLastVisDataPos(bNotes);
471             if (nColY > nMaxY)
472                 nMaxY = nColY;
473         }
474 
475     SCCOL nMaxDataX = nMaxX;
476 
477     for (i=0; i<=MAXCOL; i++)               // Attribute testen
478     {
479         SCROW nLastRow;
480         if (aCol[i].GetLastVisibleAttr( nLastRow ))
481         {
482             bFound = sal_True;
483             nMaxX = i;
484             if (nLastRow > nMaxY)
485                 nMaxY = nLastRow;
486         }
487     }
488 
489     if (nMaxX == MAXCOL)                    // Attribute rechts weglassen
490     {
491         --nMaxX;
492         while ( nMaxX>0 && aCol[nMaxX].IsVisibleAttrEqual(aCol[nMaxX+1]) )
493             --nMaxX;
494     }
495 
496     if ( nMaxX < nMaxDataX )
497     {
498         nMaxX = nMaxDataX;
499     }
500     else if ( nMaxX > nMaxDataX )
501     {
502         SCCOL nAttrStartX = nMaxDataX + 1;
503         while ( nAttrStartX < MAXCOL )
504         {
505             SCCOL nAttrEndX = nAttrStartX;
506             while ( nAttrEndX < MAXCOL && aCol[nAttrStartX].IsVisibleAttrEqual(aCol[nAttrEndX+1]) )
507                 ++nAttrEndX;
508             if ( nAttrEndX + 1 - nAttrStartX >= SC_COLUMNS_STOP )
509             {
510                 // found equally-formatted columns behind data -> stop before these columns
511                 nMaxX = nAttrStartX - 1;
512 
513                 // also don't include default-formatted columns before that
514                 SCROW nDummyRow;
515                 while ( nMaxX > nMaxDataX && !aCol[nMaxX].GetLastVisibleAttr( nDummyRow ) )
516                     --nMaxX;
517                 break;
518             }
519             nAttrStartX = nAttrEndX + 1;
520         }
521     }
522 
523     rEndCol = nMaxX;
524     rEndRow = nMaxY;
525     return bFound;
526 }
527 
528 sal_Bool ScTable::GetPrintAreaHor( SCROW nStartRow, SCROW nEndRow,
529                                 SCCOL& rEndCol, sal_Bool /* bNotes */ ) const
530 {
531     sal_Bool bFound = sal_False;
532     SCCOL nMaxX = 0;
533     SCCOL i;
534 
535     for (i=0; i<=MAXCOL; i++)               // Attribute testen
536     {
537         if (aCol[i].HasVisibleAttrIn( nStartRow, nEndRow ))
538         {
539             bFound = sal_True;
540             nMaxX = i;
541         }
542     }
543 
544     if (nMaxX == MAXCOL)                    // Attribute rechts weglassen
545     {
546         --nMaxX;
547         while ( nMaxX>0 && aCol[nMaxX].IsVisibleAttrEqual(aCol[nMaxX+1], nStartRow, nEndRow) )
548             --nMaxX;
549     }
550 
551     for (i=0; i<=MAXCOL; i++)               // Daten testen
552     {
553         if (!aCol[i].IsEmptyBlock( nStartRow, nEndRow ))        //! bNotes ??????
554         {
555             bFound = sal_True;
556             if (i>nMaxX)
557                 nMaxX = i;
558         }
559     }
560 
561     rEndCol = nMaxX;
562     return bFound;
563 }
564 
565 sal_Bool ScTable::GetPrintAreaVer( SCCOL nStartCol, SCCOL nEndCol,
566                                 SCROW& rEndRow, sal_Bool bNotes ) const
567 {
568     sal_Bool bFound = sal_False;
569     SCROW nMaxY = 0;
570     SCCOL i;
571 
572     for (i=nStartCol; i<=nEndCol; i++)              // Attribute testen
573     {
574         SCROW nLastRow;
575         if (aCol[i].GetLastVisibleAttr( nLastRow ))
576         {
577             bFound = sal_True;
578             if (nLastRow > nMaxY)
579                 nMaxY = nLastRow;
580         }
581     }
582 
583     for (i=nStartCol; i<=nEndCol; i++)              // Daten testen
584         if (!aCol[i].IsEmptyVisData(bNotes))
585         {
586             bFound = sal_True;
587             SCROW nColY = aCol[i].GetLastVisDataPos(bNotes);
588             if (nColY > nMaxY)
589                 nMaxY = nColY;
590         }
591 
592     rEndRow = nMaxY;
593     return bFound;
594 }
595 
596 sal_Bool ScTable::GetDataStart( SCCOL& rStartCol, SCROW& rStartRow ) const
597 {
598     sal_Bool bFound = sal_False;
599     SCCOL nMinX = MAXCOL;
600     SCROW nMinY = MAXROW;
601     SCCOL i;
602 
603     for (i=0; i<=MAXCOL; i++)                   // Attribute testen
604     {
605         SCROW nFirstRow;
606         if (aCol[i].GetFirstVisibleAttr( nFirstRow ))
607         {
608             if (!bFound)
609                 nMinX = i;
610             bFound = sal_True;
611             if (nFirstRow < nMinY)
612                 nMinY = nFirstRow;
613         }
614     }
615 
616     if (nMinX == 0)                                     // Attribute links weglassen
617     {
618         if ( aCol[0].IsVisibleAttrEqual(aCol[1]) )      // keine einzelnen
619         {
620             ++nMinX;
621             while ( nMinX<MAXCOL && aCol[nMinX].IsVisibleAttrEqual(aCol[nMinX-1]) )
622                 ++nMinX;
623         }
624     }
625 
626     sal_Bool bDatFound = sal_False;
627     for (i=0; i<=MAXCOL; i++)                   // Daten testen
628         if (!aCol[i].IsEmptyVisData(sal_True))
629         {
630             if (!bDatFound && i<nMinX)
631                 nMinX = i;
632             bFound = bDatFound = sal_True;
633             SCROW nColY = aCol[i].GetFirstVisDataPos(sal_True);
634             if (nColY < nMinY)
635                 nMinY = nColY;
636         }
637 
638     rStartCol = nMinX;
639     rStartRow = nMinY;
640     return bFound;
641 }
642 
643 void ScTable::GetDataArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow,
644                            sal_Bool bIncludeOld, bool bOnlyDown ) const
645 {
646     sal_Bool bLeft       = sal_False;
647     sal_Bool bRight  = sal_False;
648     sal_Bool bTop        = sal_False;
649     sal_Bool bBottom = sal_False;
650     sal_Bool bChanged;
651     sal_Bool bFound;
652     SCCOL i;
653     SCROW nTest;
654 
655     do
656     {
657         bChanged = sal_False;
658 
659         if (!bOnlyDown)
660         {
661             SCROW nStart = rStartRow;
662             SCROW nEnd = rEndRow;
663             if (nStart>0) --nStart;
664             if (nEnd<MAXROW) ++nEnd;
665 
666             if (rEndCol < MAXCOL)
667                 if (!aCol[rEndCol+1].IsEmptyBlock(nStart,nEnd))
668                 {
669                     ++rEndCol;
670                     bChanged = sal_True;
671                     bRight = sal_True;
672                 }
673 
674             if (rStartCol > 0)
675                 if (!aCol[rStartCol-1].IsEmptyBlock(nStart,nEnd))
676                 {
677                     --rStartCol;
678                     bChanged = sal_True;
679                     bLeft = sal_True;
680                 }
681 
682             if (rStartRow > 0)
683             {
684                 nTest = rStartRow-1;
685                 bFound = sal_False;
686                 for (i=rStartCol; i<=rEndCol && !bFound; i++)
687                     if (aCol[i].HasDataAt(nTest))
688                         bFound = sal_True;
689                 if (bFound)
690                 {
691                     --rStartRow;
692                     bChanged = sal_True;
693                     bTop = sal_True;
694                 }
695             }
696         }
697 
698         if (rEndRow < MAXROW)
699         {
700             nTest = rEndRow+1;
701             bFound = sal_False;
702             for (i=rStartCol; i<=rEndCol && !bFound; i++)
703                 if (aCol[i].HasDataAt(nTest))
704                     bFound = sal_True;
705             if (bFound)
706             {
707                 ++rEndRow;
708                 bChanged = sal_True;
709                 bBottom = sal_True;
710             }
711         }
712     }
713     while( bChanged );
714 
715     if ( !bIncludeOld )
716     {
717         if ( !bLeft && rStartCol < MAXCOL && rStartCol < rEndCol )
718             if ( aCol[rStartCol].IsEmptyBlock(rStartRow,rEndRow) )
719                 ++rStartCol;
720         if ( !bRight && rEndCol > 0 && rStartCol < rEndCol )
721             if ( aCol[rEndCol].IsEmptyBlock(rStartRow,rEndRow) )
722                 --rEndCol;
723         if ( !bTop && rStartRow < MAXROW && rStartRow < rEndRow )
724         {
725             bFound = sal_False;
726             for (i=rStartCol; i<=rEndCol && !bFound; i++)
727                 if (aCol[i].HasDataAt(rStartRow))
728                     bFound = sal_True;
729             if (!bFound)
730                 ++rStartRow;
731         }
732         if ( !bBottom && rEndRow > 0 && rStartRow < rEndRow )
733         {
734             bFound = sal_False;
735             for (i=rStartCol; i<=rEndCol && !bFound; i++)
736                 if (aCol[i].HasDataAt(rEndRow))
737                     bFound = sal_True;
738             if (!bFound)
739                 --rEndRow;
740         }
741     }
742 }
743 
744 
745 bool ScTable::ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rStartRow,
746         SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const
747 {
748     o_bShrunk = false;
749 
750     PutInOrder( rStartCol, rEndCol);
751     PutInOrder( rStartRow, rEndRow);
752     if (rStartCol < 0)
753         rStartCol = 0, o_bShrunk = true;
754     if (rStartRow < 0)
755         rStartRow = 0, o_bShrunk = true;
756     if (rEndCol > MAXCOL)
757         rEndCol = MAXCOL, o_bShrunk = true;
758     if (rEndRow > MAXROW)
759         rEndRow = MAXROW, o_bShrunk = true;
760 
761     bool bChanged;
762     do
763     {
764         bChanged = false;
765 
766         while (rStartCol < rEndCol)
767         {
768             if (aCol[rEndCol].IsEmptyBlock( rStartRow, rEndRow))
769             {
770                 --rEndCol;
771                 bChanged = true;
772             }
773             else
774                 break;  // while
775         }
776 
777         while (rStartCol < rEndCol)
778         {
779             if (aCol[rStartCol].IsEmptyBlock( rStartRow, rEndRow))
780             {
781                 ++rStartCol;
782                 bChanged = true;
783             }
784             else
785                 break;  // while
786         }
787 
788         if (!bColumnsOnly)
789         {
790             if (rStartRow < rEndRow)
791             {
792                 bool bFound = false;
793                 for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++)
794                     if (aCol[i].HasDataAt( rStartRow))
795                         bFound = true;
796                 if (!bFound)
797                 {
798                     ++rStartRow;
799                     bChanged = true;
800                 }
801             }
802 
803             if (rStartRow < rEndRow)
804             {
805                 bool bFound = false;
806                 for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++)
807                     if (aCol[i].HasDataAt( rEndRow))
808                         bFound = true;
809                 if (!bFound)
810                 {
811                     --rEndRow;
812                     bChanged = true;
813                 }
814             }
815         }
816 
817         if (bChanged)
818             o_bShrunk = true;
819     } while( bChanged );
820 
821     return rStartCol != rEndCol || (bColumnsOnly ?
822             !aCol[rStartCol].IsEmptyBlock( rStartRow, rEndRow) :
823             (rStartRow != rEndRow || aCol[rStartCol].HasDataAt( rStartRow)));
824 }
825 
826 
827 SCSIZE ScTable::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow,
828                                         SCCOL nEndCol, SCROW nEndRow, ScDirection eDir )
829 {
830     SCSIZE nCount = 0;
831     SCCOL nCol;
832     if ((eDir == DIR_BOTTOM) || (eDir == DIR_TOP))
833     {
834         nCount = static_cast<SCSIZE>(nEndRow - nStartRow);
835         for (nCol = nStartCol; nCol <= nEndCol; nCol++)
836             nCount = Min(nCount, aCol[nCol].GetEmptyLinesInBlock(nStartRow, nEndRow, eDir));
837     }
838     else if (eDir == DIR_RIGHT)
839     {
840         nCol = nEndCol;
841         while (((SCsCOL)nCol >= (SCsCOL)nStartCol) &&
842                  aCol[nCol].IsEmptyBlock(nStartRow, nEndRow))
843         {
844             nCount++;
845             nCol--;
846         }
847     }
848     else
849     {
850         nCol = nStartCol;
851         while ((nCol <= nEndCol) && aCol[nCol].IsEmptyBlock(nStartRow, nEndRow))
852         {
853             nCount++;
854             nCol++;
855         }
856     }
857     return nCount;
858 }
859 
860 sal_Bool ScTable::IsEmptyLine( SCROW nRow, SCCOL nStartCol, SCCOL nEndCol )
861 {
862     sal_Bool bFound = sal_False;
863     for (SCCOL i=nStartCol; i<=nEndCol && !bFound; i++)
864         if (aCol[i].HasDataAt(nRow))
865             bFound = sal_True;
866     return !bFound;
867 }
868 
869 void ScTable::LimitChartArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow )
870 {
871     while ( rStartCol<rEndCol && aCol[rStartCol].IsEmptyBlock(rStartRow,rEndRow) )
872         ++rStartCol;
873 
874     while ( rStartCol<rEndCol && aCol[rEndCol].IsEmptyBlock(rStartRow,rEndRow) )
875         --rEndCol;
876 
877     while ( rStartRow<rEndRow && IsEmptyLine(rStartRow, rStartCol, rEndCol) )
878         ++rStartRow;
879 
880     while ( rStartRow<rEndRow && IsEmptyLine(rEndRow, rStartCol, rEndCol) )
881         --rEndRow;
882 }
883 
884 void ScTable::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCsCOL nMovX, SCsROW nMovY )
885 {
886     if (nMovX)
887     {
888         SCsCOL nNewCol = (SCsCOL) rCol;
889         sal_Bool bThere = aCol[nNewCol].HasVisibleDataAt(rRow);
890         sal_Bool bFnd;
891         if (bThere)
892         {
893             do
894             {
895                 nNewCol = sal::static_int_cast<SCsCOL>( nNewCol + nMovX );
896                 bFnd = (nNewCol>=0 && nNewCol<=MAXCOL) ? aCol[nNewCol].HasVisibleDataAt(rRow) : sal_False;
897             }
898             while (bFnd);
899             nNewCol = sal::static_int_cast<SCsCOL>( nNewCol - nMovX );
900 
901             if (nNewCol == (SCsCOL)rCol)
902                 bThere = sal_False;
903         }
904 
905         if (!bThere)
906         {
907             do
908             {
909                 nNewCol = sal::static_int_cast<SCsCOL>( nNewCol + nMovX );
910                 bFnd = (nNewCol>=0 && nNewCol<=MAXCOL) ? aCol[nNewCol].HasVisibleDataAt(rRow) : sal_True;
911             }
912             while (!bFnd);
913         }
914 
915         if (nNewCol<0) nNewCol=0;
916         if (nNewCol>MAXCOL) nNewCol=MAXCOL;
917         rCol = (SCCOL) nNewCol;
918     }
919 
920     if (nMovY)
921         aCol[rCol].FindDataAreaPos(rRow,nMovY);
922 }
923 
924 sal_Bool ScTable::ValidNextPos( SCCOL nCol, SCROW nRow, const ScMarkData& rMark,
925                                 sal_Bool bMarked, sal_Bool bUnprotected )
926 {
927     if (!ValidCol(nCol) || !ValidRow(nRow))
928         return sal_False;
929 
930     if (pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED))
931         // Skip an overlapped cell.
932         return false;
933 
934     if (bMarked && !rMark.IsCellMarked(nCol,nRow))
935         return sal_False;
936 
937     if (bUnprotected && ((const ScProtectionAttr*)
938                         GetAttr(nCol,nRow,ATTR_PROTECTION))->GetProtection())
939         return sal_False;
940 
941     if (bMarked || bUnprotected)        //! auch sonst ???
942     {
943         //  #53697# ausgeblendete muessen uebersprungen werden, weil der Cursor sonst
944         //  auf der naechsten Zelle landet, auch wenn die geschuetzt/nicht markiert ist.
945         //! per Extra-Parameter steuern, nur fuer Cursor-Bewegung ???
946 
947         if (RowHidden(nRow))
948             return sal_False;
949 
950         if (ColHidden(nCol))
951             return sal_False;
952     }
953 
954     return sal_True;
955 }
956 
957 void ScTable::GetNextPos( SCCOL& rCol, SCROW& rRow, SCsCOL nMovX, SCsROW nMovY,
958                                 sal_Bool bMarked, sal_Bool bUnprotected, const ScMarkData& rMark )
959 {
960     if (bUnprotected && !IsProtected())     // Tabelle ueberhaupt geschuetzt?
961         bUnprotected = sal_False;
962 
963     sal_uInt16 nWrap = 0;
964     SCsCOL nCol = rCol;
965     SCsROW nRow = rRow;
966 
967     nCol = sal::static_int_cast<SCsCOL>( nCol + nMovX );
968     nRow = sal::static_int_cast<SCsROW>( nRow + nMovY );
969 
970     DBG_ASSERT( !nMovY || !bUnprotected,
971                 "GetNextPos mit bUnprotected horizontal nicht implementiert" );
972 
973     if ( nMovY && bMarked )
974     {
975         sal_Bool bUp = ( nMovY < 0 );
976         nRow = rMark.GetNextMarked( nCol, nRow, bUp );
977         while ( VALIDROW(nRow) &&
978                 (RowHidden(nRow) || pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) )
979         {
980             //  #53697# ausgeblendete ueberspringen (s.o.)
981             nRow += nMovY;
982             nRow = rMark.GetNextMarked( nCol, nRow, bUp );
983         }
984 
985         while ( nRow < 0 || nRow > MAXROW )
986         {
987             nCol = sal::static_int_cast<SCsCOL>( nCol + static_cast<SCsCOL>(nMovY) );
988             while ( VALIDCOL(nCol) && ColHidden(nCol) )
989                 nCol = sal::static_int_cast<SCsCOL>( nCol + static_cast<SCsCOL>(nMovY) );   //  #53697# skip hidden rows (see above)
990             if (nCol < 0)
991             {
992                 nCol = MAXCOL;
993                 if (++nWrap >= 2)
994                     return;
995             }
996             else if (nCol > MAXCOL)
997             {
998                 nCol = 0;
999                 if (++nWrap >= 2)
1000                     return;
1001             }
1002             if (nRow < 0)
1003                 nRow = MAXROW;
1004             else if (nRow > MAXROW)
1005                 nRow = 0;
1006             nRow = rMark.GetNextMarked( nCol, nRow, bUp );
1007             while ( VALIDROW(nRow) &&
1008                     (RowHidden(nRow) || pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) )
1009             {
1010                 //  #53697# ausgeblendete ueberspringen (s.o.)
1011                 nRow += nMovY;
1012                 nRow = rMark.GetNextMarked( nCol, nRow, bUp );
1013             }
1014         }
1015     }
1016 
1017     if ( nMovX && ( bMarked || bUnprotected ) )
1018     {
1019         // initiales Weiterzaehlen wrappen:
1020         if (nCol<0)
1021         {
1022             nCol = MAXCOL;
1023             --nRow;
1024             if (nRow<0)
1025                 nRow = MAXROW;
1026         }
1027         if (nCol>MAXCOL)
1028         {
1029             nCol = 0;
1030             ++nRow;
1031             if (nRow>MAXROW)
1032                 nRow = 0;
1033         }
1034 
1035         if ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) )
1036         {
1037             SCsROW* pNextRows = new SCsROW[MAXCOL+1];
1038             SCCOL i;
1039 
1040             if ( nMovX > 0 )                            //  vorwaerts
1041             {
1042                 for (i=0; i<=MAXCOL; i++)
1043                     pNextRows[i] = (i<nCol) ? (nRow+1) : nRow;
1044                 do
1045                 {
1046                     SCsROW nNextRow = pNextRows[nCol] + 1;
1047                     if ( bMarked )
1048                         nNextRow = rMark.GetNextMarked( nCol, nNextRow, sal_False );
1049                     if ( bUnprotected )
1050                         nNextRow = aCol[nCol].GetNextUnprotected( nNextRow, sal_False );
1051                     pNextRows[nCol] = nNextRow;
1052 
1053                     SCsROW nMinRow = MAXROW+1;
1054                     for (i=0; i<=MAXCOL; i++)
1055                         if (pNextRows[i] < nMinRow)     // bei gleichen den linken
1056                         {
1057                             nMinRow = pNextRows[i];
1058                             nCol = i;
1059                         }
1060                     nRow = nMinRow;
1061 
1062                     if ( nRow > MAXROW )
1063                     {
1064                         if (++nWrap >= 2) break;        // ungueltigen Wert behalten
1065                         nCol = 0;
1066                         nRow = 0;
1067                         for (i=0; i<=MAXCOL; i++)
1068                             pNextRows[i] = 0;           // alles ganz von vorne
1069                     }
1070                 }
1071                 while ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) );
1072             }
1073             else                                        //  rueckwaerts
1074             {
1075                 for (i=0; i<=MAXCOL; i++)
1076                     pNextRows[i] = (i>nCol) ? (nRow-1) : nRow;
1077                 do
1078                 {
1079                     SCsROW nNextRow = pNextRows[nCol] - 1;
1080                     if ( bMarked )
1081                         nNextRow = rMark.GetNextMarked( nCol, nNextRow, sal_True );
1082                     if ( bUnprotected )
1083                         nNextRow = aCol[nCol].GetNextUnprotected( nNextRow, sal_True );
1084                     pNextRows[nCol] = nNextRow;
1085 
1086                     SCsROW nMaxRow = -1;
1087                     for (i=0; i<=MAXCOL; i++)
1088                         if (pNextRows[i] >= nMaxRow)    // bei gleichen den rechten
1089                         {
1090                             nMaxRow = pNextRows[i];
1091                             nCol = i;
1092                         }
1093                     nRow = nMaxRow;
1094 
1095                     if ( nRow < 0 )
1096                     {
1097                         if (++nWrap >= 2) break;        // ungueltigen Wert behalten
1098                         nCol = MAXCOL;
1099                         nRow = MAXROW;
1100                         for (i=0; i<=MAXCOL; i++)
1101                             pNextRows[i] = MAXROW;      // alles ganz von vorne
1102                     }
1103                 }
1104                 while ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) );
1105             }
1106 
1107             delete[] pNextRows;
1108         }
1109     }
1110 
1111     //  ungueltige Werte kommen z.b. bei Tab heraus,
1112     //  wenn nicht markiert und nicht geschuetzt ist (linker / rechter Rand),
1113     //  dann Werte unveraendert lassen
1114 
1115     if (VALIDCOLROW(nCol,nRow))
1116     {
1117         rCol = nCol;
1118         rRow = nRow;
1119     }
1120 }
1121 
1122 sal_Bool ScTable::GetNextMarkedCell( SCCOL& rCol, SCROW& rRow, const ScMarkData& rMark )
1123 {
1124     const ScMarkArray* pMarkArray = rMark.GetArray();
1125     DBG_ASSERT(pMarkArray,"GetNextMarkedCell ohne MarkArray");
1126     if ( !pMarkArray )
1127         return sal_False;
1128 
1129     ++rRow;                 // naechste Zelle ist gesucht
1130 
1131     while ( rCol <= MAXCOL )
1132     {
1133         const ScMarkArray& rArray = pMarkArray[rCol];
1134         while ( rRow <= MAXROW )
1135         {
1136             SCROW nStart = (SCROW) rArray.GetNextMarked( (SCsROW) rRow, sal_False );
1137             if ( nStart <= MAXROW )
1138             {
1139                 SCROW nEnd = rArray.GetMarkEnd( nStart, sal_False );
1140                 ScColumnIterator aColIter( &aCol[rCol], nStart, nEnd );
1141                 SCROW nCellRow;
1142                 ScBaseCell* pCell = NULL;
1143                 while ( aColIter.Next( nCellRow, pCell ) )
1144                 {
1145                     if ( pCell && pCell->GetCellType() != CELLTYPE_NOTE )
1146                     {
1147                         rRow = nCellRow;
1148                         return sal_True;            // Zelle gefunden
1149                     }
1150                 }
1151                 rRow = nEnd + 1;                // naechsten markierten Bereich suchen
1152             }
1153             else
1154                 rRow = MAXROW + 1;              // Ende der Spalte
1155         }
1156         rRow = 0;
1157         ++rCol;                                 // naechste Spalte testen
1158     }
1159 
1160     return sal_False;                               // alle Spalten durch
1161 }
1162 
1163 void ScTable::UpdateDrawRef( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1164                                     SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1165                                     SCsCOL nDx, SCsROW nDy, SCsTAB nDz, bool bUpdateNoteCaptionPos )
1166 {
1167     if ( nTab >= nTab1 && nTab <= nTab2 && nDz == 0 )       // only within the table
1168     {
1169         InitializeNoteCaptions();
1170         ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
1171         if ( eUpdateRefMode != URM_COPY && pDrawLayer )
1172         {
1173             if ( eUpdateRefMode == URM_MOVE )
1174             {                                               // source range
1175                 nCol1 = sal::static_int_cast<SCCOL>( nCol1 - nDx );
1176                 nRow1 = sal::static_int_cast<SCROW>( nRow1 - nDy );
1177                 nCol2 = sal::static_int_cast<SCCOL>( nCol2 - nDx );
1178                 nRow2 = sal::static_int_cast<SCROW>( nRow2 - nDy );
1179             }
1180             pDrawLayer->MoveArea( nTab, nCol1,nRow1, nCol2,nRow2, nDx,nDy,
1181                                     (eUpdateRefMode == URM_INSDEL), bUpdateNoteCaptionPos );
1182         }
1183     }
1184 }
1185 
1186 void ScTable::UpdateReference( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1187                      SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
1188                      ScDocument* pUndoDoc, sal_Bool bIncludeDraw, bool bUpdateNoteCaptionPos )
1189 {
1190     SCCOL i;
1191     SCCOL iMax;
1192     if ( eUpdateRefMode == URM_COPY )
1193     {
1194         i = nCol1;
1195         iMax = nCol2;
1196     }
1197     else
1198     {
1199         i = 0;
1200         iMax = MAXCOL;
1201     }
1202     for ( ; i<=iMax; i++)
1203         aCol[i].UpdateReference( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2,
1204                                     nDx, nDy, nDz, pUndoDoc );
1205 
1206     if ( bIncludeDraw )
1207         UpdateDrawRef( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz, bUpdateNoteCaptionPos );
1208 
1209     if ( nTab >= nTab1 && nTab <= nTab2 && nDz == 0 )       // print ranges: only within the table
1210     {
1211         SCTAB nSTab = nTab;
1212         SCTAB nETab = nTab;
1213         SCCOL nSCol = 0;
1214         SCROW nSRow = 0;
1215         SCCOL nECol = 0;
1216         SCROW nERow = 0;
1217         sal_Bool bRecalcPages = sal_False;
1218 
1219         for ( ScRangeVec::iterator aIt = aPrintRanges.begin(), aEnd = aPrintRanges.end(); aIt != aEnd; ++aIt )
1220         {
1221             nSCol = aIt->aStart.Col();
1222             nSRow = aIt->aStart.Row();
1223             nECol = aIt->aEnd.Col();
1224             nERow = aIt->aEnd.Row();
1225 
1226             // do not try to modify sheet index of print range
1227             if ( ScRefUpdate::Update( pDocument, eUpdateRefMode,
1228                                       nCol1,nRow1,nTab, nCol2,nRow2,nTab,
1229                                       nDx,nDy,0,
1230                                       nSCol,nSRow,nSTab, nECol,nERow,nETab ) )
1231             {
1232                 *aIt = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 );
1233                 bRecalcPages = sal_True;
1234             }
1235         }
1236 
1237         if ( pRepeatColRange )
1238         {
1239             nSCol = pRepeatColRange->aStart.Col();
1240             nSRow = pRepeatColRange->aStart.Row();
1241             nECol = pRepeatColRange->aEnd.Col();
1242             nERow = pRepeatColRange->aEnd.Row();
1243 
1244             // do not try to modify sheet index of repeat range
1245             if ( ScRefUpdate::Update( pDocument, eUpdateRefMode,
1246                                       nCol1,nRow1,nTab, nCol2,nRow2,nTab,
1247                                       nDx,nDy,0,
1248                                       nSCol,nSRow,nSTab, nECol,nERow,nETab ) )
1249             {
1250                 *pRepeatColRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 );
1251                 bRecalcPages = sal_True;
1252                 nRepeatStartX = nSCol;  // fuer UpdatePageBreaks
1253                 nRepeatEndX = nECol;
1254             }
1255         }
1256 
1257         if ( pRepeatRowRange )
1258         {
1259             nSCol = pRepeatRowRange->aStart.Col();
1260             nSRow = pRepeatRowRange->aStart.Row();
1261             nECol = pRepeatRowRange->aEnd.Col();
1262             nERow = pRepeatRowRange->aEnd.Row();
1263 
1264             // do not try to modify sheet index of repeat range
1265             if ( ScRefUpdate::Update( pDocument, eUpdateRefMode,
1266                                       nCol1,nRow1,nTab, nCol2,nRow2,nTab,
1267                                       nDx,nDy,0,
1268                                       nSCol,nSRow,nSTab, nECol,nERow,nETab ) )
1269             {
1270                 *pRepeatRowRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 );
1271                 bRecalcPages = sal_True;
1272                 nRepeatStartY = nSRow;  // fuer UpdatePageBreaks
1273                 nRepeatEndY = nERow;
1274             }
1275         }
1276 
1277         //  updating print ranges is not necessary with multiple print ranges
1278         if ( bRecalcPages && GetPrintRangeCount() <= 1 )
1279         {
1280             UpdatePageBreaks(NULL);
1281 
1282             pDocument->RepaintRange( ScRange(0,0,nTab,MAXCOL,MAXROW,nTab) );
1283         }
1284     }
1285 }
1286 
1287 void ScTable::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
1288                                     ScDocument* pUndoDoc )
1289 {
1290     for ( SCCOL i=0; i<=MAXCOL; i++ )
1291         aCol[i].UpdateTranspose( rSource, rDest, pUndoDoc );
1292 }
1293 
1294 void ScTable::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
1295 {
1296     for ( SCCOL i=0; i<=MAXCOL; i++ )
1297         aCol[i].UpdateGrow( rArea, nGrowX, nGrowY );
1298 }
1299 
1300 void ScTable::UpdateInsertTab(SCTAB nTable)
1301 {
1302     if (nTab >= nTable) nTab++;
1303     for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].UpdateInsertTab(nTable);
1304 
1305     if (IsStreamValid())
1306         SetStreamValid(sal_False);
1307 }
1308 
1309 //UNUSED2008-05  void ScTable::UpdateInsertTabOnlyCells(SCTAB nTable)
1310 //UNUSED2008-05  {
1311 //UNUSED2008-05      for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].UpdateInsertTabOnlyCells(nTable);
1312 //UNUSED2008-05  }
1313 
1314 void ScTable::UpdateDeleteTab( SCTAB nTable, sal_Bool bIsMove, ScTable* pRefUndo )
1315 {
1316     if (nTab > nTable) nTab--;
1317 
1318     SCCOL i;
1319     if (pRefUndo)
1320         for (i=0; i <= MAXCOL; i++) aCol[i].UpdateDeleteTab(nTable, bIsMove, &pRefUndo->aCol[i]);
1321     else
1322         for (i=0; i <= MAXCOL; i++) aCol[i].UpdateDeleteTab(nTable, bIsMove, NULL);
1323 
1324     if (IsStreamValid())
1325         SetStreamValid(sal_False);
1326 }
1327 
1328 void ScTable::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo,
1329         ScProgress& rProgress )
1330 {
1331     nTab = nTabNo;
1332     for ( SCCOL i=0; i <= MAXCOL; i++ )
1333     {
1334         aCol[i].UpdateMoveTab( nOldPos, nNewPos, nTabNo );
1335         rProgress.SetState( rProgress.GetState() + aCol[i].GetCodeCount() );
1336     }
1337 
1338     if (IsStreamValid())
1339         SetStreamValid(sal_False);
1340 }
1341 
1342 void ScTable::UpdateCompile( sal_Bool bForceIfNameInUse )
1343 {
1344     for (SCCOL i=0; i <= MAXCOL; i++)
1345     {
1346         aCol[i].UpdateCompile( bForceIfNameInUse );
1347     }
1348 }
1349 
1350 void ScTable::SetTabNo(SCTAB nNewTab)
1351 {
1352     nTab = nNewTab;
1353     for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].SetTabNo(nNewTab);
1354 }
1355 
1356 sal_Bool ScTable::IsRangeNameInUse(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1357                                sal_uInt16 nIndex) const
1358 {
1359     sal_Bool bInUse = sal_False;
1360     for (SCCOL i = nCol1; !bInUse && (i <= nCol2) && (ValidCol(i)); i++)
1361         bInUse = aCol[i].IsRangeNameInUse(nRow1, nRow2, nIndex);
1362     return bInUse;
1363 }
1364 
1365 void ScTable::FindRangeNamesInUse(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1366                                std::set<sal_uInt16>& rIndexes) const
1367 {
1368     for (SCCOL i = nCol1; i <= nCol2 && ValidCol(i); i++)
1369         aCol[i].FindRangeNamesInUse(nRow1, nRow2, rIndexes);
1370 }
1371 
1372 void ScTable::ReplaceRangeNamesInUse(SCCOL nCol1, SCROW nRow1,
1373                                     SCCOL nCol2, SCROW nRow2,
1374                                     const ScRangeData::IndexMap& rMap )
1375 {
1376     for (SCCOL i = nCol1; i <= nCol2 && (ValidCol(i)); i++)
1377     {
1378         aCol[i].ReplaceRangeNamesInUse( nRow1, nRow2, rMap );
1379     }
1380 }
1381 
1382 void ScTable::ExtendPrintArea( OutputDevice* pDev,
1383                     SCCOL /* nStartCol */, SCROW nStartRow, SCCOL& rEndCol, SCROW nEndRow )
1384 {
1385     if ( !pColFlags || !pRowFlags )
1386     {
1387         DBG_ERROR("keine ColInfo oder RowInfo in ExtendPrintArea");
1388         return;
1389     }
1390 
1391     Point aPix1000 = pDev->LogicToPixel( Point(1000,1000), MAP_TWIP );
1392     double nPPTX = aPix1000.X() / 1000.0;
1393     double nPPTY = aPix1000.Y() / 1000.0;
1394 
1395     // First, mark those columns that we need to skip i.e. hidden and empty columns.
1396 
1397     ScFlatBoolColSegments aSkipCols;
1398     aSkipCols.setInsertFromBack(true); // speed optimazation.
1399     aSkipCols.setFalse(0, MAXCOL);
1400     for (SCCOL i = 0; i <= MAXCOL; ++i)
1401     {
1402         SCCOL nLastCol = i;
1403         if (ColHidden(i, NULL, &nLastCol))
1404         {
1405             // Columns are hidden in this range.
1406             aSkipCols.setTrue(i, nLastCol);
1407         }
1408         else
1409         {
1410             // These columns are visible.  Check for empty columns.
1411             for (SCCOL j = i; j <= nLastCol; ++j)
1412             {
1413                 if (aCol[j].GetCellCount() == 0)
1414                     // empty
1415                     aSkipCols.setTrue(j,j);
1416             }
1417         }
1418         i = nLastCol;
1419     }
1420 
1421     ScFlatBoolColSegments::RangeData aColData;
1422     for (SCCOL nCol = rEndCol; nCol >= 0; --nCol)
1423     {
1424         if (!aSkipCols.getRangeData(nCol, aColData))
1425             // Failed to get the data.  This should never happen!
1426             return;
1427 
1428         if (aColData.mbValue)
1429         {
1430             // Skip these columns.
1431             nCol = aColData.mnCol1; // move toward 0.
1432             continue;
1433         }
1434 
1435         // These are visible and non-empty columns.
1436         for (SCCOL nDataCol = nCol; 0 <= nDataCol && nDataCol >= aColData.mnCol1; --nDataCol)
1437         {
1438             SCCOL nPrintCol = nDataCol;
1439             VisibleDataCellIterator aIter(*mpHiddenRows, aCol[nDataCol]);
1440             ScBaseCell* pCell = aIter.reset(nStartRow);
1441             if (!pCell)
1442                 // No visible cells found in this column.  Skip it.
1443                 continue;
1444 
1445             while (pCell)
1446             {
1447                 SCCOL nNewCol = nDataCol;
1448                 SCROW nRow = aIter.getRow();
1449                 if (nRow > nEndRow)
1450                     // Went past the last row position.  Bail out.
1451                     break;
1452 
1453                 MaybeAddExtraColumn(nNewCol, nRow, pDev, nPPTX, nPPTY);
1454                 if (nNewCol > nPrintCol)
1455                     nPrintCol = nNewCol;
1456                 pCell = aIter.next();
1457             }
1458 
1459             if (nPrintCol > rEndCol)
1460                 // Make sure we don't shrink the print area.
1461                 rEndCol = nPrintCol;
1462         }
1463         nCol = aColData.mnCol1; // move toward 0.
1464     }
1465 }
1466 
1467 void ScTable::MaybeAddExtraColumn(SCCOL& rCol, SCROW nRow, OutputDevice* pDev, double nPPTX, double nPPTY)
1468 {
1469     ScBaseCell* pCell = aCol[rCol].GetCell(nRow);
1470     if (!pCell || !pCell->HasStringData())
1471         return;
1472 
1473     bool bFormula = false;  //! ueberge
1474     long nPixel = pCell->GetTextWidth();
1475 
1476     // Breite bereits im Idle-Handler berechnet?
1477     if ( TEXTWIDTH_DIRTY == nPixel )
1478     {
1479         ScNeededSizeOptions aOptions;
1480         aOptions.bTotalSize  = sal_True;
1481         aOptions.bFormula    = bFormula;
1482         aOptions.bSkipMerged = sal_False;
1483 
1484         Fraction aZoom(1,1);
1485         nPixel = aCol[rCol].GetNeededSize(
1486             nRow, pDev, nPPTX, nPPTY, aZoom, aZoom, true, aOptions );
1487         pCell->SetTextWidth( (sal_uInt16)nPixel );
1488     }
1489 
1490     long nTwips = (long) (nPixel / nPPTX);
1491     long nDocW = GetColWidth( rCol );
1492 
1493     long nMissing = nTwips - nDocW;
1494     if ( nMissing > 0 )
1495     {
1496         //  look at alignment
1497 
1498         const ScPatternAttr* pPattern = GetPattern( rCol, nRow );
1499         const SfxItemSet* pCondSet = NULL;
1500         if ( ((const SfxUInt32Item&)pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() )
1501             pCondSet = pDocument->GetCondResult( rCol, nRow, nTab );
1502 
1503         SvxCellHorJustify eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)
1504                         pPattern->GetItem( ATTR_HOR_JUSTIFY, pCondSet )).GetValue();
1505         if ( eHorJust == SVX_HOR_JUSTIFY_CENTER )
1506             nMissing /= 2;                          // distributed into both directions
1507         else
1508         {
1509             // STANDARD is LEFT (only text is handled here)
1510             bool bRight = ( eHorJust == SVX_HOR_JUSTIFY_RIGHT );
1511             if ( IsLayoutRTL() )
1512                 bRight = !bRight;
1513             if ( bRight )
1514                 nMissing = 0;       // extended only to the left (logical)
1515         }
1516     }
1517 
1518     SCCOL nNewCol = rCol;
1519     while (nMissing > 0 && nNewCol < MAXCOL)
1520     {
1521         ScBaseCell* pNextCell = aCol[nNewCol+1].GetCell(nRow);
1522         if (pNextCell && pNextCell->GetCellType() != CELLTYPE_NOTE)
1523             // Cell content in a next column ends display of this string.
1524             nMissing = 0;
1525         else
1526             nMissing -= GetColWidth(++nNewCol);
1527     }
1528     rCol = nNewCol;
1529 }
1530 
1531 void ScTable::DoColResize( SCCOL nCol1, SCCOL nCol2, SCSIZE nAdd )
1532 {
1533     for (SCCOL nCol=nCol1; nCol<=nCol2; nCol++)
1534         aCol[nCol].Resize(aCol[nCol].GetCellCount() + nAdd);
1535 }
1536 
1537 #define SET_PRINTRANGE( p1, p2 ) \
1538     if ( (p2) )                             \
1539     {                                       \
1540         if ( (p1) )                         \
1541             *(p1) = *(p2);                  \
1542         else                                \
1543             (p1) = new ScRange( *(p2) );    \
1544     }                                       \
1545     else                                    \
1546         DELETEZ( (p1) )
1547 
1548 void ScTable::SetRepeatColRange( const ScRange* pNew )
1549 {
1550     SET_PRINTRANGE( pRepeatColRange, pNew );
1551 
1552     if (IsStreamValid())
1553         SetStreamValid(sal_False);
1554 }
1555 
1556 void ScTable::SetRepeatRowRange( const ScRange* pNew )
1557 {
1558     SET_PRINTRANGE( pRepeatRowRange, pNew );
1559 
1560     if (IsStreamValid())
1561         SetStreamValid(sal_False);
1562 }
1563 
1564 void ScTable::ClearPrintRanges()
1565 {
1566     aPrintRanges.clear();
1567     bPrintEntireSheet = sal_False;
1568     InvalidatePageBreaks();     // #i117952# forget page breaks for an old print range
1569 
1570     if (IsStreamValid())
1571         SetStreamValid(sal_False);
1572 }
1573 
1574 void ScTable::AddPrintRange( const ScRange& rNew )
1575 {
1576     bPrintEntireSheet = sal_False;
1577     if( aPrintRanges.size() < 0xFFFF )
1578         aPrintRanges.push_back( rNew );
1579 
1580     if (IsStreamValid())
1581         SetStreamValid(sal_False);
1582 }
1583 
1584 //UNUSED2009-05 void ScTable::SetPrintRange( const ScRange& rNew )
1585 //UNUSED2009-05 {
1586 //UNUSED2009-05     ClearPrintRanges();
1587 //UNUSED2009-05     AddPrintRange( rNew );
1588 //UNUSED2009-05 }
1589 
1590 void ScTable::SetPrintEntireSheet()
1591 {
1592     if( !IsPrintEntireSheet() )
1593     {
1594         ClearPrintRanges();
1595         bPrintEntireSheet = sal_True;
1596     }
1597 }
1598 
1599 const ScRange* ScTable::GetPrintRange(sal_uInt16 nPos) const
1600 {
1601     return (nPos < GetPrintRangeCount()) ? &aPrintRanges[ nPos ] : NULL;
1602 }
1603 
1604 void ScTable::FillPrintSaver( ScPrintSaverTab& rSaveTab ) const
1605 {
1606     rSaveTab.SetAreas( aPrintRanges, bPrintEntireSheet );
1607     rSaveTab.SetRepeat( pRepeatColRange, pRepeatRowRange );
1608 }
1609 
1610 void ScTable::RestorePrintRanges( const ScPrintSaverTab& rSaveTab )
1611 {
1612     aPrintRanges = rSaveTab.GetPrintRanges();
1613     bPrintEntireSheet = rSaveTab.IsEntireSheet();
1614     SetRepeatColRange( rSaveTab.GetRepeatCol() );
1615     SetRepeatRowRange( rSaveTab.GetRepeatRow() );
1616 
1617     InvalidatePageBreaks();     // #i117952# forget page breaks for an old print range
1618     UpdatePageBreaks(NULL);
1619 }
1620 
1621 SCROW ScTable::VisibleDataCellIterator::ROW_NOT_FOUND = -1;
1622 
1623 ScTable::VisibleDataCellIterator::VisibleDataCellIterator(ScFlatBoolRowSegments& rRowSegs, ScColumn& rColumn) :
1624     mrRowSegs(rRowSegs),
1625     mrColumn(rColumn),
1626     mpCell(NULL),
1627     mnCurRow(ROW_NOT_FOUND),
1628     mnUBound(ROW_NOT_FOUND)
1629 {
1630 }
1631 
1632 ScTable::VisibleDataCellIterator::~VisibleDataCellIterator()
1633 {
1634 }
1635 
1636 ScBaseCell* ScTable::VisibleDataCellIterator::reset(SCROW nRow)
1637 {
1638     if (nRow > MAXROW)
1639     {
1640         mnCurRow = ROW_NOT_FOUND;
1641         return NULL;
1642     }
1643 
1644     ScFlatBoolRowSegments::RangeData aData;
1645     if (!mrRowSegs.getRangeData(nRow, aData))
1646     {
1647         mnCurRow = ROW_NOT_FOUND;
1648         return NULL;
1649     }
1650 
1651     if (!aData.mbValue)
1652     {
1653         // specified row is visible.  Take it.
1654         mnCurRow = nRow;
1655         mnUBound = aData.mnRow2;
1656     }
1657     else
1658     {
1659         // specified row is not-visible.  The first visible row is the start of
1660         // the next segment.
1661         mnCurRow = aData.mnRow2 + 1;
1662         mnUBound = mnCurRow; // get range data on the next iteration.
1663         if (mnCurRow > MAXROW)
1664         {
1665             // Make sure the row doesn't exceed our current limit.
1666             mnCurRow = ROW_NOT_FOUND;
1667             return NULL;
1668         }
1669     }
1670 
1671     mpCell = mrColumn.GetCell(mnCurRow);
1672     if (mpCell)
1673         // First visible cell found.
1674         return mpCell;
1675 
1676     // Find a first visible cell below this row (if any).
1677     return next();
1678 }
1679 
1680 ScBaseCell* ScTable::VisibleDataCellIterator::next()
1681 {
1682     if (mnCurRow == ROW_NOT_FOUND)
1683         return NULL;
1684 
1685     while (mrColumn.GetNextDataPos(mnCurRow))
1686     {
1687         if (mnCurRow > mnUBound)
1688         {
1689             // We don't know the visibility of this row range.  Query it.
1690             ScFlatBoolRowSegments::RangeData aData;
1691             if (!mrRowSegs.getRangeData(mnCurRow, aData))
1692             {
1693                 mnCurRow = ROW_NOT_FOUND;
1694                 return NULL;
1695             }
1696 
1697             if (aData.mbValue)
1698             {
1699                 // This row is invisible.  Skip to the last invisible row and
1700                 // try again.
1701                 mnCurRow = mnUBound = aData.mnRow2;
1702                 continue;
1703             }
1704 
1705             // This row is visible.
1706             mnUBound = aData.mnRow2;
1707         }
1708 
1709         mpCell = mrColumn.GetCell(mnCurRow);
1710         if (mpCell)
1711             return mpCell;
1712     }
1713     mnCurRow = ROW_NOT_FOUND;
1714     return NULL;
1715 }
1716 
1717 SCROW ScTable::VisibleDataCellIterator::getRow() const
1718 {
1719     return mnCurRow;
1720 }
1721 
1722