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