xref: /aoo42x/main/sc/source/core/data/table1.cxx (revision b3f79822)
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