xref: /AOO41X/main/sc/source/core/data/document.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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 #define _ZFORLIST_DECLARE_TABLE
34 #include "scitems.hxx"
35 #include <editeng/eeitem.hxx>
36 
37 #include <editeng/boxitem.hxx>
38 #include <editeng/frmdiritem.hxx>
39 #include <svx/pageitem.hxx>
40 #include <editeng/editeng.hxx>
41 #include <svx/svditer.hxx>
42 #include <svx/svdpage.hxx>
43 #include <svx/svdocapt.hxx>
44 #include <sfx2/app.hxx>
45 #include <sfx2/objsh.hxx>
46 #include <svl/poolcach.hxx>
47 #include <unotools/saveopt.hxx>
48 #include <svl/zforlist.hxx>
49 #include <unotools/charclass.hxx>
50 #include <unotools/transliterationwrapper.hxx>
51 #include <tools/tenccvt.hxx>
52 
53 #include <com/sun/star/text/WritingMode2.hpp>
54 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
55 #include <com/sun/star/sheet/TablePageBreakData.hpp>
56 
57 #include "document.hxx"
58 #include "table.hxx"
59 #include "attrib.hxx"
60 #include "attarray.hxx"
61 #include "markarr.hxx"
62 #include "patattr.hxx"
63 #include "rangenam.hxx"
64 #include "poolhelp.hxx"
65 #include "docpool.hxx"
66 #include "stlpool.hxx"
67 #include "stlsheet.hxx"
68 #include "globstr.hrc"
69 #include "rechead.hxx"
70 #include "dbcolect.hxx"
71 #include "pivot.hxx"
72 #include "chartlis.hxx"
73 #include "rangelst.hxx"
74 #include "markdata.hxx"
75 #include "drwlayer.hxx"
76 #include "conditio.hxx"
77 #include "validat.hxx"
78 #include "prnsave.hxx"
79 #include "chgtrack.hxx"
80 #include "sc.hrc"
81 #include "scresid.hxx"
82 #include "hints.hxx"
83 #include "detdata.hxx"
84 #include "cell.hxx"
85 #include "dpobject.hxx"
86 #include "detfunc.hxx"		// for UpdateAllComments
87 #include "scmod.hxx"
88 #include "dociter.hxx"
89 #include "progress.hxx"
90 #include "autonamecache.hxx"
91 #include "bcaslot.hxx"
92 #include "postit.hxx"
93 #include "externalrefmgr.hxx"
94 #include "tabprotection.hxx"
95 #include "clipparam.hxx"
96 
97 #include <map>
98 #include <limits>
99 
100 namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
101 using ::com::sun::star::uno::Sequence;
102 using ::com::sun::star::sheet::TablePageBreakData;
103 using ::std::set;
104 
105 struct ScDefaultAttr
106 {
107 	const ScPatternAttr*	pAttr;
108 	SCROW					nFirst;
109 	SCSIZE					nCount;
110 	ScDefaultAttr(const ScPatternAttr* pPatAttr) : pAttr(pPatAttr), nFirst(0), nCount(0) {}
111 };
112 
113 struct ScLessDefaultAttr
114 {
115 	sal_Bool operator() (const ScDefaultAttr& rValue1, const ScDefaultAttr& rValue2) const
116 	{
117 		return rValue1.pAttr < rValue2.pAttr;
118 	}
119 };
120 
121 typedef std::set<ScDefaultAttr, ScLessDefaultAttr>	ScDefaultAttrSet;
122 
123 void ScDocument::MakeTable( SCTAB nTab,bool _bNeedsNameCheck )
124 {
125 	if ( ValidTab(nTab) && !pTab[nTab] )
126 	{
127 		String aString = ScGlobal::GetRscString(STR_TABLE_DEF); //"Tabelle"
128 		aString += String::CreateFromInt32(nTab+1);
129         if ( _bNeedsNameCheck )
130 		    CreateValidTabName( aString );	// keine doppelten
131 
132 		pTab[nTab] = new ScTable(this, nTab, aString);
133         pTab[nTab]->SetLoadingMedium(bLoadingMedium);
134 		++nMaxTableNumber;
135 	}
136 }
137 
138 
139 sal_Bool ScDocument::HasTable( SCTAB nTab ) const
140 {
141 	if (VALIDTAB(nTab))
142 		if (pTab[nTab])
143 			return sal_True;
144 
145 	return sal_False;
146 }
147 
148 
149 sal_Bool ScDocument::GetName( SCTAB nTab, String& rName ) const
150 {
151 	if (VALIDTAB(nTab))
152 		if (pTab[nTab])
153 		{
154 			pTab[nTab]->GetName( rName );
155 			return sal_True;
156 		}
157 	rName.Erase();
158 	return sal_False;
159 }
160 
161 sal_Bool ScDocument::SetCodeName( SCTAB nTab, const String& rName )
162 {
163 	if (VALIDTAB(nTab))
164 	{
165 		if (pTab[nTab])
166 		{
167 			pTab[nTab]->SetCodeName( rName );
168 			return sal_True;
169 		}
170 	}
171 	OSL_TRACE( "**** can't set code name %s", rtl::OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr() );
172 	return sal_False;
173 }
174 
175 sal_Bool ScDocument::GetCodeName( SCTAB nTab, String& rName ) const
176 {
177 	if (VALIDTAB(nTab))
178 		if (pTab[nTab])
179 		{
180 			pTab[nTab]->GetCodeName( rName );
181 			return sal_True;
182 		}
183 	rName.Erase();
184 	return sal_False;
185 }
186 
187 
188 sal_Bool ScDocument::GetTable( const String& rName, SCTAB& rTab ) const
189 {
190 	String aUpperName = rName;
191 	ScGlobal::pCharClass->toUpper(aUpperName);
192 
193 	for (SCTAB i=0; i<=MAXTAB; i++)
194 		if (pTab[i])
195 		{
196 			if ( pTab[i]->GetUpperName() == aUpperName )
197 			{
198 				rTab = i;
199 				return sal_True;
200 			}
201 		}
202 	rTab = 0;
203 	return sal_False;
204 }
205 
206 
207 sal_Bool ScDocument::ValidTabName( const String& rName ) const
208 {
209     xub_StrLen nLen = rName.Len();
210     if (!nLen)
211         return false;
212 
213 #if 1
214     // Restrict sheet names to what Excel accepts.
215     /* TODO: We may want to remove this restriction for full ODFF compliance.
216      * Merely loading and calculating ODF documents using these characters in
217      * sheet names is not affected by this, but all sheet name editing and
218      * copying functionality is, maybe falling back to "Sheet4" or similar. */
219     for (xub_StrLen i = 0; i < nLen; ++i)
220     {
221         const sal_Unicode c = rName.GetChar(i);
222         switch (c)
223         {
224             case ':':
225             case '\\':
226             case '/':
227             case '?':
228             case '*':
229             case '[':
230             case ']':
231                 // these characters are not allowed to match XL's convention.
232                 return false;
233             case '\'':
234                 if (i == 0 || i == nLen - 1)
235                     // single quote is not allowed at the first or last
236                     // character position.
237                     return false;
238             break;
239         }
240     }
241 #endif
242 
243     return true;
244 }
245 
246 
247 sal_Bool ScDocument::ValidNewTabName( const String& rName ) const
248 {
249 	sal_Bool bValid = ValidTabName(rName);
250 	for (SCTAB i=0; (i<=MAXTAB) && bValid; i++)
251 		if (pTab[i])
252 		{
253 			String aOldName;
254 			pTab[i]->GetName(aOldName);
255             bValid = !ScGlobal::GetpTransliteration()->isEqual( rName, aOldName );
256 		}
257 	return bValid;
258 }
259 
260 
261 void ScDocument::CreateValidTabName(String& rName) const
262 {
263 	if ( !ValidTabName(rName) )
264 	{
265 		// neu erzeugen
266 
267 		const String aStrTable( ScResId(SCSTR_TABLE) );
268 		sal_Bool		 bOk   = sal_False;
269 
270 		//	vorneweg testen, ob der Prefix als gueltig erkannt wird
271 		//	wenn nicht, nur doppelte vermeiden
272 		sal_Bool bPrefix = ValidTabName( aStrTable );
273 		DBG_ASSERT(bPrefix, "ungueltiger Tabellenname");
274 		SCTAB nDummy;
275 
276 		SCTAB nLoops = 0;		// "zur Sicherheit"
277 		for ( SCTAB i = nMaxTableNumber+1; !bOk && nLoops <= MAXTAB; i++ )
278 		{
279 			rName  = aStrTable;
280 			rName += String::CreateFromInt32(i);
281 			if (bPrefix)
282 				bOk = ValidNewTabName( rName );
283 			else
284 				bOk = !GetTable( rName, nDummy );
285 			++nLoops;
286 		}
287 
288 		DBG_ASSERT(bOk, "kein gueltiger Tabellenname gefunden");
289 		if ( !bOk )
290 			rName = aStrTable;
291 	}
292 	else
293 	{
294 		// uebergebenen Namen ueberpruefen
295 
296 		if ( !ValidNewTabName(rName) )
297 		{
298 			SCTAB i = 1;
299 			String aName;
300 			do
301 			{
302 				i++;
303 				aName = rName;
304 				aName += '_';
305 				aName += String::CreateFromInt32(static_cast<sal_Int32>(i));
306 			}
307 			while (!ValidNewTabName(aName) && (i < MAXTAB+1));
308 			rName = aName;
309 		}
310 	}
311 }
312 
313 
314 sal_Bool ScDocument::InsertTab( SCTAB nPos, const String& rName,
315 			sal_Bool bExternalDocument )
316 {
317 	SCTAB	nTabCount = GetTableCount();
318 	sal_Bool	bValid = ValidTab(nTabCount);
319 	if ( !bExternalDocument )	// sonst rName == "'Doc'!Tab", vorher pruefen
320 		bValid = (bValid && ValidNewTabName(rName));
321 	if (bValid)
322 	{
323 		if (nPos == SC_TAB_APPEND || nPos == nTabCount)
324 		{
325 			pTab[nTabCount] = new ScTable(this, nTabCount, rName);
326             pTab[nTabCount]->SetCodeName( rName );
327 			++nMaxTableNumber;
328 			if ( bExternalDocument )
329 				pTab[nTabCount]->SetVisible( sal_False );
330 		}
331 		else
332 		{
333 			if (VALIDTAB(nPos) && (nPos < nTabCount))
334 			{
335 				ScRange aRange( 0,0,nPos, MAXCOL,MAXROW,MAXTAB );
336 				xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
337 				xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
338 				pRangeName->UpdateTabRef( nPos, 1 );
339 				pDBCollection->UpdateReference(
340 									URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
341 				if (pDPCollection)
342 					pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
343 				if (pDetOpList)
344 					pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,1 );
345 				UpdateChartRef( URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
346 				UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,1 );
347 				if ( pUnoBroadcaster )
348 					pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,1 ) );
349 
350 				SCTAB i;
351 				for (i = 0; i <= MAXTAB; i++)
352 					if (pTab[i])
353 						pTab[i]->UpdateInsertTab(nPos);
354 
355 				for (i = nTabCount; i > nPos; i--)
356 				{
357 					pTab[i] = pTab[i - 1];
358 				}
359 
360 				pTab[nPos] = new ScTable(this, nPos, rName);
361                 pTab[nPos]->SetCodeName( rName );
362 				++nMaxTableNumber;
363 
364                 // UpdateBroadcastAreas must be called between UpdateInsertTab,
365                 // which ends listening, and StartAllListeners, to not modify
366                 // areas that are to be inserted by starting listeners.
367                 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,1);
368 				for (i = 0; i <= MAXTAB; i++)
369 					if (pTab[i])
370 						pTab[i]->UpdateCompile();
371 				for (i = 0; i <= MAXTAB; i++)
372 					if (pTab[i])
373 						pTab[i]->StartAllListeners();
374 
375 				//	update conditional formats after table is inserted
376 				if ( pCondFormList )
377 					pCondFormList->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
378 				if ( pValidationList )
379 					pValidationList->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
380 				// #81844# sheet names of references are not valid until sheet is inserted
381 				if ( pChartListenerCollection )
382 					pChartListenerCollection->UpdateScheduledSeriesRanges();
383 
384 				SetDirty();
385 				bValid = sal_True;
386 			}
387 			else
388 				bValid = sal_False;
389 		}
390 	}
391 	return bValid;
392 }
393 
394 
395 sal_Bool ScDocument::DeleteTab( SCTAB nTab, ScDocument* pRefUndoDoc )
396 {
397 	sal_Bool bValid = sal_False;
398 	if (VALIDTAB(nTab))
399 	{
400 		if (pTab[nTab])
401 		{
402 			SCTAB nTabCount = GetTableCount();
403 			if (nTabCount > 1)
404 			{
405 				sal_Bool bOldAutoCalc = GetAutoCalc();
406 				SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
407 				ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTab );
408 				DelBroadcastAreasInRange( aRange );
409 
410                 // #i8180# remove database ranges etc. that are on the deleted tab
411                 // (restored in undo with ScRefUndoData)
412 
413                 xColNameRanges->DeleteOnTab( nTab );
414                 xRowNameRanges->DeleteOnTab( nTab );
415                 pDBCollection->DeleteOnTab( nTab );
416                 if (pDPCollection)
417                     pDPCollection->DeleteOnTab( nTab );
418                 if (pDetOpList)
419                     pDetOpList->DeleteOnTab( nTab );
420                 DeleteAreaLinksOnTab( nTab );
421 
422                 // normal reference update
423 
424 				aRange.aEnd.SetTab( MAXTAB );
425 				xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
426 				xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
427 				pRangeName->UpdateTabRef( nTab, 2 );
428 				pDBCollection->UpdateReference(
429 									URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1 );
430 				if (pDPCollection)
431 					pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
432 				if (pDetOpList)
433 					pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1 );
434 				UpdateChartRef( URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1 );
435 				UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1 );
436 				if ( pCondFormList )
437 					pCondFormList->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
438 				if ( pValidationList )
439 					pValidationList->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
440 				if ( pUnoBroadcaster )
441 					pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1 ) );
442 
443 				SCTAB i;
444 				for (i=0; i<=MAXTAB; i++)
445 					if (pTab[i])
446 						pTab[i]->UpdateDeleteTab(nTab,sal_False,
447 									pRefUndoDoc ? pRefUndoDoc->pTab[i] : 0);
448 				delete pTab[nTab];
449 				for (i=nTab + 1; i < nTabCount; i++)
450 					pTab[i - 1] = pTab[i];
451 				pTab[nTabCount - 1] = NULL;
452 				--nMaxTableNumber;
453                 // UpdateBroadcastAreas must be called between UpdateDeleteTab,
454                 // which ends listening, and StartAllListeners, to not modify
455                 // areas that are to be inserted by starting listeners.
456                 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1);
457 				for (i = 0; i <= MAXTAB; i++)
458 					if (pTab[i])
459 						pTab[i]->UpdateCompile();
460 				// Excel-Filter loescht einige Tables waehrend des Ladens,
461 				// Listener werden erst nach dem Laden aufgesetzt
462 				if ( !bInsertingFromOtherDoc )
463 				{
464 					for (i = 0; i <= MAXTAB; i++)
465 						if (pTab[i])
466 							pTab[i]->StartAllListeners();
467 					SetDirty();
468 				}
469 				// #81844# sheet names of references are not valid until sheet is deleted
470 				pChartListenerCollection->UpdateScheduledSeriesRanges();
471 
472 				SetAutoCalc( bOldAutoCalc );
473 				bValid = sal_True;
474 			}
475 		}
476 	}
477 	return bValid;
478 }
479 
480 
481 sal_Bool ScDocument::RenameTab( SCTAB nTab, const String& rName, sal_Bool /* bUpdateRef */,
482 		sal_Bool bExternalDocument )
483 {
484 	sal_Bool	bValid = sal_False;
485 	SCTAB	i;
486 	if VALIDTAB(nTab)
487 		if (pTab[nTab])
488 		{
489 			if ( bExternalDocument )
490 				bValid = sal_True;		// zusammengesetzter Name
491 			else
492 				bValid = ValidTabName(rName);
493 			for (i=0; (i<=MAXTAB) && bValid; i++)
494 				if (pTab[i] && (i != nTab))
495 				{
496 					String aOldName;
497 					pTab[i]->GetName(aOldName);
498                     bValid = !ScGlobal::GetpTransliteration()->isEqual( rName, aOldName );
499 				}
500 			if (bValid)
501 			{
502                 // #i75258# update charts before renaming, so they can get their live data objects.
503                 // Once the charts are live, the sheet can be renamed without problems.
504                 if ( pChartListenerCollection )
505                     pChartListenerCollection->UpdateChartsContainingTab( nTab );
506 				pTab[nTab]->SetName(rName);
507 
508                 // If formulas refer to the renamed sheet, the TokenArray remains valid,
509                 // but the XML stream must be re-generated.
510                 for (i=0; i<=MAXTAB; ++i)
511                     if (pTab[i] && pTab[i]->IsStreamValid())
512                         pTab[i]->SetStreamValid( sal_False );
513 			}
514 		}
515 	return bValid;
516 }
517 
518 
519 void ScDocument::SetVisible( SCTAB nTab, sal_Bool bVisible )
520 {
521 	if (VALIDTAB(nTab))
522 		if (pTab[nTab])
523 			pTab[nTab]->SetVisible(bVisible);
524 }
525 
526 
527 sal_Bool ScDocument::IsVisible( SCTAB nTab ) const
528 {
529 	if (VALIDTAB(nTab))
530 		if (pTab[nTab])
531 			return pTab[nTab]->IsVisible();
532 
533 	return sal_False;
534 }
535 
536 
537 sal_Bool ScDocument::IsStreamValid( SCTAB nTab ) const
538 {
539     if ( ValidTab(nTab) && pTab[nTab] )
540         return pTab[nTab]->IsStreamValid();
541 
542     return sal_False;
543 }
544 
545 
546 void ScDocument::SetStreamValid( SCTAB nTab, sal_Bool bSet, sal_Bool bIgnoreLock )
547 {
548     if ( ValidTab(nTab) && pTab[nTab] )
549         pTab[nTab]->SetStreamValid( bSet, bIgnoreLock );
550 }
551 
552 
553 void ScDocument::LockStreamValid( bool bLock )
554 {
555     mbStreamValidLocked = bLock;
556 }
557 
558 
559 sal_Bool ScDocument::IsPendingRowHeights( SCTAB nTab ) const
560 {
561     if ( ValidTab(nTab) && pTab[nTab] )
562         return pTab[nTab]->IsPendingRowHeights();
563 
564     return sal_False;
565 }
566 
567 
568 void ScDocument::SetPendingRowHeights( SCTAB nTab, sal_Bool bSet )
569 {
570     if ( ValidTab(nTab) && pTab[nTab] )
571         pTab[nTab]->SetPendingRowHeights( bSet );
572 }
573 
574 
575 void ScDocument::SetLayoutRTL( SCTAB nTab, sal_Bool bRTL )
576 {
577 	if ( ValidTab(nTab)  && pTab[nTab] )
578 	{
579         if ( bImportingXML )
580         {
581             // #i57869# only set the LoadingRTL flag, the real setting (including mirroring)
582             // is applied in SetImportingXML(sal_False). This is so the shapes can be loaded in
583             // normal LTR mode.
584 
585             pTab[nTab]->SetLoadingRTL( bRTL );
586             return;
587         }
588 
589 		pTab[nTab]->SetLayoutRTL( bRTL );		// only sets the flag
590 		pTab[nTab]->SetDrawPageSize();
591 
592 		//	mirror existing objects:
593 
594 		if (pDrawLayer)
595 		{
596 			SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
597 			DBG_ASSERT(pPage,"Page ?");
598 			if (pPage)
599 			{
600 				SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
601 				SdrObject* pObject = aIter.Next();
602 				while (pObject)
603 				{
604 					//	objects with ScDrawObjData are re-positioned in SetPageSize,
605 					//	don't mirror again
606 					ScDrawObjData* pData = ScDrawLayer::GetObjData( pObject );
607 					if ( !pData )
608 						pDrawLayer->MirrorRTL( pObject );
609 
610                     pObject->SetContextWritingMode( bRTL ? WritingMode2::RL_TB : WritingMode2::LR_TB );
611 
612 					pObject = aIter.Next();
613 				}
614 			}
615 		}
616 	}
617 }
618 
619 
620 sal_Bool ScDocument::IsLayoutRTL( SCTAB nTab ) const
621 {
622 	if ( ValidTab(nTab)  && pTab[nTab] )
623 		return pTab[nTab]->IsLayoutRTL();
624 
625 	return sal_False;
626 }
627 
628 
629 sal_Bool ScDocument::IsNegativePage( SCTAB nTab ) const
630 {
631 	//	Negative page area is always used for RTL layout.
632 	//	The separate method is used to find all RTL handling of drawing objects.
633 	return IsLayoutRTL( nTab );
634 }
635 
636 
637 /* ----------------------------------------------------------------------------
638 	benutzten Bereich suchen:
639 
640 	GetCellArea	 - nur Daten
641 	GetTableArea - Daten / Attribute
642 	GetPrintArea - beruecksichtigt auch Zeichenobjekte,
643 					streicht Attribute bis ganz rechts / unten
644 ---------------------------------------------------------------------------- */
645 
646 
647 sal_Bool ScDocument::GetCellArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
648 {
649 	if (VALIDTAB(nTab))
650 		if (pTab[nTab])
651 			return pTab[nTab]->GetCellArea( rEndCol, rEndRow );
652 
653 	rEndCol = 0;
654 	rEndRow = 0;
655 	return sal_False;
656 }
657 
658 
659 sal_Bool ScDocument::GetTableArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
660 {
661 	if (VALIDTAB(nTab))
662 		if (pTab[nTab])
663 			return pTab[nTab]->GetTableArea( rEndCol, rEndRow );
664 
665 	rEndCol = 0;
666 	rEndRow = 0;
667     return sal_False;
668 }
669 
670 bool ScDocument::ShrinkToDataArea(SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow) const
671 {
672     if (!ValidTab(nTab) || !pTab[nTab])
673         return false;
674 
675     SCCOL nCol1, nCol2;
676     SCROW nRow1, nRow2;
677     pTab[nTab]->GetFirstDataPos(nCol1, nRow1);
678     pTab[nTab]->GetLastDataPos(nCol2, nRow2);
679 
680     if (nCol1 > nCol2 || nRow1 > nRow2)
681         // invalid range.
682         return false;
683 
684     // Make sure the area only shrinks, and doesn't grow.
685     if (rStartCol < nCol1)
686         rStartCol = nCol1;
687     if (nCol2 < rEndCol)
688         rEndCol = nCol2;
689     if (rStartRow < nRow1)
690         rStartRow = nRow1;
691     if (nRow2 < rEndRow)
692         rEndRow = nRow2;
693 
694     if (rStartCol > rEndCol || rStartRow > rEndRow)
695         // invalid range.
696         return false;
697 
698     return true;  // success!
699 }
700 
701 bool ScDocument::ShrinkToUsedDataArea( bool& o_bShrunk, SCTAB nTab, SCCOL& rStartCol,
702         SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const
703 {
704     if (!ValidTab(nTab) || !pTab[nTab])
705     {
706         o_bShrunk = false;
707         return false;
708     }
709     return pTab[nTab]->ShrinkToUsedDataArea( o_bShrunk, rStartCol, rStartRow, rEndCol, rEndRow, bColumnsOnly);
710 }
711 
712 //	zusammenhaengender Bereich
713 
714 void ScDocument::GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
715                               SCCOL& rEndCol, SCROW& rEndRow, sal_Bool bIncludeOld, bool bOnlyDown ) const
716 {
717     if (ValidTab(nTab) && pTab[nTab])
718         pTab[nTab]->GetDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bIncludeOld, bOnlyDown );
719 }
720 
721 
722 void ScDocument::LimitChartArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
723 									SCCOL& rEndCol, SCROW& rEndRow )
724 {
725 	if (VALIDTAB(nTab))
726 		if (pTab[nTab])
727 			pTab[nTab]->LimitChartArea( rStartCol, rStartRow, rEndCol, rEndRow );
728 }
729 
730 
731 void ScDocument::LimitChartIfAll( ScRangeListRef& rRangeList )
732 {
733 	ScRangeListRef aNew = new ScRangeList;
734 	if (rRangeList.Is())
735 	{
736 		sal_uLong nCount = rRangeList->Count();
737 		for (sal_uLong i=0; i<nCount; i++)
738 		{
739 			ScRange aRange(*rRangeList->GetObject( i ));
740 			if ( ( aRange.aStart.Col() == 0 && aRange.aEnd.Col() == MAXCOL ) ||
741 				 ( aRange.aStart.Row() == 0 && aRange.aEnd.Row() == MAXROW ) )
742 			{
743 				SCCOL nStartCol = aRange.aStart.Col();
744 				SCROW nStartRow = aRange.aStart.Row();
745 				SCCOL nEndCol = aRange.aEnd.Col();
746 				SCROW nEndRow = aRange.aEnd.Row();
747 				SCTAB nTab = aRange.aStart.Tab();
748 				if (pTab[nTab])
749 					pTab[nTab]->LimitChartArea(nStartCol, nStartRow, nEndCol, nEndRow);
750 				aRange.aStart.SetCol( nStartCol );
751 				aRange.aStart.SetRow( nStartRow );
752 				aRange.aEnd.SetCol( nEndCol );
753 				aRange.aEnd.SetRow( nEndRow );
754 			}
755 			aNew->Append(aRange);
756 		}
757 	}
758 	else
759 	{
760 		DBG_ERROR("LimitChartIfAll: Ref==0");
761 	}
762 	rRangeList = aNew;
763 }
764 
765 
766 void lcl_GetFirstTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark )
767 {
768     // without ScMarkData, leave start/end unchanged
769     if ( pTabMark )
770     {
771         for (SCTAB nTab=0; nTab<=MAXTAB; ++nTab)
772             if (pTabMark->GetTableSelect(nTab))
773             {
774                 // find first range of consecutive selected sheets
775                 rTabRangeStart = nTab;
776                 while ( nTab+1 <= MAXTAB && pTabMark->GetTableSelect(nTab+1) )
777                     ++nTab;
778                 rTabRangeEnd = nTab;
779                 return;
780             }
781     }
782 }
783 
784 bool lcl_GetNextTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark )
785 {
786     if ( pTabMark )
787     {
788         // find next range of consecutive selected sheets after rTabRangeEnd
789         for (SCTAB nTab=rTabRangeEnd+1; nTab<=MAXTAB; ++nTab)
790             if (pTabMark->GetTableSelect(nTab))
791             {
792                 rTabRangeStart = nTab;
793                 while ( nTab+1 <= MAXTAB && pTabMark->GetTableSelect(nTab+1) )
794                     ++nTab;
795                 rTabRangeEnd = nTab;
796                 return true;
797             }
798     }
799     return false;
800 }
801 
802 
803 sal_Bool ScDocument::CanInsertRow( const ScRange& rRange ) const
804 {
805 	SCCOL nStartCol = rRange.aStart.Col();
806 	SCROW nStartRow = rRange.aStart.Row();
807 	SCTAB nStartTab = rRange.aStart.Tab();
808 	SCCOL nEndCol = rRange.aEnd.Col();
809 	SCROW nEndRow = rRange.aEnd.Row();
810 	SCTAB nEndTab = rRange.aEnd.Tab();
811 	PutInOrder( nStartCol, nEndCol );
812 	PutInOrder( nStartRow, nEndRow );
813 	PutInOrder( nStartTab, nEndTab );
814 	SCSIZE nSize = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
815 
816 	sal_Bool bTest = sal_True;
817 	for (SCTAB i=nStartTab; i<=nEndTab && bTest; i++)
818 		if (pTab[i])
819 			bTest &= pTab[i]->TestInsertRow( nStartCol, nEndCol, nSize );
820 
821 	return bTest;
822 }
823 
824 
825 sal_Bool ScDocument::InsertRow( SCCOL nStartCol, SCTAB nStartTab,
826 							SCCOL nEndCol,   SCTAB nEndTab,
827                             SCROW nStartRow, SCSIZE nSize, ScDocument* pRefUndoDoc,
828                             const ScMarkData* pTabMark )
829 {
830 	SCTAB i;
831 
832 	PutInOrder( nStartCol, nEndCol );
833 	PutInOrder( nStartTab, nEndTab );
834 	if ( pTabMark )
835 	{
836 	    nStartTab = 0;
837 	    nEndTab = MAXTAB;
838 	}
839 
840 	sal_Bool bTest = sal_True;
841 	sal_Bool bRet = sal_False;
842 	sal_Bool bOldAutoCalc = GetAutoCalc();
843 	SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
844 	for ( i = nStartTab; i <= nEndTab && bTest; i++)
845         if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
846 			bTest &= pTab[i]->TestInsertRow( nStartCol, nEndCol, nSize );
847 	if (bTest)
848 	{
849 		// UpdateBroadcastAreas muss vor UpdateReference gerufen werden, damit nicht
850 		// Eintraege verschoben werden, die erst bei UpdateReference neu erzeugt werden
851 
852         // handle chunks of consecutive selected sheets together
853         SCTAB nTabRangeStart = nStartTab;
854         SCTAB nTabRangeEnd = nEndTab;
855         lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
856         do
857         {
858             UpdateBroadcastAreas( URM_INSDEL, ScRange(
859                 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
860                 ScAddress( nEndCol, MAXROW, nTabRangeEnd )), 0, static_cast<SCsROW>(nSize), 0 );
861         }
862         while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
863 
864         lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
865         do
866         {
867             UpdateReference( URM_INSDEL, nStartCol, nStartRow, nTabRangeStart,
868                              nEndCol, MAXROW, nTabRangeEnd,
869                              0, static_cast<SCsROW>(nSize), 0, pRefUndoDoc, sal_False );        // without drawing objects
870         }
871         while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
872 
873 		for (i=nStartTab; i<=nEndTab; i++)
874             if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
875 				pTab[i]->InsertRow( nStartCol, nEndCol, nStartRow, nSize );
876 
877 		//	#82991# UpdateRef for drawing layer must be after inserting,
878 		//	when the new row heights are known.
879 		for (i=nStartTab; i<=nEndTab; i++)
880             if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
881 				pTab[i]->UpdateDrawRef( URM_INSDEL,
882 							nStartCol, nStartRow, nStartTab, nEndCol, MAXROW, nEndTab,
883 							0, static_cast<SCsROW>(nSize), 0 );
884 
885 		if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
886 		{	// durch Restaurierung von Referenzen auf geloeschte Bereiche ist
887 			// ein neues Listening faellig, bisherige Listener wurden in
888 			// FormulaCell UpdateReference abgehaengt
889 			StartAllListeners();
890 		}
891 		else
892         {   // Listeners have been removed in UpdateReference
893 			for (i=0; i<=MAXTAB; i++)
894 				if (pTab[i])
895                     pTab[i]->StartNeededListeners();
896             // #69592# at least all cells using range names pointing relative
897             // to the moved range must recalculate
898 			for (i=0; i<=MAXTAB; i++)
899 				if (pTab[i])
900 					pTab[i]->SetRelNameDirty();
901 		}
902 		bRet = sal_True;
903 	}
904 	SetAutoCalc( bOldAutoCalc );
905 	if ( bRet )
906 		pChartListenerCollection->UpdateDirtyCharts();
907 	return bRet;
908 }
909 
910 
911 sal_Bool ScDocument::InsertRow( const ScRange& rRange, ScDocument* pRefUndoDoc )
912 {
913 	return InsertRow( rRange.aStart.Col(), rRange.aStart.Tab(),
914 					  rRange.aEnd.Col(),   rRange.aEnd.Tab(),
915 					  rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
916 					  pRefUndoDoc );
917 }
918 
919 
920 void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
921 							SCCOL nEndCol,   SCTAB nEndTab,
922 							SCROW nStartRow, SCSIZE nSize,
923                             ScDocument* pRefUndoDoc, sal_Bool* pUndoOutline,
924                             const ScMarkData* pTabMark )
925 {
926 	SCTAB i;
927 
928 	PutInOrder( nStartCol, nEndCol );
929 	PutInOrder( nStartTab, nEndTab );
930 	if ( pTabMark )
931 	{
932 	    nStartTab = 0;
933 	    nEndTab = MAXTAB;
934 	}
935 
936 	sal_Bool bOldAutoCalc = GetAutoCalc();
937 	SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
938 
939     // handle chunks of consecutive selected sheets together
940     SCTAB nTabRangeStart = nStartTab;
941     SCTAB nTabRangeEnd = nEndTab;
942     lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
943     do
944     {
945         if ( ValidRow(nStartRow+nSize) )
946         {
947             DelBroadcastAreasInRange( ScRange(
948                 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
949                 ScAddress( nEndCol, nStartRow+nSize-1, nTabRangeEnd ) ) );
950             UpdateBroadcastAreas( URM_INSDEL, ScRange(
951                 ScAddress( nStartCol, nStartRow+nSize, nTabRangeStart ),
952                 ScAddress( nEndCol, MAXROW, nTabRangeEnd )), 0, -(static_cast<SCsROW>(nSize)), 0 );
953         }
954         else
955             DelBroadcastAreasInRange( ScRange(
956                 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
957                 ScAddress( nEndCol, MAXROW, nTabRangeEnd ) ) );
958     }
959     while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
960 
961 	if ( ValidRow(nStartRow+nSize) )
962 	{
963         lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
964         do
965         {
966             UpdateReference( URM_INSDEL, nStartCol, nStartRow+nSize, nTabRangeStart,
967                              nEndCol, MAXROW, nTabRangeEnd,
968                              0, -(static_cast<SCsROW>(nSize)), 0, pRefUndoDoc, sal_True, false );
969         }
970         while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
971 	}
972 
973 	if (pUndoOutline)
974 		*pUndoOutline = sal_False;
975 
976 	for ( i = nStartTab; i <= nEndTab; i++)
977         if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
978 			pTab[i]->DeleteRow( nStartCol, nEndCol, nStartRow, nSize, pUndoOutline );
979 
980 	if ( ValidRow(nStartRow+nSize) )
981     {   // Listeners have been removed in UpdateReference
982 		for (i=0; i<=MAXTAB; i++)
983 			if (pTab[i])
984                 pTab[i]->StartNeededListeners();
985         // #69592# at least all cells using range names pointing relative to
986         // the moved range must recalculate
987 		for (i=0; i<=MAXTAB; i++)
988 			if (pTab[i])
989 				pTab[i]->SetRelNameDirty();
990 	}
991 
992 	SetAutoCalc( bOldAutoCalc );
993 	pChartListenerCollection->UpdateDirtyCharts();
994 }
995 
996 
997 void ScDocument::DeleteRow( const ScRange& rRange, ScDocument* pRefUndoDoc, sal_Bool* pUndoOutline )
998 {
999 	DeleteRow( rRange.aStart.Col(), rRange.aStart.Tab(),
1000 			   rRange.aEnd.Col(),   rRange.aEnd.Tab(),
1001 			   rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
1002 			   pRefUndoDoc, pUndoOutline );
1003 }
1004 
1005 
1006 sal_Bool ScDocument::CanInsertCol( const ScRange& rRange ) const
1007 {
1008 	SCCOL nStartCol = rRange.aStart.Col();
1009 	SCROW nStartRow = rRange.aStart.Row();
1010 	SCTAB nStartTab = rRange.aStart.Tab();
1011 	SCCOL nEndCol = rRange.aEnd.Col();
1012 	SCROW nEndRow = rRange.aEnd.Row();
1013 	SCTAB nEndTab = rRange.aEnd.Tab();
1014 	PutInOrder( nStartCol, nEndCol );
1015 	PutInOrder( nStartRow, nEndRow );
1016 	PutInOrder( nStartTab, nEndTab );
1017 	SCSIZE nSize = static_cast<SCSIZE>(nEndCol - nStartCol + 1);
1018 
1019 	sal_Bool bTest = sal_True;
1020 	for (SCTAB i=nStartTab; i<=nEndTab && bTest; i++)
1021 		if (pTab[i])
1022 			bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
1023 
1024 	return bTest;
1025 }
1026 
1027 
1028 sal_Bool ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
1029 							SCROW nEndRow,   SCTAB nEndTab,
1030                             SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
1031                             const ScMarkData* pTabMark )
1032 {
1033 	SCTAB i;
1034 
1035 	PutInOrder( nStartRow, nEndRow );
1036 	PutInOrder( nStartTab, nEndTab );
1037 	if ( pTabMark )
1038 	{
1039 	    nStartTab = 0;
1040 	    nEndTab = MAXTAB;
1041 	}
1042 
1043 	sal_Bool bTest = sal_True;
1044 	sal_Bool bRet = sal_False;
1045 	sal_Bool bOldAutoCalc = GetAutoCalc();
1046 	SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
1047 	for ( i = nStartTab; i <= nEndTab && bTest; i++)
1048         if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1049 			bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
1050 	if (bTest)
1051 	{
1052         // handle chunks of consecutive selected sheets together
1053         SCTAB nTabRangeStart = nStartTab;
1054         SCTAB nTabRangeEnd = nEndTab;
1055         lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
1056         do
1057         {
1058             UpdateBroadcastAreas( URM_INSDEL, ScRange(
1059                 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1060                 ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), static_cast<SCsCOL>(nSize), 0, 0 );
1061         }
1062         while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
1063 
1064         lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
1065         do
1066         {
1067             UpdateReference( URM_INSDEL, nStartCol, nStartRow, nTabRangeStart,
1068                              MAXCOL, nEndRow, nTabRangeEnd,
1069                              static_cast<SCsCOL>(nSize), 0, 0, pRefUndoDoc, sal_True, false );
1070         }
1071         while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
1072 
1073 		for (i=nStartTab; i<=nEndTab; i++)
1074             if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1075 				pTab[i]->InsertCol( nStartCol, nStartRow, nEndRow, nSize );
1076 
1077 		if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
1078 		{	// durch Restaurierung von Referenzen auf geloeschte Bereiche ist
1079 			// ein neues Listening faellig, bisherige Listener wurden in
1080 			// FormulaCell UpdateReference abgehaengt
1081 			StartAllListeners();
1082 		}
1083 		else
1084         {   // Listeners have been removed in UpdateReference
1085 			for (i=0; i<=MAXTAB; i++)
1086 				if (pTab[i])
1087                     pTab[i]->StartNeededListeners();
1088             // #69592# at least all cells using range names pointing relative
1089             // to the moved range must recalculate
1090 			for (i=0; i<=MAXTAB; i++)
1091 				if (pTab[i])
1092 					pTab[i]->SetRelNameDirty();
1093 		}
1094 		bRet = sal_True;
1095 	}
1096 	SetAutoCalc( bOldAutoCalc );
1097 	if ( bRet )
1098 		pChartListenerCollection->UpdateDirtyCharts();
1099 	return bRet;
1100 }
1101 
1102 
1103 sal_Bool ScDocument::InsertCol( const ScRange& rRange, ScDocument* pRefUndoDoc )
1104 {
1105 	return InsertCol( rRange.aStart.Row(), rRange.aStart.Tab(),
1106 					  rRange.aEnd.Row(),   rRange.aEnd.Tab(),
1107 					  rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
1108 					  pRefUndoDoc );
1109 }
1110 
1111 
1112 void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTAB nEndTab,
1113 								SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
1114                                 sal_Bool* pUndoOutline, const ScMarkData* pTabMark )
1115 {
1116 	SCTAB i;
1117 
1118 	PutInOrder( nStartRow, nEndRow );
1119 	PutInOrder( nStartTab, nEndTab );
1120 	if ( pTabMark )
1121 	{
1122 	    nStartTab = 0;
1123 	    nEndTab = MAXTAB;
1124 	}
1125 
1126 	sal_Bool bOldAutoCalc = GetAutoCalc();
1127 	SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
1128 
1129     // handle chunks of consecutive selected sheets together
1130     SCTAB nTabRangeStart = nStartTab;
1131     SCTAB nTabRangeEnd = nEndTab;
1132     lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
1133     do
1134     {
1135         if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1136         {
1137             DelBroadcastAreasInRange( ScRange(
1138                 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1139                 ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize-1), nEndRow, nTabRangeEnd ) ) );
1140             UpdateBroadcastAreas( URM_INSDEL, ScRange(
1141                 ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart ),
1142                 ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), -static_cast<SCsCOL>(nSize), 0, 0 );
1143         }
1144         else
1145             DelBroadcastAreasInRange( ScRange(
1146                 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1147                 ScAddress( MAXCOL, nEndRow, nTabRangeEnd ) ) );
1148     }
1149     while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
1150 
1151     if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1152 	{
1153         lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
1154         do
1155         {
1156             UpdateReference( URM_INSDEL, sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart,
1157                              MAXCOL, nEndRow, nTabRangeEnd,
1158                              -static_cast<SCsCOL>(nSize), 0, 0, pRefUndoDoc, sal_True, false );
1159         }
1160         while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
1161 	}
1162 
1163 	if (pUndoOutline)
1164 		*pUndoOutline = sal_False;
1165 
1166 	for ( i = nStartTab; i <= nEndTab; i++)
1167         if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1168 			pTab[i]->DeleteCol( nStartCol, nStartRow, nEndRow, nSize, pUndoOutline );
1169 
1170     if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1171     {   // Listeners have been removed in UpdateReference
1172 		for (i=0; i<=MAXTAB; i++)
1173 			if (pTab[i])
1174                 pTab[i]->StartNeededListeners();
1175         // #69592# at least all cells using range names pointing relative to
1176         // the moved range must recalculate
1177 		for (i=0; i<=MAXTAB; i++)
1178 			if (pTab[i])
1179 				pTab[i]->SetRelNameDirty();
1180 	}
1181 
1182 	SetAutoCalc( bOldAutoCalc );
1183 	pChartListenerCollection->UpdateDirtyCharts();
1184 }
1185 
1186 
1187 void ScDocument::DeleteCol( const ScRange& rRange, ScDocument* pRefUndoDoc, sal_Bool* pUndoOutline )
1188 {
1189 	DeleteCol( rRange.aStart.Row(), rRange.aStart.Tab(),
1190 			   rRange.aEnd.Row(),   rRange.aEnd.Tab(),
1191 			   rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
1192 			   pRefUndoDoc, pUndoOutline );
1193 }
1194 
1195 
1196 //	fuer Area-Links: Zellen einuegen/loeschen, wenn sich der Bereich veraendert
1197 //	(ohne Paint)
1198 
1199 
1200 void lcl_GetInsDelRanges( const ScRange& rOld, const ScRange& rNew,
1201 							ScRange& rColRange, sal_Bool& rInsCol, sal_Bool& rDelCol,
1202 							ScRange& rRowRange, sal_Bool& rInsRow, sal_Bool& rDelRow )
1203 {
1204 	DBG_ASSERT( rOld.aStart == rNew.aStart, "FitBlock: Anfang unterschiedlich" );
1205 
1206 	rInsCol = rDelCol = rInsRow = rDelRow = sal_False;
1207 
1208 	SCCOL nStartX = rOld.aStart.Col();
1209 	SCROW nStartY = rOld.aStart.Row();
1210 	SCCOL nOldEndX = rOld.aEnd.Col();
1211 	SCROW nOldEndY = rOld.aEnd.Row();
1212 	SCCOL nNewEndX = rNew.aEnd.Col();
1213 	SCROW nNewEndY = rNew.aEnd.Row();
1214 	SCTAB nTab = rOld.aStart.Tab();
1215 
1216 	//	wenn es mehr Zeilen werden, werden Spalten auf der alten Hoehe eingefuegt/geloescht
1217 	sal_Bool bGrowY = ( nNewEndY > nOldEndY );
1218 	SCROW nColEndY = bGrowY ? nOldEndY : nNewEndY;
1219 	SCCOL nRowEndX = bGrowY ? nNewEndX : nOldEndX;
1220 
1221 	//	Spalten
1222 
1223 	if ( nNewEndX > nOldEndX )			// Spalten einfuegen
1224 	{
1225 		rColRange = ScRange( nOldEndX+1, nStartY, nTab, nNewEndX, nColEndY, nTab );
1226 		rInsCol = sal_True;
1227 	}
1228 	else if ( nNewEndX < nOldEndX )		// Spalten loeschen
1229 	{
1230 		rColRange = ScRange( nNewEndX+1, nStartY, nTab, nOldEndX, nColEndY, nTab );
1231 		rDelCol = sal_True;
1232 	}
1233 
1234 	//	Zeilen
1235 
1236 	if ( nNewEndY > nOldEndY )			// Zeilen einfuegen
1237 	{
1238 		rRowRange = ScRange( nStartX, nOldEndY+1, nTab, nRowEndX, nNewEndY, nTab );
1239 		rInsRow = sal_True;
1240 	}
1241 	else if ( nNewEndY < nOldEndY )		// Zeilen loeschen
1242 	{
1243 		rRowRange = ScRange( nStartX, nNewEndY+1, nTab, nRowEndX, nOldEndY, nTab );
1244 		rDelRow = sal_True;
1245 	}
1246 }
1247 
1248 
1249 sal_Bool ScDocument::HasPartOfMerged( const ScRange& rRange )
1250 {
1251 	sal_Bool bPart = sal_False;
1252 	SCTAB nTab = rRange.aStart.Tab();
1253 
1254 	SCCOL nStartX = rRange.aStart.Col();
1255 	SCROW nStartY = rRange.aStart.Row();
1256 	SCCOL nEndX = rRange.aEnd.Col();
1257 	SCROW nEndY = rRange.aEnd.Row();
1258 
1259 	if (HasAttrib( nStartX, nStartY, nTab, nEndX, nEndY, nTab,
1260 						HASATTR_MERGED | HASATTR_OVERLAPPED ))
1261 	{
1262 		ExtendMerge( nStartX, nStartY, nEndX, nEndY, nTab );
1263 		ExtendOverlapped( nStartX, nStartY, nEndX, nEndY, nTab );
1264 
1265 		bPart = ( nStartX != rRange.aStart.Col() || nEndX != rRange.aEnd.Col() ||
1266 				  nStartY != rRange.aStart.Row() || nEndY != rRange.aEnd.Row() );
1267 	}
1268 	return bPart;
1269 }
1270 
1271 
1272 sal_Bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
1273 {
1274 	if ( rOld == rNew )
1275 		return sal_True;
1276 
1277 	sal_Bool bOk = sal_True;
1278 	sal_Bool bInsCol,bDelCol,bInsRow,bDelRow;
1279 	ScRange aColRange,aRowRange;
1280 	lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
1281 
1282 	if ( bInsCol && !CanInsertCol( aColRange ) )			// Zellen am Rand ?
1283 		bOk = sal_False;
1284 	if ( bInsRow && !CanInsertRow( aRowRange ) )			// Zellen am Rand ?
1285 		bOk = sal_False;
1286 
1287 	if ( bInsCol || bDelCol )
1288 	{
1289 		aColRange.aEnd.SetCol(MAXCOL);
1290 		if ( HasPartOfMerged(aColRange) )
1291 			bOk = sal_False;
1292 	}
1293 	if ( bInsRow || bDelRow )
1294 	{
1295 		aRowRange.aEnd.SetRow(MAXROW);
1296 		if ( HasPartOfMerged(aRowRange) )
1297 			bOk = sal_False;
1298 	}
1299 
1300 	return bOk;
1301 }
1302 
1303 
1304 void ScDocument::FitBlock( const ScRange& rOld, const ScRange& rNew, sal_Bool bClear )
1305 {
1306 	if (bClear)
1307 		DeleteAreaTab( rOld, IDF_ALL );
1308 
1309 	sal_Bool bInsCol,bDelCol,bInsRow,bDelRow;
1310 	ScRange aColRange,aRowRange;
1311 	lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
1312 
1313 	if ( bInsCol )
1314 		InsertCol( aColRange );			// Spalten zuerst einfuegen
1315 	if ( bInsRow )
1316 		InsertRow( aRowRange );
1317 
1318 	if ( bDelRow )
1319 		DeleteRow( aRowRange );			// Zeilen zuerst loeschen
1320 	if ( bDelCol )
1321 		DeleteCol( aColRange );
1322 
1323 	//	Referenzen um eingefuegte Zeilen erweitern
1324 
1325 	if ( bInsCol || bInsRow )
1326 	{
1327 		ScRange aGrowSource = rOld;
1328 		aGrowSource.aEnd.SetCol(Min( rOld.aEnd.Col(), rNew.aEnd.Col() ));
1329 		aGrowSource.aEnd.SetRow(Min( rOld.aEnd.Row(), rNew.aEnd.Row() ));
1330 		SCCOL nGrowX = bInsCol ? ( rNew.aEnd.Col() - rOld.aEnd.Col() ) : 0;
1331 		SCROW nGrowY = bInsRow ? ( rNew.aEnd.Row() - rOld.aEnd.Row() ) : 0;
1332 		UpdateGrow( aGrowSource, nGrowX, nGrowY );
1333 	}
1334 }
1335 
1336 
1337 void ScDocument::DeleteArea(SCCOL nCol1, SCROW nRow1,
1338 							SCCOL nCol2, SCROW nRow2,
1339 							const ScMarkData& rMark, sal_uInt16 nDelFlag)
1340 {
1341 	PutInOrder( nCol1, nCol2 );
1342 	PutInOrder( nRow1, nRow2 );
1343 	sal_Bool bOldAutoCalc = GetAutoCalc();
1344 	SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
1345 	for (SCTAB i = 0; i <= MAXTAB; i++)
1346 		if (pTab[i])
1347 			if ( rMark.GetTableSelect(i) || bIsUndo )
1348 				pTab[i]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
1349 	SetAutoCalc( bOldAutoCalc );
1350 }
1351 
1352 
1353 void ScDocument::DeleteAreaTab(SCCOL nCol1, SCROW nRow1,
1354 								SCCOL nCol2, SCROW nRow2,
1355 								SCTAB nTab, sal_uInt16 nDelFlag)
1356 {
1357 	PutInOrder( nCol1, nCol2 );
1358 	PutInOrder( nRow1, nRow2 );
1359 	if ( VALIDTAB(nTab) && pTab[nTab] )
1360 	{
1361 		sal_Bool bOldAutoCalc = GetAutoCalc();
1362 		SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
1363 		pTab[nTab]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
1364 		SetAutoCalc( bOldAutoCalc );
1365 	}
1366 }
1367 
1368 
1369 void ScDocument::DeleteAreaTab( const ScRange& rRange, sal_uInt16 nDelFlag )
1370 {
1371 	for ( SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); nTab++ )
1372 		DeleteAreaTab( rRange.aStart.Col(), rRange.aStart.Row(),
1373 					   rRange.aEnd.Col(),   rRange.aEnd.Row(),
1374 					   nTab, nDelFlag );
1375 }
1376 
1377 
1378 void ScDocument::InitUndoSelected( ScDocument* pSrcDoc, const ScMarkData& rTabSelection,
1379                                 sal_Bool bColInfo, sal_Bool bRowInfo )
1380 {
1381     if (bIsUndo)
1382     {
1383         Clear();
1384 
1385         xPoolHelper = pSrcDoc->xPoolHelper;
1386 
1387         String aString;
1388         for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
1389             if ( rTabSelection.GetTableSelect( nTab ) )
1390             {
1391                 pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1392                 nMaxTableNumber = nTab + 1;
1393             }
1394     }
1395     else
1396 		{
1397         DBG_ERROR("InitUndo");
1398 		}
1399 }
1400 
1401 
1402 void ScDocument::InitUndo( ScDocument* pSrcDoc, SCTAB nTab1, SCTAB nTab2,
1403 								sal_Bool bColInfo, sal_Bool bRowInfo )
1404 {
1405 	if (bIsUndo)
1406 	{
1407 		Clear();
1408 
1409 		xPoolHelper = pSrcDoc->xPoolHelper;
1410 
1411 		String aString;
1412 		for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
1413 			pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1414 
1415 		nMaxTableNumber = nTab2 + 1;
1416 	}
1417 	else
1418 	{
1419 		DBG_ERROR("InitUndo");
1420 	}
1421 }
1422 
1423 
1424 void ScDocument::AddUndoTab( SCTAB nTab1, SCTAB nTab2, sal_Bool bColInfo, sal_Bool bRowInfo )
1425 {
1426 	if (bIsUndo)
1427 	{
1428 		String aString;
1429 		for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
1430 			if (!pTab[nTab])
1431 				pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1432 
1433 		if ( nMaxTableNumber <= nTab2 )
1434 			nMaxTableNumber = nTab2 + 1;
1435 	}
1436 	else
1437 	{
1438 		DBG_ERROR("InitUndo");
1439 	}
1440 }
1441 
1442 
1443 void ScDocument::SetCutMode( sal_Bool bVal )
1444 {
1445 	if (bIsClip)
1446         GetClipParam().mbCutMode = bVal;
1447 	else
1448 	{
1449 		DBG_ERROR("SetCutMode without bIsClip");
1450 	}
1451 }
1452 
1453 
1454 sal_Bool ScDocument::IsCutMode()
1455 {
1456 	if (bIsClip)
1457 		return GetClipParam().mbCutMode;
1458 	else
1459 	{
1460 		DBG_ERROR("IsCutMode ohne bIsClip");
1461 		return sal_False;
1462 	}
1463 }
1464 
1465 
1466 void ScDocument::CopyToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1467 							SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1468 							sal_uInt16 nFlags, sal_Bool bOnlyMarked, ScDocument* pDestDoc,
1469 							const ScMarkData* pMarks, sal_Bool bColRowFlags )
1470 {
1471 	PutInOrder( nCol1, nCol2 );
1472 	PutInOrder( nRow1, nRow2 );
1473 	PutInOrder( nTab1, nTab2 );
1474 	if( !pDestDoc->aDocName.Len() )
1475 		pDestDoc->aDocName = aDocName;
1476 	if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
1477 	{
1478 		sal_Bool bOldAutoCalc = pDestDoc->GetAutoCalc();
1479 		pDestDoc->SetAutoCalc( sal_False );		// Mehrfachberechnungen vermeiden
1480 		for (SCTAB i = nTab1; i <= nTab2; i++)
1481 		{
1482 			if (pTab[i] && pDestDoc->pTab[i])
1483 				pTab[i]->CopyToTable( nCol1, nRow1, nCol2, nRow2, nFlags,
1484 									  bOnlyMarked, pDestDoc->pTab[i], pMarks,
1485 									  sal_False, bColRowFlags );
1486 		}
1487 		pDestDoc->SetAutoCalc( bOldAutoCalc );
1488 	}
1489 }
1490 
1491 
1492 void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1493 							SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1494 							sal_uInt16 nFlags, sal_Bool bOnlyMarked, ScDocument* pDestDoc,
1495 							const ScMarkData* pMarks)
1496 {
1497 	PutInOrder( nCol1, nCol2 );
1498 	PutInOrder( nRow1, nRow2 );
1499 	PutInOrder( nTab1, nTab2 );
1500 	if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
1501 	{
1502 		sal_Bool bOldAutoCalc = pDestDoc->GetAutoCalc();
1503 		pDestDoc->SetAutoCalc( sal_False );		// Mehrfachberechnungen vermeiden
1504 		if (nTab1 > 0)
1505 			CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, sal_False, pDestDoc, pMarks );
1506 
1507 		for (SCTAB i = nTab1; i <= nTab2; i++)
1508 		{
1509 			if (pTab[i] && pDestDoc->pTab[i])
1510 				pTab[i]->UndoToTable(nCol1, nRow1, nCol2, nRow2, nFlags,
1511 									bOnlyMarked, pDestDoc->pTab[i], pMarks);
1512 		}
1513 
1514 		if (nTab2 < MAXTAB)
1515 			CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA, sal_False, pDestDoc, pMarks );
1516 		pDestDoc->SetAutoCalc( bOldAutoCalc );
1517 	}
1518 }
1519 
1520 
1521 void ScDocument::CopyToDocument(const ScRange& rRange,
1522 							sal_uInt16 nFlags, sal_Bool bOnlyMarked, ScDocument* pDestDoc,
1523 							const ScMarkData* pMarks, sal_Bool bColRowFlags)
1524 {
1525 	ScRange aNewRange = rRange;
1526 	aNewRange.Justify();
1527 
1528 	if( !pDestDoc->aDocName.Len() )
1529 		pDestDoc->aDocName = aDocName;
1530 	sal_Bool bOldAutoCalc = pDestDoc->GetAutoCalc();
1531 	pDestDoc->SetAutoCalc( sal_False );		// Mehrfachberechnungen vermeiden
1532 	for (SCTAB i = aNewRange.aStart.Tab(); i <= aNewRange.aEnd.Tab(); i++)
1533 		if (pTab[i] && pDestDoc->pTab[i])
1534 			pTab[i]->CopyToTable(aNewRange.aStart.Col(), aNewRange.aStart.Row(),
1535 								 aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
1536 								 nFlags, bOnlyMarked, pDestDoc->pTab[i],
1537 								 pMarks, sal_False, bColRowFlags);
1538 	pDestDoc->SetAutoCalc( bOldAutoCalc );
1539 }
1540 
1541 
1542 void ScDocument::UndoToDocument(const ScRange& rRange,
1543 							sal_uInt16 nFlags, sal_Bool bOnlyMarked, ScDocument* pDestDoc,
1544 							const ScMarkData* pMarks)
1545 {
1546 	ScRange aNewRange = rRange;
1547 	aNewRange.Justify();
1548 	SCTAB nTab1 = aNewRange.aStart.Tab();
1549 	SCTAB nTab2 = aNewRange.aEnd.Tab();
1550 
1551 	sal_Bool bOldAutoCalc = pDestDoc->GetAutoCalc();
1552 	pDestDoc->SetAutoCalc( sal_False );		// Mehrfachberechnungen vermeiden
1553 	if (nTab1 > 0)
1554 		CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, sal_False, pDestDoc, pMarks );
1555 
1556 	for (SCTAB i = nTab1; i <= nTab2; i++)
1557 	{
1558 		if (pTab[i] && pDestDoc->pTab[i])
1559 			pTab[i]->UndoToTable(aNewRange.aStart.Col(), aNewRange.aStart.Row(),
1560 									aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
1561 									nFlags, bOnlyMarked, pDestDoc->pTab[i], pMarks);
1562 	}
1563 
1564 	if (nTab2 < MAXTAB)
1565 		CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA, sal_False, pDestDoc, pMarks );
1566 	pDestDoc->SetAutoCalc( bOldAutoCalc );
1567 }
1568 
1569 void ScDocument::CopyToClip(const ScClipParam& rClipParam,
1570                             ScDocument* pClipDoc, const ScMarkData* pMarks,
1571                             bool bAllTabs, bool bKeepScenarioFlags, bool bIncludeObjects, bool bCloneNoteCaptions)
1572 {
1573     DBG_ASSERT( bAllTabs || pMarks, "CopyToClip: ScMarkData fehlt" );
1574 
1575     if (bIsClip)
1576         return;
1577 
1578     if (!pClipDoc)
1579     {
1580         DBG_ERROR("CopyToClip: no ClipDoc");
1581         pClipDoc = SC_MOD()->GetClipDoc();
1582     }
1583 
1584     pClipDoc->aDocName = aDocName;
1585     pClipDoc->SetClipParam(rClipParam);
1586     pClipDoc->ResetClip(this, pMarks);
1587 
1588     ScRange aClipRange = rClipParam.getWholeRange();
1589     CopyRangeNamesToClip(pClipDoc, aClipRange, pMarks, bAllTabs);
1590 
1591     for (SCTAB i = 0; i <= MAXTAB; ++i)
1592     {
1593         if (!pTab[i] || !pClipDoc->pTab[i])
1594             continue;
1595 
1596         if (pMarks && !pMarks->GetTableSelect(i))
1597             continue;
1598 
1599         pTab[i]->CopyToClip(rClipParam.maRanges, pClipDoc->pTab[i], bKeepScenarioFlags, bCloneNoteCaptions);
1600 
1601         if (pDrawLayer && bIncludeObjects)
1602         {
1603             //	also copy drawing objects
1604             Rectangle aObjRect = GetMMRect(
1605                 aClipRange.aStart.Col(), aClipRange.aStart.Row(), aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i);
1606             pDrawLayer->CopyToClip(pClipDoc, i, aObjRect);
1607         }
1608     }
1609 
1610     // Make sure to mark overlapped cells.
1611     pClipDoc->ExtendMerge(aClipRange, true);
1612 }
1613 
1614 void ScDocument::CopyTabToClip(SCCOL nCol1, SCROW nRow1,
1615 								SCCOL nCol2, SCROW nRow2,
1616 								SCTAB nTab, ScDocument* pClipDoc)
1617 {
1618 	if (!bIsClip)
1619 	{
1620 		PutInOrder( nCol1, nCol2 );
1621 		PutInOrder( nRow1, nRow2 );
1622 		if (!pClipDoc)
1623 		{
1624 			DBG_ERROR("CopyTabToClip: no ClipDoc");
1625 			pClipDoc = SC_MOD()->GetClipDoc();
1626 		}
1627 
1628         ScClipParam& rClipParam = pClipDoc->GetClipParam();
1629 		pClipDoc->aDocName = aDocName;
1630         rClipParam.maRanges.RemoveAll();
1631         rClipParam.maRanges.Append(ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0));
1632 		pClipDoc->ResetClip( this, nTab );
1633 
1634 		if (pTab[nTab] && pClipDoc->pTab[nTab])
1635             pTab[nTab]->CopyToClip(nCol1, nRow1, nCol2, nRow2, pClipDoc->pTab[nTab], sal_False, sal_True);
1636 
1637         pClipDoc->GetClipParam().mbCutMode = false;
1638 	}
1639 }
1640 
1641 
1642 void ScDocument::TransposeClip( ScDocument* pTransClip, sal_uInt16 nFlags, sal_Bool bAsLink )
1643 {
1644 	DBG_ASSERT( bIsClip && pTransClip && pTransClip->bIsClip,
1645 					"TransposeClip mit falschem Dokument" );
1646 
1647 		//	initialisieren
1648 		//	-> pTransClip muss vor dem Original-Dokument geloescht werden!
1649 
1650 	pTransClip->ResetClip(this, (ScMarkData*)NULL);		// alle
1651 
1652 		//	Bereiche uebernehmen
1653 
1654 	pTransClip->pRangeName->FreeAll();
1655 	for (sal_uInt16 i = 0; i < pRangeName->GetCount(); i++)		//! DB-Bereiche Pivot-Bereiche auch !!!
1656 	{
1657 		sal_uInt16 nIndex = ((ScRangeData*)((*pRangeName)[i]))->GetIndex();
1658 		ScRangeData* pData = new ScRangeData(*((*pRangeName)[i]));
1659 		if (!pTransClip->pRangeName->Insert(pData))
1660 			delete pData;
1661 		else
1662 			pData->SetIndex(nIndex);
1663 	}
1664 
1665 		//	Daten
1666 
1667     ScRange aClipRange = GetClipParam().getWholeRange();
1668 	if ( ValidRow(aClipRange.aEnd.Row()-aClipRange.aStart.Row()) )
1669 	{
1670 		for (SCTAB i=0; i<=MAXTAB; i++)
1671 			if (pTab[i])
1672 			{
1673 				DBG_ASSERT( pTransClip->pTab[i], "TransposeClip: Tabelle nicht da" );
1674 				pTab[i]->TransposeClip( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
1675 											aClipRange.aEnd.Col(), aClipRange.aEnd.Row(),
1676 											pTransClip->pTab[i], nFlags, bAsLink );
1677 
1678 				if ( pDrawLayer && ( nFlags & IDF_OBJECTS ) )
1679 				{
1680 					//	Drawing objects are copied to the new area without transposing.
1681 					//	CopyFromClip is used to adjust the objects to the transposed block's
1682 					//	cell range area.
1683 					//	(pDrawLayer in the original clipboard document is set only if there
1684 					//	are drawing objects to copy)
1685 
1686 					pTransClip->InitDrawLayer();
1687 					Rectangle aSourceRect = GetMMRect( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
1688 														aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i );
1689 					Rectangle aDestRect = pTransClip->GetMMRect( 0, 0,
1690                             static_cast<SCCOL>(aClipRange.aEnd.Row() - aClipRange.aStart.Row()),
1691                             static_cast<SCROW>(aClipRange.aEnd.Col() - aClipRange.aStart.Col()), i );
1692 					pTransClip->pDrawLayer->CopyFromClip( pDrawLayer, i, aSourceRect, ScAddress(0,0,i), aDestRect );
1693 				}
1694 			}
1695 
1696         pTransClip->SetClipParam(GetClipParam());
1697         pTransClip->GetClipParam().transpose();
1698 	}
1699 	else
1700 	{
1701 		DBG_ERROR("TransposeClip: zu gross");
1702 	}
1703 
1704 		//	Dies passiert erst beim Einfuegen...
1705 
1706     GetClipParam().mbCutMode = false;
1707 }
1708 
1709 void ScDocument::CopyRangeNamesToClip(ScDocument* pClipDoc, const ScRange& rClipRange, const ScMarkData* pMarks, bool bAllTabs)
1710 {
1711     std::set<sal_uInt16> aUsedNames;        // indexes of named ranges that are used in the copied cells
1712     for (SCTAB i = 0; i <= MAXTAB; ++i)
1713         if (pTab[i] && pClipDoc->pTab[i])
1714             if ( bAllTabs || !pMarks || pMarks->GetTableSelect(i) )
1715                 pTab[i]->FindRangeNamesInUse(
1716                     rClipRange.aStart.Col(), rClipRange.aStart.Row(),
1717                     rClipRange.aEnd.Col(), rClipRange.aEnd.Row(), aUsedNames);
1718 
1719     pClipDoc->pRangeName->FreeAll();
1720     for (sal_uInt16 i = 0; i < pRangeName->GetCount(); i++)        //! DB-Bereiche Pivot-Bereiche auch !!!
1721     {
1722         sal_uInt16 nIndex = ((ScRangeData*)((*pRangeName)[i]))->GetIndex();
1723         bool bInUse = ( aUsedNames.find(nIndex) != aUsedNames.end() );
1724         if (bInUse)
1725         {
1726             ScRangeData* pData = new ScRangeData(*((*pRangeName)[i]));
1727             if (!pClipDoc->pRangeName->Insert(pData))
1728                 delete pData;
1729             else
1730                 pData->SetIndex(nIndex);
1731         }
1732     }
1733 }
1734 
1735 ScDocument::NumFmtMergeHandler::NumFmtMergeHandler(ScDocument* pDoc, ScDocument* pSrcDoc) :
1736         mpDoc(pDoc)
1737 {
1738     mpDoc->MergeNumberFormatter(pSrcDoc);
1739 }
1740 
1741 ScDocument::NumFmtMergeHandler::~NumFmtMergeHandler()
1742 {
1743     mpDoc->pFormatExchangeList = NULL;
1744 }
1745 
1746 void ScDocument::MergeNumberFormatter(ScDocument* pSrcDoc)
1747 {
1748     SvNumberFormatter* pThisFormatter = xPoolHelper->GetFormTable();
1749     SvNumberFormatter* pOtherFormatter = pSrcDoc->xPoolHelper->GetFormTable();
1750     if (pOtherFormatter && pOtherFormatter != pThisFormatter)
1751     {
1752         SvNumberFormatterIndexTable* pExchangeList =
1753                  pThisFormatter->MergeFormatter(*(pOtherFormatter));
1754         if (pExchangeList->Count() > 0)
1755             pFormatExchangeList = pExchangeList;
1756     }
1757 }
1758 
1759 void ScDocument::CopyRangeNamesFromClip(ScDocument* pClipDoc, ScClipRangeNameData& rRangeNames)
1760 {
1761     sal_uInt16 nClipRangeNameCount = pClipDoc->pRangeName->GetCount();
1762     ScClipRangeNameData aClipRangeNames;
1763 
1764     // array containing range names which might need update of indices
1765     aClipRangeNames.mpRangeNames.resize(nClipRangeNameCount, NULL);
1766 
1767     for (sal_uInt16 i = 0; i < nClipRangeNameCount; ++i)        //! DB-Bereiche Pivot-Bereiche auch
1768     {
1769         /*  Copy only if the name doesn't exist in this document.
1770             If it exists we use the already existing name instead,
1771             another possibility could be to create new names if
1772             documents differ.
1773             A proper solution would ask the user how to proceed.
1774             The adjustment of the indices in the formulas is done later.
1775         */
1776         ScRangeData* pClipRangeData = (*pClipDoc->pRangeName)[i];
1777         sal_uInt16 k;
1778         if ( pRangeName->SearchName( pClipRangeData->GetName(), k ) )
1779         {
1780             aClipRangeNames.mpRangeNames[i] = NULL;  // range name not inserted
1781             sal_uInt16 nOldIndex = pClipRangeData->GetIndex();
1782             sal_uInt16 nNewIndex = ((*pRangeName)[k])->GetIndex();
1783             aClipRangeNames.insert(nOldIndex, nNewIndex);
1784             if ( !aClipRangeNames.mbReplace )
1785                 aClipRangeNames.mbReplace = ( nOldIndex != nNewIndex );
1786         }
1787         else
1788         {
1789             ScRangeData* pData = new ScRangeData( *pClipRangeData );
1790             pData->SetDocument(this);
1791             if ( pRangeName->FindIndex( pData->GetIndex() ) )
1792                 pData->SetIndex(0);     // need new index, done in Insert
1793             if ( pRangeName->Insert( pData ) )
1794             {
1795                 aClipRangeNames.mpRangeNames[i] = pData;
1796                 sal_uInt16 nOldIndex = pClipRangeData->GetIndex();
1797                 sal_uInt16 nNewIndex = pData->GetIndex();
1798                 aClipRangeNames.insert(nOldIndex, nNewIndex);
1799                 if ( !aClipRangeNames.mbReplace )
1800                     aClipRangeNames.mbReplace = ( nOldIndex != nNewIndex );
1801             }
1802             else
1803             {   // must be an overflow
1804                 delete pData;
1805                 aClipRangeNames.mpRangeNames[i] = NULL;
1806                 aClipRangeNames.insert(pClipRangeData->GetIndex(), 0);
1807                 aClipRangeNames.mbReplace = true;
1808             }
1809         }
1810     }
1811     rRangeNames = aClipRangeNames;
1812 }
1813 
1814 void ScDocument::UpdateRangeNamesInFormulas(
1815     ScClipRangeNameData& rRangeNames, const ScRangeList& rDestRanges, const ScMarkData& rMark,
1816     SCCOL nXw, SCROW nYw)
1817 {
1818     // nXw and nYw are the extra width and height of the destination range
1819     // extended due to presence of merged cell(s).
1820 
1821     if (!rRangeNames.mbReplace)
1822         return;
1823 
1824     // first update all inserted named formulas if they contain other
1825     // range names and used indices changed
1826     size_t nRangeNameCount = rRangeNames.mpRangeNames.size();
1827     for (size_t i = 0; i < nRangeNameCount; ++i)        //! DB-Bereiche Pivot-Bereiche auch
1828     {
1829         if ( rRangeNames.mpRangeNames[i] )
1830             rRangeNames.mpRangeNames[i]->ReplaceRangeNamesInUse(rRangeNames.maRangeMap);
1831     }
1832     // then update the formulas, they might need just the updated range names
1833     for (sal_uLong nRange = 0; nRange < rDestRanges.Count(); ++nRange)
1834     {
1835         const ScRange* pRange = rDestRanges.GetObject( nRange);
1836         SCCOL nCol1 = pRange->aStart.Col();
1837         SCROW nRow1 = pRange->aStart.Row();
1838         SCCOL nCol2 = pRange->aEnd.Col();
1839         SCROW nRow2 = pRange->aEnd.Row();
1840 
1841         SCCOL nC1 = nCol1;
1842         SCROW nR1 = nRow1;
1843         SCCOL nC2 = nC1 + nXw;
1844         if (nC2 > nCol2)
1845             nC2 = nCol2;
1846         SCROW nR2 = nR1 + nYw;
1847         if (nR2 > nRow2)
1848             nR2 = nRow2;
1849         do
1850         {
1851             do
1852             {
1853                 for (SCTAB k = 0; k <= MAXTAB; k++)
1854                 {
1855                     if ( pTab[k] && rMark.GetTableSelect(k) )
1856                         pTab[k]->ReplaceRangeNamesInUse(nC1, nR1,
1857                             nC2, nR2, rRangeNames.maRangeMap);
1858                 }
1859                 nC1 = nC2 + 1;
1860                 nC2 = Min((SCCOL)(nC1 + nXw), nCol2);
1861             } while (nC1 <= nCol2);
1862             nC1 = nCol1;
1863             nC2 = nC1 + nXw;
1864             if (nC2 > nCol2)
1865                 nC2 = nCol2;
1866             nR1 = nR2 + 1;
1867             nR2 = Min((SCROW)(nR1 + nYw), nRow2);
1868         } while (nR1 <= nRow2);
1869     }
1870 }
1871 
1872 ScClipParam& ScDocument::GetClipParam()
1873 {
1874     if (!mpClipParam.get())
1875         mpClipParam.reset(new ScClipParam);
1876 
1877     return *mpClipParam;
1878 }
1879 
1880 void ScDocument::SetClipParam(const ScClipParam& rParam)
1881 {
1882     mpClipParam.reset(new ScClipParam(rParam));
1883 }
1884 
1885 sal_Bool ScDocument::IsClipboardSource() const
1886 {
1887 	ScDocument* pClipDoc = SC_MOD()->GetClipDoc();
1888 	return pClipDoc && pClipDoc->xPoolHelper.isValid() &&
1889 			xPoolHelper->GetDocPool() == pClipDoc->xPoolHelper->GetDocPool();
1890 }
1891 
1892 
1893 void ScDocument::StartListeningFromClip( SCCOL nCol1, SCROW nRow1,
1894 										SCCOL nCol2, SCROW nRow2,
1895 										const ScMarkData& rMark, sal_uInt16 nInsFlag )
1896 {
1897 	if (nInsFlag & IDF_CONTENTS)
1898 	{
1899 		for (SCTAB i = 0; i <= MAXTAB; i++)
1900 			if (pTab[i])
1901 				if (rMark.GetTableSelect(i))
1902 					pTab[i]->StartListeningInArea( nCol1, nRow1, nCol2, nRow2 );
1903 	}
1904 }
1905 
1906 
1907 void ScDocument::BroadcastFromClip( SCCOL nCol1, SCROW nRow1,
1908 									SCCOL nCol2, SCROW nRow2,
1909 									const ScMarkData& rMark, sal_uInt16 nInsFlag )
1910 {
1911 	if (nInsFlag & IDF_CONTENTS)
1912 	{
1913         ScBulkBroadcast aBulkBroadcast( GetBASM());
1914         for (SCTAB i = 0; i <= MAXTAB; i++)
1915             if (pTab[i])
1916                 if (rMark.GetTableSelect(i))
1917                     pTab[i]->BroadcastInArea( nCol1, nRow1, nCol2, nRow2 );
1918 	}
1919 }
1920 
1921 
1922 void ScDocument::CopyBlockFromClip( SCCOL nCol1, SCROW nRow1,
1923 									SCCOL nCol2, SCROW nRow2,
1924 									const ScMarkData& rMark,
1925 									SCsCOL nDx, SCsROW nDy,
1926 									const ScCopyBlockFromClipParams* pCBFCP )
1927 {
1928 	ScTable** ppClipTab = pCBFCP->pClipDoc->pTab;
1929 	SCTAB nTabEnd = pCBFCP->nTabEnd;
1930 	SCTAB nClipTab = 0;
1931 	for (SCTAB i = pCBFCP->nTabStart; i <= nTabEnd; i++)
1932     {
1933         if (pTab[i] && rMark.GetTableSelect(i) )
1934         {
1935             while (!ppClipTab[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
1936 
1937             pTab[i]->CopyFromClip( nCol1, nRow1, nCol2, nRow2, nDx, nDy,
1938                 pCBFCP->nInsFlag, pCBFCP->bAsLink, pCBFCP->bSkipAttrForEmpty, ppClipTab[nClipTab] );
1939 
1940 			if ( pCBFCP->pClipDoc->pDrawLayer && ( pCBFCP->nInsFlag & IDF_OBJECTS ) )
1941 			{
1942 				//	also copy drawing objects
1943 
1944 				// drawing layer must be created before calling CopyFromClip
1945 				// (ScDocShell::MakeDrawLayer also does InitItems etc.)
1946 				DBG_ASSERT( pDrawLayer, "CopyBlockFromClip: No drawing layer" );
1947 				if ( pDrawLayer )
1948 				{
1949 					//	For GetMMRect, the row heights in the target document must already be valid
1950 					//	(copied in an extra step before pasting, or updated after pasting cells, but
1951 					//	before pasting objects).
1952 
1953 					Rectangle aSourceRect = pCBFCP->pClipDoc->GetMMRect(
1954 									nCol1-nDx, nRow1-nDy, nCol2-nDx, nRow2-nDy, nClipTab );
1955 					Rectangle aDestRect = GetMMRect( nCol1, nRow1, nCol2, nRow2, i );
1956 					pDrawLayer->CopyFromClip( pCBFCP->pClipDoc->pDrawLayer, nClipTab, aSourceRect,
1957 												ScAddress( nCol1, nRow1, i ), aDestRect );
1958 				}
1959 			}
1960 
1961             nClipTab = (nClipTab+1) % (MAXTAB+1);
1962         }
1963     }
1964     if ( pCBFCP->nInsFlag & IDF_CONTENTS )
1965 	{
1966 		nClipTab = 0;
1967 		for (SCTAB i = pCBFCP->nTabStart; i <= nTabEnd; i++)
1968         {
1969             if (pTab[i] && rMark.GetTableSelect(i) )
1970             {
1971                 while (!ppClipTab[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
1972                 SCsTAB nDz = ((SCsTAB)i) - nClipTab;
1973 
1974                 //  #89081# ranges of consecutive selected tables (in clipboard and dest. doc)
1975                 //  must be handled in one UpdateReference call
1976                 SCTAB nFollow = 0;
1977                 while ( i + nFollow < nTabEnd
1978                         && rMark.GetTableSelect( i + nFollow + 1 )
1979                         && nClipTab + nFollow < MAXTAB
1980                         && ppClipTab[nClipTab + nFollow + 1] )
1981                     ++nFollow;
1982 
1983                 if ( pCBFCP->pClipDoc->GetClipParam().mbCutMode )
1984                 {
1985                     sal_Bool bOldInserting = IsInsertingFromOtherDoc();
1986                     SetInsertingFromOtherDoc( sal_True);
1987                     UpdateReference( URM_MOVE,
1988                         nCol1, nRow1, i, nCol2, nRow2, i+nFollow,
1989                         nDx, nDy, nDz, pCBFCP->pRefUndoDoc, sal_False );
1990                     SetInsertingFromOtherDoc( bOldInserting);
1991                 }
1992                 else
1993                     UpdateReference( URM_COPY,
1994                         nCol1, nRow1, i, nCol2, nRow2, i+nFollow,
1995                         nDx, nDy, nDz, pCBFCP->pRefUndoDoc, sal_False );
1996 
1997                 nClipTab = (nClipTab+nFollow+1) % (MAXTAB+1);
1998                 i = sal::static_int_cast<SCTAB>( i + nFollow );
1999             }
2000         }
2001 	}
2002 }
2003 
2004 
2005 void ScDocument::CopyNonFilteredFromClip( SCCOL nCol1, SCROW nRow1,
2006 									SCCOL nCol2, SCROW nRow2,
2007 									const ScMarkData& rMark,
2008                                     SCsCOL nDx, SCsROW /* nDy */,
2009 									const ScCopyBlockFromClipParams* pCBFCP,
2010                                     SCROW & rClipStartRow )
2011 {
2012 	//	call CopyBlockFromClip for ranges of consecutive non-filtered rows
2013 	//	nCol1/nRow1 etc. is in target doc
2014 
2015 	//	filtered state is taken from first used table in clipboard (as in GetClipArea)
2016 	SCTAB nFlagTab = 0;
2017 	ScTable** ppClipTab = pCBFCP->pClipDoc->pTab;
2018 	while ( nFlagTab < MAXTAB && !ppClipTab[nFlagTab] )
2019 		++nFlagTab;
2020 
2021 	SCROW nSourceRow = rClipStartRow;
2022 	SCROW nSourceEnd = 0;
2023     if (pCBFCP->pClipDoc->GetClipParam().maRanges.Count())
2024         nSourceEnd = pCBFCP->pClipDoc->GetClipParam().maRanges.First()->aEnd.Row();
2025 	SCROW nDestRow = nRow1;
2026 
2027 	while ( nSourceRow <= nSourceEnd && nDestRow <= nRow2 )
2028 	{
2029 		// skip filtered rows
2030         nSourceRow = pCBFCP->pClipDoc->FirstNonFilteredRow(nSourceRow, nSourceEnd, nFlagTab);
2031 
2032 		if ( nSourceRow <= nSourceEnd )
2033 		{
2034 			// look for more non-filtered rows following
2035             SCROW nLastRow = nSourceRow;
2036             pCBFCP->pClipDoc->RowFiltered(nSourceRow, nFlagTab, NULL, &nLastRow);
2037             SCROW nFollow = nLastRow - nSourceRow;
2038 
2039             if (nFollow > nSourceEnd - nSourceRow)
2040                 nFollow = nSourceEnd - nSourceRow;
2041             if (nFollow > nRow2 - nDestRow)
2042                 nFollow = nRow2 - nDestRow;
2043 
2044 			SCsROW nNewDy = ((SCsROW)nDestRow) - nSourceRow;
2045 			CopyBlockFromClip( nCol1, nDestRow, nCol2, nDestRow + nFollow, rMark, nDx, nNewDy, pCBFCP );
2046 
2047 			nSourceRow += nFollow + 1;
2048 			nDestRow += nFollow + 1;
2049 		}
2050 	}
2051     rClipStartRow = nSourceRow;
2052 }
2053 
2054 
2055 void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMark,
2056 								sal_uInt16 nInsFlag,
2057 								ScDocument* pRefUndoDoc, ScDocument* pClipDoc, sal_Bool bResetCut,
2058 								sal_Bool bAsLink, sal_Bool bIncludeFiltered, sal_Bool bSkipAttrForEmpty,
2059                                 const ScRangeList * pDestRanges )
2060 {
2061 	if (!bIsClip)
2062 	{
2063 		if (!pClipDoc)
2064 		{
2065 			DBG_ERROR("CopyFromClip: no ClipDoc");
2066 			pClipDoc = SC_MOD()->GetClipDoc();
2067 		}
2068 		if (pClipDoc->bIsClip && pClipDoc->GetTableCount())
2069 		{
2070 			sal_Bool bOldAutoCalc = GetAutoCalc();
2071 			SetAutoCalc( sal_False );	// avoid multiple recalculations
2072 
2073             NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
2074 
2075             ScClipRangeNameData aClipRangeNames;
2076             CopyRangeNamesFromClip(pClipDoc, aClipRangeNames);
2077 
2078 			SCCOL nAllCol1 = rDestRange.aStart.Col();
2079 			SCROW nAllRow1 = rDestRange.aStart.Row();
2080 			SCCOL nAllCol2 = rDestRange.aEnd.Col();
2081 			SCROW nAllRow2 = rDestRange.aEnd.Row();
2082 
2083             SCCOL nXw = 0;
2084             SCROW nYw = 0;
2085             ScRange aClipRange = pClipDoc->GetClipParam().getWholeRange();
2086             for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)    // find largest merge overlap
2087                 if (pClipDoc->pTab[nTab])                   // all sheets of the clipboard content
2088                 {
2089                     SCCOL nThisEndX = aClipRange.aEnd.Col();
2090                     SCROW nThisEndY = aClipRange.aEnd.Row();
2091                     pClipDoc->ExtendMerge( aClipRange.aStart.Col(),
2092                                             aClipRange.aStart.Row(),
2093                                             nThisEndX, nThisEndY, nTab );
2094                     // only extra value from ExtendMerge
2095                     nThisEndX = sal::static_int_cast<SCCOL>( nThisEndX - aClipRange.aEnd.Col() );
2096                     nThisEndY = sal::static_int_cast<SCROW>( nThisEndY - aClipRange.aEnd.Row() );
2097                     if ( nThisEndX > nXw )
2098                         nXw = nThisEndX;
2099                     if ( nThisEndY > nYw )
2100                         nYw = nThisEndY;
2101                 }
2102 
2103             SCCOL nDestAddX;
2104             SCROW nDestAddY;
2105             pClipDoc->GetClipArea( nDestAddX, nDestAddY, bIncludeFiltered );
2106             nXw = sal::static_int_cast<SCCOL>( nXw + nDestAddX );
2107             nYw = sal::static_int_cast<SCROW>( nYw + nDestAddY );   // ClipArea, plus ExtendMerge value
2108 
2109             /*  Decide which contents to delete before copying. Delete all
2110                 contents if nInsFlag contains any real content flag.
2111                 #i102056# Notes are pasted from clipboard in a second pass,
2112                 together with the special flag IDF_ADDNOTES that states to not
2113                 overwrite/delete existing cells but to insert the notes into
2114                 these cells. In this case, just delete old notes from the
2115                 destination area. */
2116 			sal_uInt16 nDelFlag = IDF_NONE;
2117             if ( (nInsFlag & (IDF_CONTENTS | IDF_ADDNOTES)) == (IDF_NOTE | IDF_ADDNOTES) )
2118                 nDelFlag |= IDF_NOTE;
2119             else if ( nInsFlag & IDF_CONTENTS )
2120 				nDelFlag |= IDF_CONTENTS;
2121 			//	With bSkipAttrForEmpty, don't remove attributes, copy
2122 			//	on top of existing attributes instead.
2123 			if ( ( nInsFlag & IDF_ATTRIB ) && !bSkipAttrForEmpty )
2124 				nDelFlag |= IDF_ATTRIB;
2125 
2126 			ScCopyBlockFromClipParams aCBFCP;
2127 			aCBFCP.pRefUndoDoc = pRefUndoDoc;
2128 			aCBFCP.pClipDoc = pClipDoc;
2129 			aCBFCP.nInsFlag = nInsFlag;
2130 			aCBFCP.bAsLink	= bAsLink;
2131 			aCBFCP.bSkipAttrForEmpty = bSkipAttrForEmpty;
2132 			aCBFCP.nTabStart = MAXTAB;		// wird in der Schleife angepasst
2133 			aCBFCP.nTabEnd = 0;				// wird in der Schleife angepasst
2134 
2135 			//	Inc/DecRecalcLevel einmal aussen, damit nicht fuer jeden Block
2136 			//	die Draw-Seitengroesse neu berechnet werden muss
2137 			//!	nur wenn ganze Zeilen/Spalten kopiert werden?
2138 
2139 			for (SCTAB j = 0; j <= MAXTAB; j++)
2140 				if (pTab[j] && rMark.GetTableSelect(j))
2141 				{
2142 					if ( j < aCBFCP.nTabStart )
2143 						aCBFCP.nTabStart = j;
2144 					aCBFCP.nTabEnd = j;
2145 					pTab[j]->IncRecalcLevel();
2146 				}
2147 
2148             ScRangeList aLocalRangeList;
2149             if (!pDestRanges)
2150             {
2151                 aLocalRangeList.Append( rDestRange);
2152                 pDestRanges = &aLocalRangeList;
2153             }
2154 
2155 			bInsertingFromOtherDoc = sal_True;	// kein Broadcast/Listener aufbauen bei Insert
2156 
2157 			// bei mindestens 64 Zeilen wird in ScColumn::CopyFromClip voralloziert
2158 			sal_Bool bDoDouble = ( nYw < 64 && nAllRow2 - nAllRow1 > 64);
2159 			sal_Bool bOldDouble = ScColumn::bDoubleAlloc;
2160 			if (bDoDouble)
2161 				ScColumn::bDoubleAlloc = sal_True;
2162 
2163             SCCOL nClipStartCol = aClipRange.aStart.Col();
2164             SCROW nClipStartRow = aClipRange.aStart.Row();
2165             // WaE: commented because unused:   SCCOL nClipEndCol = pClipDoc->aClipRange.aEnd.Col();
2166             SCROW nClipEndRow = aClipRange.aEnd.Row();
2167             for (sal_uLong nRange = 0; nRange < pDestRanges->Count(); ++nRange)
2168             {
2169                 const ScRange* pRange = pDestRanges->GetObject( nRange);
2170                 SCCOL nCol1 = pRange->aStart.Col();
2171                 SCROW nRow1 = pRange->aStart.Row();
2172                 SCCOL nCol2 = pRange->aEnd.Col();
2173                 SCROW nRow2 = pRange->aEnd.Row();
2174 
2175                 DeleteArea(nCol1, nRow1, nCol2, nRow2, rMark, nDelFlag);
2176 
2177                 SCCOL nC1 = nCol1;
2178                 SCROW nR1 = nRow1;
2179                 SCCOL nC2 = nC1 + nXw;
2180                 if (nC2 > nCol2)
2181                     nC2 = nCol2;
2182                 SCROW nR2 = nR1 + nYw;
2183                 if (nR2 > nRow2)
2184                     nR2 = nRow2;
2185 
2186                 do
2187                 {
2188                     // Pasting is done column-wise, when pasting to a filtered
2189                     // area this results in partitioning and we have to
2190                     // remember and reset the start row for each column until
2191                     // it can be advanced for the next chunk of unfiltered
2192                     // rows.
2193                     SCROW nSaveClipStartRow = nClipStartRow;
2194                     do
2195                     {
2196                         nClipStartRow = nSaveClipStartRow;
2197                         SCsCOL nDx = ((SCsCOL)nC1) - nClipStartCol;
2198                         SCsROW nDy = ((SCsROW)nR1) - nClipStartRow;
2199                         if ( bIncludeFiltered )
2200                         {
2201                             CopyBlockFromClip( nC1, nR1, nC2, nR2, rMark, nDx,
2202                                     nDy, &aCBFCP );
2203                             nClipStartRow += nR2 - nR1 + 1;
2204                         }
2205                         else
2206                         {
2207                             CopyNonFilteredFromClip( nC1, nR1, nC2, nR2, rMark,
2208                                     nDx, nDy, &aCBFCP, nClipStartRow );
2209                         }
2210                         // Not needed for columns, but if it was this would be how to.
2211                         //if (nClipStartCol > nClipEndCol)
2212                         //    nClipStartCol = pClipDoc->aClipRange.aStart.Col();
2213                         nC1 = nC2 + 1;
2214                         nC2 = Min((SCCOL)(nC1 + nXw), nCol2);
2215                     } while (nC1 <= nCol2);
2216                     if (nClipStartRow > nClipEndRow)
2217                         nClipStartRow = aClipRange.aStart.Row();
2218                     nC1 = nCol1;
2219                     nC2 = nC1 + nXw;
2220                     if (nC2 > nCol2)
2221                         nC2 = nCol2;
2222                     nR1 = nR2 + 1;
2223                     nR2 = Min((SCROW)(nR1 + nYw), nRow2);
2224                 } while (nR1 <= nRow2);
2225             }
2226 
2227 			ScColumn::bDoubleAlloc = bOldDouble;
2228 
2229 			for (SCTAB k = 0; k <= MAXTAB; k++)
2230 				if (pTab[k] && rMark.GetTableSelect(k))
2231 					pTab[k]->DecRecalcLevel();
2232 
2233 			bInsertingFromOtherDoc = sal_False;
2234 
2235             UpdateRangeNamesInFormulas(aClipRangeNames, *pDestRanges, rMark, nXw, nYw);
2236 
2237 			// Listener aufbauen nachdem alles inserted wurde
2238 			StartListeningFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
2239 			// nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
2240 			BroadcastFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
2241 			if (bResetCut)
2242                 pClipDoc->GetClipParam().mbCutMode = false;
2243 			SetAutoCalc( bOldAutoCalc );
2244 		}
2245 	}
2246 }
2247 
2248 static SCROW lcl_getLastNonFilteredRow(
2249     const ScBitMaskCompressedArray<SCROW, sal_uInt8>& rFlags, SCROW nBegRow, SCROW nEndRow,
2250     SCROW nRowCount)
2251 {
2252     SCROW nFilteredRow = rFlags.GetFirstForCondition(
2253         nBegRow, nEndRow, CR_FILTERED, CR_FILTERED);
2254 
2255     SCROW nRow = nFilteredRow - 1;
2256     if (nRow - nBegRow + 1 > nRowCount)
2257         // make sure the row range stays within the data size.
2258         nRow = nBegRow + nRowCount - 1;
2259 
2260     return nRow;
2261 }
2262 
2263 void ScDocument::CopyMultiRangeFromClip(
2264     const ScAddress& rDestPos, const ScMarkData& rMark, sal_uInt16 nInsFlag, ScDocument* pClipDoc,
2265     bool bResetCut, bool bAsLink, bool /*bIncludeFiltered*/, bool bSkipAttrForEmpty)
2266 {
2267     if (bIsClip)
2268         return;
2269 
2270     if (!pClipDoc->bIsClip || !pClipDoc->GetTableCount())
2271         // There is nothing in the clip doc to copy.
2272         return;
2273 
2274     sal_Bool bOldAutoCalc = GetAutoCalc();
2275     SetAutoCalc( sal_False );   // avoid multiple recalculations
2276 
2277     NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
2278 
2279     ScClipRangeNameData aClipRangeNames;
2280     CopyRangeNamesFromClip(pClipDoc, aClipRangeNames);
2281 
2282     SCCOL nCol1 = rDestPos.Col();
2283     SCROW nRow1 = rDestPos.Row();
2284     ScClipParam& rClipParam = pClipDoc->GetClipParam();
2285 
2286     ScCopyBlockFromClipParams aCBFCP;
2287     aCBFCP.pRefUndoDoc = NULL;
2288     aCBFCP.pClipDoc = pClipDoc;
2289     aCBFCP.nInsFlag = nInsFlag;
2290     aCBFCP.bAsLink  = bAsLink;
2291     aCBFCP.bSkipAttrForEmpty = bSkipAttrForEmpty;
2292     aCBFCP.nTabStart = MAXTAB;
2293     aCBFCP.nTabEnd = 0;
2294 
2295     for (SCTAB j = 0; j <= MAXTAB; ++j)
2296     {
2297         if (pTab[j] && rMark.GetTableSelect(j))
2298         {
2299             if ( j < aCBFCP.nTabStart )
2300                 aCBFCP.nTabStart = j;
2301             aCBFCP.nTabEnd = j;
2302             pTab[j]->IncRecalcLevel();
2303         }
2304     }
2305 
2306     ScRange aDestRange;
2307     rMark.GetMarkArea(aDestRange);
2308     SCROW nLastMarkedRow = aDestRange.aEnd.Row();
2309 
2310     bInsertingFromOtherDoc = sal_True;  // kein Broadcast/Listener aufbauen bei Insert
2311 
2312     SCROW nBegRow = nRow1;
2313     sal_uInt16 nDelFlag = IDF_CONTENTS;
2314     const ScBitMaskCompressedArray<SCROW, sal_uInt8>& rFlags = GetRowFlagsArray(aCBFCP.nTabStart);
2315 
2316     for (ScRange* p = rClipParam.maRanges.First(); p; p = rClipParam.maRanges.Next())
2317     {
2318         // The begin row must not be filtered.
2319 
2320         SCROW nRowCount = p->aEnd.Row() - p->aStart.Row() + 1;
2321 
2322         SCsCOL nDx = static_cast<SCsCOL>(nCol1 - p->aStart.Col());
2323         SCsROW nDy = static_cast<SCsROW>(nBegRow - p->aStart.Row());
2324         SCCOL nCol2 = nCol1 + p->aEnd.Col() - p->aStart.Col();
2325 
2326         SCROW nEndRow = lcl_getLastNonFilteredRow(rFlags, nBegRow, nLastMarkedRow, nRowCount);
2327 
2328         if (!bSkipAttrForEmpty)
2329             DeleteArea(nCol1, nBegRow, nCol2, nEndRow, rMark, nDelFlag);
2330 
2331         CopyBlockFromClip(nCol1, nBegRow, nCol2, nEndRow, rMark, nDx, nDy, &aCBFCP);
2332         nRowCount -= nEndRow - nBegRow + 1;
2333 
2334         while (nRowCount > 0)
2335         {
2336             // Get the first non-filtered row.
2337             SCROW nNonFilteredRow = rFlags.GetFirstForCondition(nEndRow+1, nLastMarkedRow, CR_FILTERED, 0);
2338             if (nNonFilteredRow > nLastMarkedRow)
2339                 return;
2340 
2341             SCROW nRowsSkipped = nNonFilteredRow - nEndRow - 1;
2342             nDy += nRowsSkipped;
2343 
2344             nBegRow = nNonFilteredRow;
2345             nEndRow = lcl_getLastNonFilteredRow(rFlags, nBegRow, nLastMarkedRow, nRowCount);
2346 
2347             if (!bSkipAttrForEmpty)
2348                 DeleteArea(nCol1, nBegRow, nCol2, nEndRow, rMark, nDelFlag);
2349 
2350             CopyBlockFromClip(nCol1, nBegRow, nCol2, nEndRow, rMark, nDx, nDy, &aCBFCP);
2351             nRowCount -= nEndRow - nBegRow + 1;
2352         }
2353 
2354         if (rClipParam.meDirection == ScClipParam::Row)
2355             // Begin row for the next range being pasted.
2356             nBegRow = rFlags.GetFirstForCondition(nEndRow+1, nLastMarkedRow, CR_FILTERED, 0);
2357         else
2358             nBegRow = nRow1;
2359 
2360         if (rClipParam.meDirection == ScClipParam::Column)
2361             nCol1 += p->aEnd.Col() - p->aStart.Col() + 1;
2362     }
2363 
2364     for (SCTAB i = 0; i <= MAXTAB; i++)
2365         if (pTab[i] && rMark.GetTableSelect(i))
2366             pTab[i]->DecRecalcLevel();
2367 
2368     bInsertingFromOtherDoc = sal_False;
2369 
2370     ScRangeList aRanges;
2371     aRanges.Append(aDestRange);
2372     SCCOL nCols = aDestRange.aEnd.Col() - aDestRange.aStart.Col() + 1;
2373     SCROW nRows = aDestRange.aEnd.Row() - aDestRange.aStart.Row() + 1;
2374     UpdateRangeNamesInFormulas(aClipRangeNames, aRanges, rMark, nCols-1, nRows-1);
2375 
2376     // Listener aufbauen nachdem alles inserted wurde
2377     StartListeningFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
2378                            aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
2379     // nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
2380     BroadcastFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
2381                       aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
2382 
2383     if (bResetCut)
2384         pClipDoc->GetClipParam().mbCutMode = false;
2385     SetAutoCalc( bOldAutoCalc );
2386 }
2387 
2388 void ScDocument::SetClipArea( const ScRange& rArea, sal_Bool bCut )
2389 {
2390 	if (bIsClip)
2391 	{
2392         ScClipParam& rClipParam = GetClipParam();
2393         rClipParam.maRanges.RemoveAll();
2394         rClipParam.maRanges.Append(rArea);
2395         rClipParam.mbCutMode = bCut;
2396 	}
2397 	else
2398 	{
2399 		DBG_ERROR("SetClipArea: kein Clip");
2400 	}
2401 }
2402 
2403 
2404 void ScDocument::GetClipArea(SCCOL& nClipX, SCROW& nClipY, sal_Bool bIncludeFiltered)
2405 {
2406     if (!bIsClip)
2407     {
2408         DBG_ERROR("GetClipArea: kein Clip");
2409         return;
2410     }
2411 
2412     ScRangeList& rClipRanges = GetClipParam().maRanges;
2413     if (!rClipRanges.Count())
2414         // No clip range.  Bail out.
2415         return;
2416 
2417     ScRangePtr p = rClipRanges.First();
2418     SCCOL nStartCol = p->aStart.Col();
2419     SCCOL nEndCol   = p->aEnd.Col();
2420     SCROW nStartRow = p->aStart.Row();
2421     SCROW nEndRow   = p->aEnd.Row();
2422     for (p = rClipRanges.Next(); p; p = rClipRanges.Next())
2423     {
2424         if (p->aStart.Col() < nStartCol)
2425             nStartCol = p->aStart.Col();
2426         if (p->aStart.Row() < nStartRow)
2427             nStartRow = p->aStart.Row();
2428         if (p->aEnd.Col() > nEndCol)
2429             nEndCol = p->aEnd.Col();
2430         if (p->aEnd.Row() < nEndRow)
2431             nEndRow = p->aEnd.Row();
2432 	}
2433 
2434     nClipX = nEndCol - nStartCol;
2435 
2436     if ( bIncludeFiltered )
2437         nClipY = nEndRow - nStartRow;
2438 	else
2439 	{
2440         //	count non-filtered rows
2441         //	count on first used table in clipboard
2442         SCTAB nCountTab = 0;
2443         while ( nCountTab < MAXTAB && !pTab[nCountTab] )
2444             ++nCountTab;
2445 
2446         SCROW nResult = CountNonFilteredRows(nStartRow, nEndRow, nCountTab);
2447 
2448         if ( nResult > 0 )
2449             nClipY = nResult - 1;
2450         else
2451             nClipY = 0;					// always return at least 1 row
2452 	}
2453 }
2454 
2455 
2456 void ScDocument::GetClipStart(SCCOL& nClipX, SCROW& nClipY)
2457 {
2458 	if (bIsClip)
2459 	{
2460         ScRangeList& rClipRanges = GetClipParam().maRanges;
2461         if (rClipRanges.Count())
2462         {
2463             nClipX = rClipRanges.First()->aStart.Col();
2464             nClipY = rClipRanges.First()->aStart.Row();
2465         }
2466 	}
2467 	else
2468 	{
2469 		DBG_ERROR("GetClipStart: kein Clip");
2470 	}
2471 }
2472 
2473 
2474 sal_Bool ScDocument::HasClipFilteredRows()
2475 {
2476 	//	count on first used table in clipboard
2477 	SCTAB nCountTab = 0;
2478 	while ( nCountTab < MAXTAB && !pTab[nCountTab] )
2479 		++nCountTab;
2480 
2481     ScRangeList& rClipRanges = GetClipParam().maRanges;
2482     if (!rClipRanges.Count())
2483         return false;
2484 
2485     for (ScRange* p = rClipRanges.First(); p; p = rClipRanges.Next())
2486     {
2487         bool bAnswer = pTab[nCountTab]->HasFilteredRows(p->aStart.Row(), p->aEnd.Row());
2488         if (bAnswer)
2489             return true;
2490     }
2491     return false;
2492 }
2493 
2494 
2495 void ScDocument::MixDocument( const ScRange& rRange, sal_uInt16 nFunction, sal_Bool bSkipEmpty,
2496 									ScDocument* pSrcDoc )
2497 {
2498 	SCTAB nTab1 = rRange.aStart.Tab();
2499 	SCTAB nTab2 = rRange.aEnd.Tab();
2500 	for (SCTAB i = nTab1; i <= nTab2; i++)
2501 		if (pTab[i] && pSrcDoc->pTab[i])
2502 			pTab[i]->MixData( rRange.aStart.Col(), rRange.aStart.Row(),
2503 								rRange.aEnd.Col(), rRange.aEnd.Row(),
2504 								nFunction, bSkipEmpty, pSrcDoc->pTab[i] );
2505 }
2506 
2507 
2508 void ScDocument::FillTab( const ScRange& rSrcArea, const ScMarkData& rMark,
2509 								sal_uInt16 nFlags, sal_uInt16 nFunction,
2510 								sal_Bool bSkipEmpty, sal_Bool bAsLink )
2511 {
2512 	sal_uInt16 nDelFlags = nFlags;
2513 	if (nDelFlags & IDF_CONTENTS)
2514 		nDelFlags |= IDF_CONTENTS;			// immer alle Inhalte oder keine loeschen!
2515 
2516 	SCTAB nSrcTab = rSrcArea.aStart.Tab();
2517 
2518 	if (ValidTab(nSrcTab)  && pTab[nSrcTab])
2519 	{
2520 		SCCOL nStartCol = rSrcArea.aStart.Col();
2521 		SCROW nStartRow = rSrcArea.aStart.Row();
2522 		SCCOL nEndCol = rSrcArea.aEnd.Col();
2523 		SCROW nEndRow = rSrcArea.aEnd.Row();
2524 		ScDocument* pMixDoc = NULL;
2525 		sal_Bool bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
2526 
2527 		sal_Bool bOldAutoCalc = GetAutoCalc();
2528 		SetAutoCalc( sal_False );					// Mehrfachberechnungen vermeiden
2529 
2530 		SCTAB nCount = GetTableCount();
2531 		for (SCTAB i=0; i<nCount; i++)
2532 			if ( i!=nSrcTab && pTab[i] && rMark.GetTableSelect(i) )
2533 			{
2534 				if (bDoMix)
2535 				{
2536 					if (!pMixDoc)
2537 					{
2538 						pMixDoc = new ScDocument( SCDOCMODE_UNDO );
2539 						pMixDoc->InitUndo( this, i, i );
2540 					}
2541 					else
2542 						pMixDoc->AddUndoTab( i, i );
2543 					pTab[i]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2544 											IDF_CONTENTS, sal_False, pMixDoc->pTab[i] );
2545 				}
2546 				pTab[i]->DeleteArea( nStartCol,nStartRow, nEndCol,nEndRow, nDelFlags);
2547 				pTab[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2548 												 nFlags, sal_False, pTab[i], NULL, bAsLink );
2549 
2550 				if (bDoMix)
2551 					pTab[i]->MixData( nStartCol,nStartRow, nEndCol,nEndRow,
2552 										nFunction, bSkipEmpty, pMixDoc->pTab[i] );
2553 			}
2554 
2555 		delete pMixDoc;
2556 
2557 		SetAutoCalc( bOldAutoCalc );
2558 	}
2559 	else
2560 	{
2561 		DBG_ERROR("falsche Tabelle");
2562 	}
2563 }
2564 
2565 
2566 void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
2567 								sal_uInt16 nFlags, sal_uInt16 nFunction,
2568 								sal_Bool bSkipEmpty, sal_Bool bAsLink )
2569 {
2570 	sal_uInt16 nDelFlags = nFlags;
2571 	if (nDelFlags & IDF_CONTENTS)
2572 		nDelFlags |= IDF_CONTENTS;			// immer alle Inhalte oder keine loeschen!
2573 
2574 	if (ValidTab(nSrcTab)  && pTab[nSrcTab])
2575 	{
2576 		ScDocument* pMixDoc = NULL;
2577 		sal_Bool bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
2578 
2579 		sal_Bool bOldAutoCalc = GetAutoCalc();
2580 		SetAutoCalc( sal_False );					// Mehrfachberechnungen vermeiden
2581 
2582 		ScRange aArea;
2583 		rMark.GetMultiMarkArea( aArea );
2584 		SCCOL nStartCol = aArea.aStart.Col();
2585 		SCROW nStartRow = aArea.aStart.Row();
2586 		SCCOL nEndCol = aArea.aEnd.Col();
2587 		SCROW nEndRow = aArea.aEnd.Row();
2588 
2589 		SCTAB nCount = GetTableCount();
2590 		for (SCTAB i=0; i<nCount; i++)
2591 			if ( i!=nSrcTab && pTab[i] && rMark.GetTableSelect(i) )
2592 			{
2593 				if (bDoMix)
2594 				{
2595 					if (!pMixDoc)
2596 					{
2597 						pMixDoc = new ScDocument( SCDOCMODE_UNDO );
2598 						pMixDoc->InitUndo( this, i, i );
2599 					}
2600 					else
2601 						pMixDoc->AddUndoTab( i, i );
2602 					pTab[i]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2603 											IDF_CONTENTS, sal_True, pMixDoc->pTab[i], &rMark );
2604 				}
2605 
2606 				pTab[i]->DeleteSelection( nDelFlags, rMark );
2607 				pTab[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2608 											 nFlags, sal_True, pTab[i], &rMark, bAsLink );
2609 
2610 				if (bDoMix)
2611 					pTab[i]->MixMarked( rMark, nFunction, bSkipEmpty, pMixDoc->pTab[i] );
2612 			}
2613 
2614 		delete pMixDoc;
2615 
2616 		SetAutoCalc( bOldAutoCalc );
2617 	}
2618 	else
2619 	{
2620 		DBG_ERROR("falsche Tabelle");
2621 	}
2622 }
2623 
2624 
2625 void ScDocument::PutCell( SCCOL nCol, SCROW nRow, SCTAB nTab, ScBaseCell* pCell, sal_Bool bForceTab )
2626 {
2627 	if (VALIDTAB(nTab))
2628 	{
2629 		if ( bForceTab && !pTab[nTab] )
2630 		{
2631 			sal_Bool bExtras = !bIsUndo;		// Spaltenbreiten, Zeilenhoehen, Flags
2632 
2633 			pTab[nTab] = new ScTable(this, nTab,
2634 							String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("temp")),
2635 							bExtras, bExtras);
2636 			++nMaxTableNumber;
2637 		}
2638 
2639 		if (pTab[nTab])
2640 			pTab[nTab]->PutCell( nCol, nRow, pCell );
2641 	}
2642 }
2643 
2644 
2645 void ScDocument::PutCell( const ScAddress& rPos, ScBaseCell* pCell, sal_Bool bForceTab )
2646 {
2647 	SCTAB nTab = rPos.Tab();
2648 	if ( bForceTab && !pTab[nTab] )
2649 	{
2650 		sal_Bool bExtras = !bIsUndo;		// Spaltenbreiten, Zeilenhoehen, Flags
2651 
2652 		pTab[nTab] = new ScTable(this, nTab,
2653 						String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("temp")),
2654 						bExtras, bExtras);
2655 		++nMaxTableNumber;
2656 	}
2657 
2658 	if (pTab[nTab])
2659 		pTab[nTab]->PutCell( rPos, pCell );
2660 }
2661 
2662 
2663 sal_Bool ScDocument::SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rString,
2664                             SvNumberFormatter* pFormatter, bool bDetectNumberFormat )
2665 {
2666 	if ( ValidTab(nTab) && pTab[nTab] )
2667 		return pTab[nTab]->SetString( nCol, nRow, nTab, rString, pFormatter, bDetectNumberFormat );
2668 	else
2669 		return sal_False;
2670 }
2671 
2672 
2673 void ScDocument::SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal )
2674 {
2675 	if (VALIDTAB(nTab))
2676 		if (pTab[nTab])
2677 			pTab[nTab]->SetValue( nCol, nRow, rVal );
2678 }
2679 
2680 
2681 void ScDocument::GetString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString )
2682 {
2683 	if ( VALIDTAB(nTab) && pTab[nTab] )
2684 		pTab[nTab]->GetString( nCol, nRow, rString );
2685 	else
2686 		rString.Erase();
2687 }
2688 
2689 
2690 void ScDocument::GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString )
2691 {
2692 	if ( VALIDTAB(nTab) && pTab[nTab] )
2693 		pTab[nTab]->GetInputString( nCol, nRow, rString );
2694 	else
2695 		rString.Erase();
2696 }
2697 
2698 
2699 sal_uInt16 ScDocument::GetStringForFormula( const ScAddress& rPos, rtl::OUString& rString )
2700 {
2701     // Used in formulas (add-in parameters etc), so it must use the same semantics as
2702     // ScInterpreter::GetCellString: always format values as numbers.
2703     // The return value is the error code.
2704 
2705     sal_uInt16 nErr = 0;
2706     String aStr;
2707     ScBaseCell* pCell = GetCell( rPos );
2708     if (pCell)
2709     {
2710         SvNumberFormatter* pFormatter = GetFormatTable();
2711         switch (pCell->GetCellType())
2712         {
2713             case CELLTYPE_STRING:
2714                 static_cast<ScStringCell*>(pCell)->GetString(aStr);
2715             break;
2716             case CELLTYPE_EDIT:
2717                 static_cast<ScEditCell*>(pCell)->GetString(aStr);
2718             break;
2719             case CELLTYPE_FORMULA:
2720             {
2721                 ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
2722                 nErr = pFCell->GetErrCode();
2723                 if (pFCell->IsValue())
2724                 {
2725                     double fVal = pFCell->GetValue();
2726                     sal_uInt32 nIndex = pFormatter->GetStandardFormat(
2727                                         NUMBERFORMAT_NUMBER,
2728                                         ScGlobal::eLnge);
2729                     pFormatter->GetInputLineString(fVal, nIndex, aStr);
2730                 }
2731                 else
2732                     pFCell->GetString(aStr);
2733             }
2734             break;
2735             case CELLTYPE_VALUE:
2736             {
2737                 double fVal = static_cast<ScValueCell*>(pCell)->GetValue();
2738                 sal_uInt32 nIndex = pFormatter->GetStandardFormat(
2739                                         NUMBERFORMAT_NUMBER,
2740                                         ScGlobal::eLnge);
2741                 pFormatter->GetInputLineString(fVal, nIndex, aStr);
2742             }
2743             break;
2744             default:
2745                 ;
2746         }
2747     }
2748     rString = aStr;
2749     return nErr;
2750 }
2751 
2752 
2753 void ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, double& rValue )
2754 {
2755 	if ( VALIDTAB(nTab) && pTab[nTab] )
2756 		rValue = pTab[nTab]->GetValue( nCol, nRow );
2757 	else
2758 		rValue = 0.0;
2759 }
2760 
2761 
2762 double ScDocument::GetValue( const ScAddress& rPos )
2763 {
2764 	SCTAB nTab = rPos.Tab();
2765 	if ( pTab[nTab] )
2766 		return pTab[nTab]->GetValue( rPos );
2767 	return 0.0;
2768 }
2769 
2770 
2771 void ScDocument::GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab,
2772 								  sal_uInt32& rFormat )
2773 {
2774 	if (VALIDTAB(nTab))
2775 		if (pTab[nTab])
2776 		{
2777 			rFormat = pTab[nTab]->GetNumberFormat( nCol, nRow );
2778 			return ;
2779 		}
2780 	rFormat = 0;
2781 }
2782 
2783 
2784 sal_uInt32 ScDocument::GetNumberFormat( const ScAddress& rPos ) const
2785 {
2786 	SCTAB nTab = rPos.Tab();
2787 	if ( pTab[nTab] )
2788 		return pTab[nTab]->GetNumberFormat( rPos );
2789 	return 0;
2790 }
2791 
2792 
2793 void ScDocument::GetNumberFormatInfo( short& nType, sal_uLong& nIndex,
2794 			const ScAddress& rPos, const ScBaseCell* pCell ) const
2795 {
2796 	SCTAB nTab = rPos.Tab();
2797 	if ( pTab[nTab] )
2798 	{
2799 		nIndex = pTab[nTab]->GetNumberFormat( rPos );
2800         if ( (nIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && pCell &&
2801                 pCell->GetCellType() == CELLTYPE_FORMULA )
2802 			static_cast<const ScFormulaCell*>(pCell)->GetFormatInfo( nType, nIndex );
2803 		else
2804 			nType = GetFormatTable()->GetType( nIndex );
2805 	}
2806 	else
2807 	{
2808 		nType = NUMBERFORMAT_UNDEFINED;
2809 		nIndex = 0;
2810 	}
2811 }
2812 
2813 
2814 void ScDocument::GetFormula( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rFormula,
2815 							 sal_Bool bAsciiExport ) const
2816 {
2817 	if ( VALIDTAB(nTab) && pTab[nTab] )
2818 			pTab[nTab]->GetFormula( nCol, nRow, rFormula, bAsciiExport );
2819 	else
2820 		rFormula.Erase();
2821 }
2822 
2823 
2824 CellType ScDocument::GetCellType( const ScAddress& rPos ) const
2825 {
2826 	SCTAB nTab = rPos.Tab();
2827 	if ( pTab[nTab] )
2828 		return pTab[nTab]->GetCellType( rPos );
2829 	return CELLTYPE_NONE;
2830 }
2831 
2832 
2833 void ScDocument::GetCellType( SCCOL nCol, SCROW nRow, SCTAB nTab,
2834 		CellType& rCellType ) const
2835 {
2836 	if (ValidTab(nTab) && pTab[nTab])
2837 		rCellType = pTab[nTab]->GetCellType( nCol, nRow );
2838 	else
2839 		rCellType = CELLTYPE_NONE;
2840 }
2841 
2842 
2843 void ScDocument::GetCell( SCCOL nCol, SCROW nRow, SCTAB nTab,
2844 		ScBaseCell*& rpCell ) const
2845 {
2846 	if (ValidTab(nTab) && pTab[nTab])
2847 		rpCell = pTab[nTab]->GetCell( nCol, nRow );
2848 	else
2849 	{
2850 		DBG_ERROR("GetCell ohne Tabelle");
2851 		rpCell = NULL;
2852 	}
2853 }
2854 
2855 
2856 ScBaseCell* ScDocument::GetCell( const ScAddress& rPos ) const
2857 {
2858 	SCTAB nTab = rPos.Tab();
2859 	if (ValidTab(nTab) && pTab[nTab])
2860 		return pTab[nTab]->GetCell( rPos );
2861 
2862 	DBG_ERROR("GetCell ohne Tabelle");
2863 	return NULL;
2864 }
2865 
2866 
2867 sal_Bool ScDocument::HasStringData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
2868 {
2869 	if ( VALIDTAB(nTab) && pTab[nTab] )
2870 			return pTab[nTab]->HasStringData( nCol, nRow );
2871 	else
2872 		return sal_False;
2873 }
2874 
2875 
2876 sal_Bool ScDocument::HasValueData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
2877 {
2878 	if ( VALIDTAB(nTab) && pTab[nTab] )
2879 			return pTab[nTab]->HasValueData( nCol, nRow );
2880 	else
2881 		return sal_False;
2882 }
2883 
2884 
2885 sal_Bool ScDocument::HasStringCells( const ScRange& rRange ) const
2886 {
2887 	//	sal_True, wenn String- oder Editzellen im Bereich
2888 
2889 	SCCOL nStartCol = rRange.aStart.Col();
2890 	SCROW nStartRow = rRange.aStart.Row();
2891 	SCTAB nStartTab = rRange.aStart.Tab();
2892 	SCCOL nEndCol = rRange.aEnd.Col();
2893 	SCROW nEndRow = rRange.aEnd.Row();
2894 	SCTAB nEndTab = rRange.aEnd.Tab();
2895 
2896 	for ( SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++ )
2897 		if ( pTab[nTab] && pTab[nTab]->HasStringCells( nStartCol, nStartRow, nEndCol, nEndRow ) )
2898 			return sal_True;
2899 
2900 	return sal_False;
2901 }
2902 
2903 
2904 sal_Bool ScDocument::HasSelectionData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
2905 {
2906     sal_uInt32 nValidation = static_cast< const SfxUInt32Item* >( GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA ) )->GetValue();
2907     if( nValidation )
2908     {
2909         const ScValidationData* pData = GetValidationEntry( nValidation );
2910         if( pData && pData->HasSelectionList() )
2911             return sal_True;
2912     }
2913     return HasStringCells( ScRange( nCol, 0, nTab, nCol, MAXROW, nTab ) );
2914 }
2915 
2916 
2917 ScPostIt* ScDocument::GetNote( const ScAddress& rPos )
2918 {
2919     ScTable* pTable = ValidTab( rPos.Tab() ) ? pTab[ rPos.Tab() ] : 0;
2920 	return pTable ? pTable->GetNote( rPos.Col(), rPos.Row() ) : 0;
2921 }
2922 
2923 
2924 void ScDocument::TakeNote( const ScAddress& rPos, ScPostIt*& rpNote )
2925 {
2926     if( ValidTab( rPos.Tab() ) && pTab[ rPos.Tab() ] )
2927         pTab[ rPos.Tab() ]->TakeNote( rPos.Col(), rPos.Row(), rpNote );
2928     else
2929         DELETEZ( rpNote );
2930 }
2931 
2932 
2933 ScPostIt* ScDocument::ReleaseNote( const ScAddress& rPos )
2934 {
2935     ScTable* pTable = ValidTab( rPos.Tab() ) ? pTab[ rPos.Tab() ] : 0;
2936     return pTable ? pTable->ReleaseNote( rPos.Col(), rPos.Row() ) : 0;
2937 }
2938 
2939 
2940 ScPostIt* ScDocument::GetOrCreateNote( const ScAddress& rPos )
2941 {
2942     ScPostIt* pNote = GetNote( rPos );
2943     if( !pNote )
2944     {
2945         pNote = new ScPostIt( *this, rPos, false );
2946         TakeNote( rPos, pNote );
2947     }
2948     return pNote;
2949 }
2950 
2951 
2952 void ScDocument::DeleteNote( const ScAddress& rPos )
2953 {
2954     if( ValidTab( rPos.Tab() ) && pTab[ rPos.Tab() ] )
2955         pTab[ rPos.Tab() ]->DeleteNote( rPos.Col(), rPos.Row() );
2956 }
2957 
2958 
2959 void ScDocument::InitializeNoteCaptions( SCTAB nTab, bool bForced )
2960 {
2961     if( ValidTab( nTab ) && pTab[ nTab ] )
2962         pTab[ nTab ]->InitializeNoteCaptions( bForced );
2963 }
2964 
2965 void ScDocument::InitializeAllNoteCaptions( bool bForced )
2966 {
2967     for( SCTAB nTab = 0; nTab < GetTableCount(); ++nTab )
2968         InitializeNoteCaptions( nTab, bForced );
2969 }
2970 
2971 void ScDocument::SetDirty()
2972 {
2973 	sal_Bool bOldAutoCalc = GetAutoCalc();
2974 	bAutoCalc = sal_False;		// keine Mehrfachberechnung
2975     {   // scope for bulk broadcast
2976         ScBulkBroadcast aBulkBroadcast( GetBASM());
2977         for (SCTAB i=0; i<=MAXTAB; i++)
2978             if (pTab[i]) pTab[i]->SetDirty();
2979     }
2980 
2981 	//	Charts werden zwar auch ohne AutoCalc im Tracking auf Dirty gesetzt,
2982 	//	wenn alle Formeln dirty sind, werden die Charts aber nicht mehr erwischt
2983 	//	(#45205#) - darum alle Charts nochmal explizit
2984 	if (pChartListenerCollection)
2985 		pChartListenerCollection->SetDirty();
2986 
2987 	SetAutoCalc( bOldAutoCalc );
2988 }
2989 
2990 
2991 void ScDocument::SetDirty( const ScRange& rRange )
2992 {
2993 	sal_Bool bOldAutoCalc = GetAutoCalc();
2994 	bAutoCalc = sal_False;		// keine Mehrfachberechnung
2995     {   // scope for bulk broadcast
2996         ScBulkBroadcast aBulkBroadcast( GetBASM());
2997         SCTAB nTab2 = rRange.aEnd.Tab();
2998         for (SCTAB i=rRange.aStart.Tab(); i<=nTab2; i++)
2999             if (pTab[i]) pTab[i]->SetDirty( rRange );
3000     }
3001 	SetAutoCalc( bOldAutoCalc );
3002 }
3003 
3004 
3005 void ScDocument::SetTableOpDirty( const ScRange& rRange )
3006 {
3007 	sal_Bool bOldAutoCalc = GetAutoCalc();
3008 	bAutoCalc = sal_False;		// no multiple recalculation
3009 	SCTAB nTab2 = rRange.aEnd.Tab();
3010 	for (SCTAB i=rRange.aStart.Tab(); i<=nTab2; i++)
3011 		if (pTab[i]) pTab[i]->SetTableOpDirty( rRange );
3012 	SetAutoCalc( bOldAutoCalc );
3013 }
3014 
3015 
3016 void ScDocument::InterpretDirtyCells( const ScRangeList& rRanges )
3017 {
3018     sal_uLong nRangeCount = rRanges.Count();
3019     for (sal_uLong nPos=0; nPos<nRangeCount; nPos++)
3020     {
3021         ScCellIterator aIter( this, *rRanges.GetObject(nPos) );
3022         ScBaseCell* pCell = aIter.GetFirst();
3023         while (pCell)
3024         {
3025             if (pCell->GetCellType() == CELLTYPE_FORMULA)
3026             {
3027                 if ( static_cast<ScFormulaCell*>(pCell)->GetDirty() && GetAutoCalc() )
3028                     static_cast<ScFormulaCell*>(pCell)->Interpret();
3029             }
3030             pCell = aIter.GetNext();
3031         }
3032     }
3033 }
3034 
3035 
3036 void ScDocument::AddTableOpFormulaCell( ScFormulaCell* pCell )
3037 {
3038     ScInterpreterTableOpParams* p = aTableOpList.Last();
3039     if ( p && p->bCollectNotifications )
3040     {
3041         if ( p->bRefresh )
3042         {   // refresh pointers only
3043             p->aNotifiedFormulaCells.push_back( pCell );
3044         }
3045         else
3046         {   // init both, address and pointer
3047             p->aNotifiedFormulaCells.push_back( pCell );
3048             p->aNotifiedFormulaPos.push_back( pCell->aPos );
3049         }
3050     }
3051 }
3052 
3053 
3054 void ScDocument::CalcAll()
3055 {
3056     ClearLookupCaches();    // Ensure we don't deliver zombie data.
3057 	sal_Bool bOldAutoCalc = GetAutoCalc();
3058 	SetAutoCalc( sal_True );
3059 	SCTAB i;
3060 	for (i=0; i<=MAXTAB; i++)
3061 		if (pTab[i]) pTab[i]->SetDirtyVar();
3062 	for (i=0; i<=MAXTAB; i++)
3063 		if (pTab[i]) pTab[i]->CalcAll();
3064 	ClearFormulaTree();
3065 	SetAutoCalc( bOldAutoCalc );
3066 }
3067 
3068 
3069 void ScDocument::CompileAll()
3070 {
3071 	if ( pCondFormList )
3072 		pCondFormList->CompileAll();
3073 
3074 	for (SCTAB i=0; i<=MAXTAB; i++)
3075 		if (pTab[i]) pTab[i]->CompileAll();
3076 	SetDirty();
3077 }
3078 
3079 
3080 void ScDocument::CompileXML()
3081 {
3082 	sal_Bool bOldAutoCalc = GetAutoCalc();
3083 	SetAutoCalc( sal_False );
3084     ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(
3085                 STR_PROGRESS_CALCULATING ), GetXMLImportedFormulaCount() );
3086 
3087     // #b6355215# set AutoNameCache to speed up automatic name lookup
3088     DBG_ASSERT( !pAutoNameCache, "AutoNameCache already set" );
3089     pAutoNameCache = new ScAutoNameCache( this );
3090 
3091 	for (SCTAB i=0; i<=MAXTAB; i++)
3092 		if (pTab[i]) pTab[i]->CompileXML( aProgress );
3093 
3094     DELETEZ( pAutoNameCache );  // valid only during CompileXML, where cell contents don't change
3095 
3096 	if ( pCondFormList )
3097 		pCondFormList->CompileXML();
3098 	if ( pValidationList )
3099 		pValidationList->CompileXML();
3100 
3101 	SetDirty();
3102 	SetAutoCalc( bOldAutoCalc );
3103 }
3104 
3105 
3106 void ScDocument::CalcAfterLoad()
3107 {
3108 	SCTAB i;
3109 
3110 	if (bIsClip)	// Excel-Dateien werden aus dem Clipboard in ein Clip-Doc geladen
3111 		return;		// dann wird erst beim Einfuegen in das richtige Doc berechnet
3112 
3113 	bCalcingAfterLoad = sal_True;
3114 	for ( i = 0; i <= MAXTAB; i++)
3115 		if (pTab[i]) pTab[i]->CalcAfterLoad();
3116 	for (i=0; i<=MAXTAB; i++)
3117 		if (pTab[i]) pTab[i]->SetDirtyAfterLoad();
3118 	bCalcingAfterLoad = sal_False;
3119 
3120 	SetDetectiveDirty(sal_False);	// noch keine wirklichen Aenderungen
3121 
3122     // #i112436# If formula cells are already dirty, they don't broadcast further changes.
3123     // So the source ranges of charts must be interpreted even if they are not visible,
3124     // similar to ScMyShapeResizer::CreateChartListener for loading own files (i104899).
3125     if (pChartListenerCollection)
3126     {
3127         sal_uInt16 nChartCount = pChartListenerCollection->GetCount();
3128         for ( sal_uInt16 nIndex = 0; nIndex < nChartCount; nIndex++ )
3129         {
3130             ScChartListener* pChartListener = static_cast<ScChartListener*>(pChartListenerCollection->At(nIndex));
3131             InterpretDirtyCells(*pChartListener->GetRangeList());
3132         }
3133     }
3134 }
3135 
3136 
3137 sal_uInt16 ScDocument::GetErrCode( const ScAddress& rPos ) const
3138 {
3139 	SCTAB nTab = rPos.Tab();
3140 	if ( pTab[nTab] )
3141 		return pTab[nTab]->GetErrCode( rPos );
3142 	return 0;
3143 }
3144 
3145 
3146 void ScDocument::ResetChanged( const ScRange& rRange )
3147 {
3148 	SCTAB nStartTab = rRange.aStart.Tab();
3149 	SCTAB nEndTab = rRange.aEnd.Tab();
3150 	for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
3151 		if (pTab[nTab])
3152 			pTab[nTab]->ResetChanged( rRange );
3153 }
3154 
3155 //
3156 //	Spaltenbreiten / Zeilenhoehen	--------------------------------------
3157 //
3158 
3159 
3160 void ScDocument::SetColWidth( SCCOL nCol, SCTAB nTab, sal_uInt16 nNewWidth )
3161 {
3162 	if ( ValidTab(nTab) && pTab[nTab] )
3163 		pTab[nTab]->SetColWidth( nCol, nNewWidth );
3164 }
3165 
3166 
3167 void ScDocument::SetRowHeight( SCROW nRow, SCTAB nTab, sal_uInt16 nNewHeight )
3168 {
3169 	if ( ValidTab(nTab) && pTab[nTab] )
3170 		pTab[nTab]->SetRowHeight( nRow, nNewHeight );
3171 }
3172 
3173 
3174 void ScDocument::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
3175 {
3176 	if ( ValidTab(nTab) && pTab[nTab] )
3177 		pTab[nTab]->SetRowHeightRange
3178 			( nStartRow, nEndRow, nNewHeight, 1.0, 1.0 );
3179 }
3180 
3181 void ScDocument::SetRowHeightOnly( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
3182 {
3183     if ( ValidTab(nTab) && pTab[nTab] )
3184         pTab[nTab]->SetRowHeightOnly( nStartRow, nEndRow, nNewHeight );
3185 }
3186 
3187 void ScDocument::SetManualHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_Bool bManual )
3188 {
3189 	if ( ValidTab(nTab) && pTab[nTab] )
3190 		pTab[nTab]->SetManualHeight( nStartRow, nEndRow, bManual );
3191 }
3192 
3193 
3194 sal_uInt16 ScDocument::GetColWidth( SCCOL nCol, SCTAB nTab ) const
3195 {
3196 	if ( ValidTab(nTab) && pTab[nTab] )
3197 		return pTab[nTab]->GetColWidth( nCol );
3198 	DBG_ERROR("Falsche Tabellennummer");
3199 	return 0;
3200 }
3201 
3202 
3203 sal_uInt16 ScDocument::GetOriginalWidth( SCCOL nCol, SCTAB nTab ) const
3204 {
3205 	if ( ValidTab(nTab) && pTab[nTab] )
3206 		return pTab[nTab]->GetOriginalWidth( nCol );
3207 	DBG_ERROR("Falsche Tabellennummer");
3208 	return 0;
3209 }
3210 
3211 
3212 sal_uInt16 ScDocument::GetCommonWidth( SCCOL nEndCol, SCTAB nTab ) const
3213 {
3214 	if ( ValidTab(nTab) && pTab[nTab] )
3215 		return pTab[nTab]->GetCommonWidth( nEndCol );
3216 	DBG_ERROR("Wrong table number");
3217 	return 0;
3218 }
3219 
3220 
3221 sal_uInt16 ScDocument::GetOriginalHeight( SCROW nRow, SCTAB nTab ) const
3222 {
3223 	if ( ValidTab(nTab) && pTab[nTab] )
3224 		return pTab[nTab]->GetOriginalHeight( nRow );
3225 	DBG_ERROR("Wrong table number");
3226 	return 0;
3227 }
3228 
3229 
3230 sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, bool bHiddenAsZero ) const
3231 {
3232 	if ( ValidTab(nTab) && pTab[nTab] )
3233         return pTab[nTab]->GetRowHeight( nRow, NULL, NULL, bHiddenAsZero );
3234 	DBG_ERROR("Wrong sheet number");
3235 	return 0;
3236 }
3237 
3238 
3239 sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, SCROW* pStartRow, SCROW* pEndRow, bool bHiddenAsZero ) const
3240 {
3241 	if ( ValidTab(nTab) && pTab[nTab] )
3242         return pTab[nTab]->GetRowHeight( nRow, pStartRow, pEndRow, bHiddenAsZero );
3243 	DBG_ERROR("Wrong sheet number");
3244 	return 0;
3245 }
3246 
3247 
3248 sal_uLong ScDocument::GetRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
3249 {
3250     if (nStartRow == nEndRow)
3251         return GetRowHeight( nStartRow, nTab);  // faster for a single row
3252 
3253     // check bounds because this method replaces former for(i=start;i<=end;++i) loops
3254     if (nStartRow > nEndRow)
3255         return 0;
3256 
3257 	if ( ValidTab(nTab) && pTab[nTab] )
3258         return pTab[nTab]->GetRowHeight( nStartRow, nEndRow);
3259 
3260     DBG_ERROR("wrong sheet number");
3261     return 0;
3262 }
3263 
3264 SCROW ScDocument::GetRowForHeight( SCTAB nTab, sal_uLong nHeight ) const
3265 {
3266     return pTab[nTab]->GetRowForHeight(nHeight);
3267 }
3268 
3269 sal_uLong ScDocument::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow,
3270         SCTAB nTab, double fScale ) const
3271 {
3272     // faster for a single row
3273     if (nStartRow == nEndRow)
3274         return (sal_uLong) (GetRowHeight( nStartRow, nTab) * fScale);
3275 
3276     // check bounds because this method replaces former for(i=start;i<=end;++i) loops
3277     if (nStartRow > nEndRow)
3278         return 0;
3279 
3280 	if ( ValidTab(nTab) && pTab[nTab] )
3281         return pTab[nTab]->GetScaledRowHeight( nStartRow, nEndRow, fScale);
3282 
3283     DBG_ERROR("wrong sheet number");
3284     return 0;
3285 }
3286 
3287 SCROW ScDocument::GetHiddenRowCount( SCROW nRow, SCTAB nTab ) const
3288 {
3289 	if ( ValidTab(nTab) && pTab[nTab] )
3290 		return pTab[nTab]->GetHiddenRowCount( nRow );
3291 	DBG_ERROR("Falsche Tabellennummer");
3292 	return 0;
3293 }
3294 
3295 
3296 sal_uLong ScDocument::GetColOffset( SCCOL nCol, SCTAB nTab ) const
3297 {
3298 	if ( ValidTab(nTab) && pTab[nTab] )
3299 		return pTab[nTab]->GetColOffset( nCol );
3300 	DBG_ERROR("Falsche Tabellennummer");
3301 	return 0;
3302 }
3303 
3304 
3305 sal_uLong ScDocument::GetRowOffset( SCROW nRow, SCTAB nTab ) const
3306 {
3307 	if ( ValidTab(nTab) && pTab[nTab] )
3308 		return pTab[nTab]->GetRowOffset( nRow );
3309 	DBG_ERROR("Falsche Tabellennummer");
3310 	return 0;
3311 }
3312 
3313 
3314 sal_uInt16 ScDocument::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, OutputDevice* pDev,
3315 										double nPPTX, double nPPTY,
3316 										const Fraction& rZoomX, const Fraction& rZoomY,
3317 										sal_Bool bFormula, const ScMarkData* pMarkData,
3318 										sal_Bool bSimpleTextImport )
3319 {
3320 	if ( ValidTab(nTab) && pTab[nTab] )
3321 		return pTab[nTab]->GetOptimalColWidth( nCol, pDev, nPPTX, nPPTY,
3322 			rZoomX, rZoomY, bFormula, pMarkData, bSimpleTextImport );
3323 	DBG_ERROR("Falsche Tabellennummer");
3324 	return 0;
3325 }
3326 
3327 
3328 long ScDocument::GetNeededSize( SCCOL nCol, SCROW nRow, SCTAB nTab,
3329 									OutputDevice* pDev,
3330 									double nPPTX, double nPPTY,
3331 									const Fraction& rZoomX, const Fraction& rZoomY,
3332 									sal_Bool bWidth, sal_Bool bTotalSize )
3333 {
3334 	if ( ValidTab(nTab) && pTab[nTab] )
3335 		return pTab[nTab]->GetNeededSize
3336 				( nCol, nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, bTotalSize );
3337 	DBG_ERROR("Falsche Tabellennummer");
3338 	return 0;
3339 }
3340 
3341 
3342 sal_Bool ScDocument::SetOptimalHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nExtra,
3343 									OutputDevice* pDev,
3344 									double nPPTX, double nPPTY,
3345 									const Fraction& rZoomX, const Fraction& rZoomY,
3346 									sal_Bool bShrink )
3347 {
3348 //!	MarkToMulti();
3349 	if ( ValidTab(nTab) && pTab[nTab] )
3350 		return pTab[nTab]->SetOptimalHeight( nStartRow, nEndRow, nExtra,
3351 												pDev, nPPTX, nPPTY, rZoomX, rZoomY, bShrink );
3352 	DBG_ERROR("Falsche Tabellennummer");
3353 	return sal_False;
3354 }
3355 
3356 
3357 void ScDocument::UpdateAllRowHeights( OutputDevice* pDev, double nPPTX, double nPPTY,
3358                                     const Fraction& rZoomX, const Fraction& rZoomY, const ScMarkData* pTabMark )
3359 {
3360     // one progress across all (selected) sheets
3361 
3362     sal_uLong nCellCount = 0;
3363     for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
3364         if ( pTab[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
3365             nCellCount += pTab[nTab]->GetWeightedCount();
3366 
3367     ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), nCellCount );
3368 
3369     sal_uLong nProgressStart = 0;
3370     for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
3371         if ( pTab[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
3372         {
3373             pTab[nTab]->SetOptimalHeight( 0, MAXROW, 0,
3374                         pDev, nPPTX, nPPTY, rZoomX, rZoomY, sal_False, &aProgress, nProgressStart );
3375             nProgressStart += pTab[nTab]->GetWeightedCount();
3376         }
3377 }
3378 
3379 
3380 //
3381 //	Spalten-/Zeilen-Flags	----------------------------------------------
3382 //
3383 
3384 void ScDocument::ShowCol(SCCOL nCol, SCTAB nTab, sal_Bool bShow)
3385 {
3386 	if ( ValidTab(nTab) && pTab[nTab] )
3387 		pTab[nTab]->ShowCol( nCol, bShow );
3388 }
3389 
3390 
3391 void ScDocument::ShowRow(SCROW nRow, SCTAB nTab, sal_Bool bShow)
3392 {
3393 	if ( ValidTab(nTab) && pTab[nTab] )
3394 		pTab[nTab]->ShowRow( nRow, bShow );
3395 }
3396 
3397 
3398 void ScDocument::ShowRows(SCROW nRow1, SCROW nRow2, SCTAB nTab, sal_Bool bShow)
3399 {
3400 	if ( ValidTab(nTab) && pTab[nTab] )
3401 		pTab[nTab]->ShowRows( nRow1, nRow2, bShow );
3402 }
3403 
3404 
3405 void ScDocument::SetColFlags( SCCOL nCol, SCTAB nTab, sal_uInt8 nNewFlags )
3406 {
3407 	if ( ValidTab(nTab) && pTab[nTab] )
3408 		pTab[nTab]->SetColFlags( nCol, nNewFlags );
3409 }
3410 
3411 
3412 void ScDocument::SetRowFlags( SCROW nRow, SCTAB nTab, sal_uInt8 nNewFlags )
3413 {
3414 	if ( ValidTab(nTab) && pTab[nTab] )
3415 		pTab[nTab]->SetRowFlags( nRow, nNewFlags );
3416 }
3417 
3418 
3419 void ScDocument::SetRowFlags( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt8 nNewFlags )
3420 {
3421 	if ( ValidTab(nTab) && pTab[nTab] )
3422 		pTab[nTab]->SetRowFlags( nStartRow, nEndRow, nNewFlags );
3423 }
3424 
3425 
3426 sal_uInt8 ScDocument::GetColFlags( SCCOL nCol, SCTAB nTab ) const
3427 {
3428 	if ( ValidTab(nTab) && pTab[nTab] )
3429 		return pTab[nTab]->GetColFlags( nCol );
3430 	DBG_ERROR("Falsche Tabellennummer");
3431 	return 0;
3432 }
3433 
3434 sal_uInt8 ScDocument::GetRowFlags( SCROW nRow, SCTAB nTab ) const
3435 {
3436 	if ( ValidTab(nTab) && pTab[nTab] )
3437 		return pTab[nTab]->GetRowFlags( nRow );
3438 	DBG_ERROR("Falsche Tabellennummer");
3439 	return 0;
3440 }
3441 
3442 ScBitMaskCompressedArray< SCROW, sal_uInt8> & ScDocument::GetRowFlagsArrayModifiable(
3443         SCTAB nTab )
3444 {
3445     return const_cast< ScBitMaskCompressedArray< SCROW, sal_uInt8> & >(
3446             GetRowFlagsArray( nTab));
3447 }
3448 
3449 const ScBitMaskCompressedArray< SCROW, sal_uInt8> & ScDocument::GetRowFlagsArray(
3450         SCTAB nTab ) const
3451 {
3452     const ScBitMaskCompressedArray< SCROW, sal_uInt8> * pFlags;
3453 	if ( ValidTab(nTab) && pTab[nTab] )
3454 		pFlags = pTab[nTab]->GetRowFlagsArray();
3455     else
3456     {
3457 	    DBG_ERROR("wrong sheet number");
3458         pFlags = 0;
3459     }
3460     if (!pFlags)
3461     {
3462         DBG_ERROR("no row flags at sheet");
3463         static ScBitMaskCompressedArray< SCROW, sal_uInt8> aDummy( MAXROW, 0);
3464         pFlags = &aDummy;
3465     }
3466 	return *pFlags;
3467 }
3468 
3469 void ScDocument::GetAllRowBreaks(set<SCROW>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
3470 {
3471     if (!ValidTab(nTab) || !pTab[nTab])
3472         return;
3473 
3474     pTab[nTab]->GetAllRowBreaks(rBreaks, bPage, bManual);
3475 }
3476 
3477 void ScDocument::GetAllColBreaks(set<SCCOL>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
3478 {
3479     if (!ValidTab(nTab) || !pTab[nTab])
3480         return;
3481 
3482     pTab[nTab]->GetAllColBreaks(rBreaks, bPage, bManual);
3483 }
3484 
3485 ScBreakType ScDocument::HasRowBreak(SCROW nRow, SCTAB nTab) const
3486 {
3487     ScBreakType nType = BREAK_NONE;
3488     if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
3489         return nType;
3490 
3491     if (pTab[nTab]->HasRowPageBreak(nRow))
3492         nType |= BREAK_PAGE;
3493 
3494     if (pTab[nTab]->HasRowManualBreak(nRow))
3495         nType |= BREAK_MANUAL;
3496 
3497     return nType;
3498 }
3499 
3500 ScBreakType ScDocument::HasColBreak(SCCOL nCol, SCTAB nTab) const
3501 {
3502     ScBreakType nType = BREAK_NONE;
3503     if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
3504         return nType;
3505 
3506     if (pTab[nTab]->HasColPageBreak(nCol))
3507         nType |= BREAK_PAGE;
3508 
3509     if (pTab[nTab]->HasColManualBreak(nCol))
3510         nType |= BREAK_MANUAL;
3511 
3512     return nType;
3513 }
3514 
3515 void ScDocument::SetRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
3516 {
3517     if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
3518         return;
3519 
3520     pTab[nTab]->SetRowBreak(nRow, bPage, bManual);
3521 }
3522 
3523 void ScDocument::SetColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
3524 {
3525     if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
3526         return;
3527 
3528     pTab[nTab]->SetColBreak(nCol, bPage, bManual);
3529 }
3530 
3531 void ScDocument::RemoveRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
3532 {
3533     if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
3534         return;
3535 
3536     pTab[nTab]->RemoveRowBreak(nRow, bPage, bManual);
3537 }
3538 
3539 void ScDocument::RemoveColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
3540 {
3541     if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
3542         return;
3543 
3544     pTab[nTab]->RemoveColBreak(nCol, bPage, bManual);
3545 }
3546 
3547 Sequence<TablePageBreakData> ScDocument::GetRowBreakData(SCTAB nTab) const
3548 {
3549     if (!ValidTab(nTab) || !pTab[nTab])
3550         return Sequence<TablePageBreakData>();
3551 
3552     return pTab[nTab]->GetRowBreakData();
3553 }
3554 
3555 bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow)
3556 {
3557     if (!ValidTab(nTab) || !pTab[nTab])
3558 		return false;
3559 
3560 	return pTab[nTab]->RowHidden(nRow, pFirstRow, pLastRow);
3561 }
3562 
3563 bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW& rLastRow)
3564 {
3565     if (!ValidTab(nTab) || !pTab[nTab])
3566 	{
3567 		rLastRow = nRow;
3568 		return false;
3569 	}
3570 
3571 	return pTab[nTab]->RowHidden(nRow, rLastRow);
3572 }
3573 
3574 
3575 bool ScDocument::HasHiddenRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3576 {
3577     if (!ValidTab(nTab) || !pTab[nTab])
3578 		return false;
3579 
3580 	return pTab[nTab]->HasHiddenRows(nStartRow, nEndRow);
3581 }
3582 
3583 bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL& rLastCol)
3584 {
3585     if (!ValidTab(nTab) || !pTab[nTab])
3586 	{
3587 		rLastCol = nCol;
3588 		return false;
3589 	}
3590 
3591 	return pTab[nTab]->ColHidden(nCol, rLastCol);
3592 }
3593 
3594 bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol)
3595 {
3596     if (!ValidTab(nTab) || !pTab[nTab])
3597 	{
3598         if (pFirstCol)
3599             *pFirstCol = nCol;
3600         if (pLastCol)
3601             *pLastCol = nCol;
3602 		return false;
3603 	}
3604 
3605 	return pTab[nTab]->ColHidden(nCol, pFirstCol, pLastCol);
3606 }
3607 
3608 void ScDocument::SetRowHidden(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHidden)
3609 {
3610 	if (!ValidTab(nTab) || !pTab[nTab])
3611 		return;
3612 
3613 	pTab[nTab]->SetRowHidden(nStartRow, nEndRow, bHidden);
3614 }
3615 
3616 void ScDocument::SetColHidden(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bHidden)
3617 {
3618 	if (!ValidTab(nTab) || !pTab[nTab])
3619 		return;
3620 
3621 	pTab[nTab]->SetColHidden(nStartCol, nEndCol, bHidden);
3622 }
3623 
3624 SCROW ScDocument::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3625 {
3626 	if (!ValidTab(nTab) || !pTab[nTab])
3627 		return ::std::numeric_limits<SCROW>::max();;
3628 
3629     return pTab[nTab]->FirstVisibleRow(nStartRow, nEndRow);
3630 }
3631 
3632 SCROW ScDocument::LastVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3633 {
3634 	if (!ValidTab(nTab) || !pTab[nTab])
3635 		return ::std::numeric_limits<SCROW>::max();;
3636 
3637     return pTab[nTab]->LastVisibleRow(nStartRow, nEndRow);
3638 }
3639 
3640 SCROW ScDocument::CountVisibleRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3641 {
3642 	if (!ValidTab(nTab) || !pTab[nTab])
3643         return 0;
3644 
3645     return pTab[nTab]->CountVisibleRows(nStartRow, nEndRow);
3646 }
3647 
3648 bool ScDocument::RowFiltered(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow)
3649 {
3650     if (!ValidTab(nTab) || !pTab[nTab])
3651 		return false;
3652 
3653 	return pTab[nTab]->RowFiltered(nRow, pFirstRow, pLastRow);
3654 }
3655 
3656 bool ScDocument::HasFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3657 {
3658     if (!ValidTab(nTab) || !pTab[nTab])
3659 		return false;
3660 
3661 	return pTab[nTab]->HasFilteredRows(nStartRow, nEndRow);
3662 }
3663 
3664 bool ScDocument::ColFiltered(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol)
3665 {
3666     if (!ValidTab(nTab) || !pTab[nTab])
3667 		return false;
3668 
3669 	return pTab[nTab]->ColFiltered(nCol, pFirstCol, pLastCol);
3670 }
3671 
3672 void ScDocument::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bFiltered)
3673 {
3674 	if (!ValidTab(nTab) || !pTab[nTab])
3675 		return;
3676 
3677 	pTab[nTab]->SetRowFiltered(nStartRow, nEndRow, bFiltered);
3678 }
3679 
3680 void ScDocument::SetColFiltered(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bFiltered)
3681 {
3682 	if (!ValidTab(nTab) || !pTab[nTab])
3683 		return;
3684 
3685 	pTab[nTab]->SetColFiltered(nStartCol, nEndCol, bFiltered);
3686 }
3687 
3688 SCROW ScDocument::FirstNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3689 {
3690 	if (!ValidTab(nTab) || !pTab[nTab])
3691 		return ::std::numeric_limits<SCROW>::max();;
3692 
3693     return pTab[nTab]->FirstNonFilteredRow(nStartRow, nEndRow);
3694 }
3695 
3696 SCROW ScDocument::LastNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3697 {
3698 	if (!ValidTab(nTab) || !pTab[nTab])
3699 		return ::std::numeric_limits<SCROW>::max();;
3700 
3701     return pTab[nTab]->LastNonFilteredRow(nStartRow, nEndRow);
3702 }
3703 
3704 SCROW ScDocument::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3705 {
3706 	if (!ValidTab(nTab) || !pTab[nTab])
3707         return 0;
3708 
3709     return pTab[nTab]->CountNonFilteredRows(nStartRow, nEndRow);
3710 }
3711 
3712 void ScDocument::SyncColRowFlags()
3713 {
3714     for (SCTAB i = 0; i <= nMaxTableNumber; ++i)
3715     {
3716         if (!ValidTab(i) || !pTab[i])
3717             continue;
3718 
3719         pTab[i]->SyncColRowFlags();
3720     }
3721 }
3722 
3723 SCROW ScDocument::GetLastFlaggedRow( SCTAB nTab ) const
3724 {
3725 	if ( ValidTab(nTab) && pTab[nTab] )
3726 		return pTab[nTab]->GetLastFlaggedRow();
3727 	return 0;
3728 }
3729 
3730 
3731 SCCOL ScDocument::GetLastChangedCol( SCTAB nTab ) const
3732 {
3733 	if ( ValidTab(nTab) && pTab[nTab] )
3734         return pTab[nTab]->GetLastChangedCol();
3735 	return 0;
3736 }
3737 
3738 SCROW ScDocument::GetLastChangedRow( SCTAB nTab ) const
3739 {
3740 	if ( ValidTab(nTab) && pTab[nTab] )
3741         return pTab[nTab]->GetLastChangedRow();
3742 	return 0;
3743 }
3744 
3745 
3746 SCCOL ScDocument::GetNextDifferentChangedCol( SCTAB nTab, SCCOL nStart) const
3747 {
3748 	if ( ValidTab(nTab) && pTab[nTab] )
3749 	{
3750 		sal_uInt8 nStartFlags = pTab[nTab]->GetColFlags(nStart);
3751 		sal_uInt16 nStartWidth = pTab[nTab]->GetOriginalWidth(nStart);
3752 		for (SCCOL nCol = nStart + 1; nCol <= MAXCOL; nCol++)
3753 		{
3754 			if (((nStartFlags & CR_MANUALBREAK) != (pTab[nTab]->GetColFlags(nCol) & CR_MANUALBREAK)) ||
3755 				(nStartWidth != pTab[nTab]->GetOriginalWidth(nCol)) ||
3756 				((nStartFlags & CR_HIDDEN) != (pTab[nTab]->GetColFlags(nCol) & CR_HIDDEN)) )
3757 				return nCol;
3758 		}
3759 		return MAXCOL+1;
3760 	}
3761 	return 0;
3762 }
3763 
3764 SCROW ScDocument::GetNextDifferentChangedRow( SCTAB nTab, SCROW nStart, bool bCareManualSize) const
3765 {
3766     const ScBitMaskCompressedArray< SCROW, sal_uInt8> * pRowFlagsArray;
3767     if ( ValidTab(nTab) && pTab[nTab] && ((pRowFlagsArray = pTab[nTab]->GetRowFlagsArray()) != NULL) &&
3768             pTab[nTab]->mpRowHeights && pTab[nTab]->mpHiddenRows )
3769     {
3770         size_t nIndex;          // ignored
3771         SCROW nFlagsEndRow;
3772         SCROW nHiddenEndRow;
3773         SCROW nHeightEndRow;
3774         sal_uInt8 nFlags;
3775         bool bHidden;
3776         sal_uInt16 nHeight;
3777         sal_uInt8 nStartFlags = nFlags = pRowFlagsArray->GetValue( nStart, nIndex, nFlagsEndRow);
3778         bool bStartHidden = bHidden = pTab[nTab]->RowHidden( nStart, NULL, &nHiddenEndRow);
3779         sal_uInt16 nStartHeight = nHeight = pTab[nTab]->GetRowHeight( nStart, NULL, &nHeightEndRow, false);
3780         SCROW nRow;
3781         while ((nRow = std::min( nHiddenEndRow, std::min( nFlagsEndRow, nHeightEndRow)) + 1) <= MAXROW)
3782         {
3783             if (nFlagsEndRow < nRow)
3784                 nFlags = pRowFlagsArray->GetValue( nRow, nIndex, nFlagsEndRow);
3785             if (nHiddenEndRow < nRow)
3786                 bHidden = pTab[nTab]->RowHidden( nRow, NULL, &nHiddenEndRow);
3787             if (nHeightEndRow < nRow)
3788                 nHeight = pTab[nTab]->GetRowHeight( nRow, NULL, &nHeightEndRow, false);
3789             if (    ((nStartFlags & CR_MANUALBREAK) != (nFlags & CR_MANUALBREAK)) ||
3790                     ((nStartFlags & CR_MANUALSIZE) != (nFlags & CR_MANUALSIZE)) ||
3791                     (bStartHidden != bHidden) ||
3792                     (bCareManualSize && (nStartFlags & CR_MANUALSIZE) && (nStartHeight != nHeight)) ||
3793                     (!bCareManualSize && ((nStartHeight != nHeight))))
3794                 return nRow;
3795         }
3796         return MAXROW+1;
3797     }
3798     return 0;
3799 }
3800 
3801 sal_Bool ScDocument::GetColDefault( SCTAB nTab, SCCOL nCol, SCROW nLastRow, SCROW& nDefault)
3802 {
3803 	sal_Bool bRet(sal_False);
3804 	nDefault = 0;
3805 	ScDocAttrIterator aDocAttrItr(this, nTab, nCol, 0, nCol, nLastRow);
3806 	SCCOL nColumn;
3807 	SCROW nStartRow;
3808 	SCROW nEndRow;
3809 	const ScPatternAttr* pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
3810 	if (nEndRow < nLastRow)
3811 	{
3812 		ScDefaultAttrSet aSet;
3813 		ScDefaultAttrSet::iterator aItr = aSet.end();
3814 		while (pAttr)
3815 		{
3816 			ScDefaultAttr aAttr(pAttr);
3817 			aItr = aSet.find(aAttr);
3818 			if (aItr == aSet.end())
3819 			{
3820 				aAttr.nCount = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
3821 				aAttr.nFirst = nStartRow;
3822 				aSet.insert(aAttr);
3823 			}
3824 			else
3825 			{
3826 				aAttr.nCount = aItr->nCount + static_cast<SCSIZE>(nEndRow - nStartRow + 1);
3827 				aAttr.nFirst = aItr->nFirst;
3828 				aSet.erase(aItr);
3829 				aSet.insert(aAttr);
3830 			}
3831 			pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
3832 		}
3833 		ScDefaultAttrSet::iterator aDefaultItr = aSet.begin();
3834 		aItr = aDefaultItr;
3835 		aItr++;
3836 		while (aItr != aSet.end())
3837 		{
3838             // for entries with equal count, use the one with the lowest start row,
3839             // don't use the random order of pointer comparisons
3840             if ( aItr->nCount > aDefaultItr->nCount ||
3841                  ( aItr->nCount == aDefaultItr->nCount && aItr->nFirst < aDefaultItr->nFirst ) )
3842 				aDefaultItr = aItr;
3843 			aItr++;
3844 		}
3845 		nDefault = aDefaultItr->nFirst;
3846 		bRet = sal_True;
3847 	}
3848 	else
3849 		bRet = sal_True;
3850 	return bRet;
3851 }
3852 
3853 sal_Bool ScDocument::GetRowDefault( SCTAB /* nTab */, SCROW /* nRow */, SCCOL /* nLastCol */, SCCOL& /* nDefault */ )
3854 {
3855 	sal_Bool bRet(sal_False);
3856 	return bRet;
3857 }
3858 
3859 void ScDocument::StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
3860 {
3861 	if ( ValidTab(nTab) && pTab[nTab] )
3862 		pTab[nTab]->StripHidden( rX1, rY1, rX2, rY2 );
3863 }
3864 
3865 
3866 void ScDocument::ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
3867 {
3868 	if ( ValidTab(nTab) && pTab[nTab] )
3869 		pTab[nTab]->ExtendHidden( rX1, rY1, rX2, rY2 );
3870 }
3871 
3872 //
3873 //	Attribute	----------------------------------------------------------
3874 //
3875 
3876 const SfxPoolItem* ScDocument::GetAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich ) const
3877 {
3878 	if ( ValidTab(nTab)  && pTab[nTab] )
3879 	{
3880 		const SfxPoolItem* pTemp = pTab[nTab]->GetAttr( nCol, nRow, nWhich );
3881 		if (pTemp)
3882 			return pTemp;
3883 		else
3884 		{
3885 			DBG_ERROR( "Attribut Null" );
3886 		}
3887 	}
3888 	return &xPoolHelper->GetDocPool()->GetDefaultItem( nWhich );
3889 }
3890 
3891 
3892 const ScPatternAttr* ScDocument::GetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3893 {
3894 	if ( ValidTab(nTab)  && pTab[nTab] )
3895 		return pTab[nTab]->GetPattern( nCol, nRow );
3896 	return NULL;
3897 }
3898 
3899 
3900 const ScPatternAttr* ScDocument::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
3901 {
3902     if ( ValidTab(nTab)  && pTab[nTab] )
3903         return pTab[nTab]->GetMostUsedPattern( nCol, nStartRow, nEndRow );
3904     return NULL;
3905 }
3906 
3907 
3908 void ScDocument::ApplyAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem& rAttr )
3909 {
3910 	if ( ValidTab(nTab)  && pTab[nTab] )
3911 		pTab[nTab]->ApplyAttr( nCol, nRow, rAttr );
3912 }
3913 
3914 
3915 void ScDocument::ApplyPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr )
3916 {
3917 	if ( ValidTab(nTab)  && pTab[nTab] )
3918 		pTab[nTab]->ApplyPattern( nCol, nRow, rAttr );
3919 }
3920 
3921 
3922 void ScDocument::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow,
3923 						SCCOL nEndCol, SCROW nEndRow,
3924 						const ScMarkData& rMark,
3925 						const ScPatternAttr& rAttr )
3926 {
3927 	for (SCTAB i=0; i <= MAXTAB; i++)
3928 		if (pTab[i])
3929 			if (rMark.GetTableSelect(i))
3930 				pTab[i]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
3931 }
3932 
3933 
3934 void ScDocument::ApplyPatternAreaTab( SCCOL nStartCol, SCROW nStartRow,
3935 						SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScPatternAttr& rAttr )
3936 {
3937 	if (VALIDTAB(nTab))
3938 		if (pTab[nTab])
3939 			pTab[nTab]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
3940 }
3941 
3942 void ScDocument::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
3943 		const ScMarkData& rMark, const ScPatternAttr& rPattern, short nNewType )
3944 {
3945 	for (SCTAB i=0; i <= MAXTAB; i++)
3946 		if (pTab[i])
3947 			if (rMark.GetTableSelect(i))
3948 				pTab[i]->ApplyPatternIfNumberformatIncompatible( rRange, rPattern, nNewType );
3949 }
3950 
3951 
3952 void ScDocument::ApplyStyle( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScStyleSheet& rStyle)
3953 {
3954 	if (VALIDTAB(nTab))
3955 		if (pTab[nTab])
3956 			pTab[nTab]->ApplyStyle( nCol, nRow, rStyle );
3957 }
3958 
3959 
3960 void ScDocument::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow,
3961 						SCCOL nEndCol, SCROW nEndRow,
3962 						const ScMarkData& rMark,
3963 						const ScStyleSheet& rStyle)
3964 {
3965 	for (SCTAB i=0; i <= MAXTAB; i++)
3966 		if (pTab[i])
3967 			if (rMark.GetTableSelect(i))
3968 				pTab[i]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
3969 }
3970 
3971 
3972 void ScDocument::ApplyStyleAreaTab( SCCOL nStartCol, SCROW nStartRow,
3973 						SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScStyleSheet& rStyle)
3974 {
3975 	if (VALIDTAB(nTab))
3976 		if (pTab[nTab])
3977 			pTab[nTab]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
3978 }
3979 
3980 
3981 void ScDocument::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
3982 {
3983 	// ApplySelectionStyle needs multi mark
3984 	if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
3985 	{
3986 		ScRange aRange;
3987 		rMark.GetMarkArea( aRange );
3988 		ApplyStyleArea( aRange.aStart.Col(), aRange.aStart.Row(),
3989 						  aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rStyle );
3990 	}
3991 	else
3992 	{
3993 		for (SCTAB i=0; i<=MAXTAB; i++)
3994 			if ( pTab[i] && rMark.GetTableSelect(i) )
3995 					pTab[i]->ApplySelectionStyle( rStyle, rMark );
3996 	}
3997 }
3998 
3999 
4000 void ScDocument::ApplySelectionLineStyle( const ScMarkData& rMark,
4001 					const SvxBorderLine* pLine, sal_Bool bColorOnly )
4002 {
4003 	if ( bColorOnly && !pLine )
4004 		return;
4005 
4006 	for (SCTAB i=0; i<=MAXTAB; i++)
4007 		if (pTab[i])
4008 			if (rMark.GetTableSelect(i))
4009 				pTab[i]->ApplySelectionLineStyle( rMark, pLine, bColorOnly );
4010 }
4011 
4012 
4013 const ScStyleSheet*	ScDocument::GetStyle( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4014 {
4015 	if ( VALIDTAB(nTab) && pTab[nTab] )
4016 		return pTab[nTab]->GetStyle(nCol, nRow);
4017 	else
4018 		return NULL;
4019 }
4020 
4021 
4022 const ScStyleSheet*	ScDocument::GetSelectionStyle( const ScMarkData& rMark ) const
4023 {
4024 	sal_Bool	bEqual = sal_True;
4025 	sal_Bool	bFound;
4026 
4027 	const ScStyleSheet* pStyle = NULL;
4028 	const ScStyleSheet* pNewStyle;
4029 
4030 	if ( rMark.IsMultiMarked() )
4031 		for (SCTAB i=0; i<=MAXTAB && bEqual; i++)
4032 			if (pTab[i] && rMark.GetTableSelect(i))
4033 			{
4034 				pNewStyle = pTab[i]->GetSelectionStyle( rMark, bFound );
4035 				if (bFound)
4036 				{
4037 					if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
4038 						bEqual = sal_False;												// unterschiedliche
4039 					pStyle = pNewStyle;
4040 				}
4041 			}
4042 	if ( rMark.IsMarked() )
4043 	{
4044 		ScRange aRange;
4045 		rMark.GetMarkArea( aRange );
4046 		for (SCTAB i=aRange.aStart.Tab(); i<=aRange.aEnd.Tab() && bEqual; i++)
4047 			if (pTab[i] && rMark.GetTableSelect(i))
4048 			{
4049 				pNewStyle = pTab[i]->GetAreaStyle( bFound,
4050 										aRange.aStart.Col(), aRange.aStart.Row(),
4051 										aRange.aEnd.Col(),   aRange.aEnd.Row()   );
4052 				if (bFound)
4053 				{
4054 					if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
4055 						bEqual = sal_False;												// unterschiedliche
4056 					pStyle = pNewStyle;
4057 				}
4058 			}
4059 	}
4060 
4061 	return bEqual ? pStyle : NULL;
4062 }
4063 
4064 
4065 void ScDocument::StyleSheetChanged( const SfxStyleSheetBase* pStyleSheet, sal_Bool bRemoved,
4066 									OutputDevice* pDev,
4067 									double nPPTX, double nPPTY,
4068 									const Fraction& rZoomX, const Fraction& rZoomY )
4069 {
4070 	for (SCTAB i=0; i <= MAXTAB; i++)
4071 		if (pTab[i])
4072 			pTab[i]->StyleSheetChanged
4073 				( pStyleSheet, bRemoved, pDev, nPPTX, nPPTY, rZoomX, rZoomY );
4074 
4075 	if ( pStyleSheet && pStyleSheet->GetName() == ScGlobal::GetRscString(STR_STYLENAME_STANDARD) )
4076 	{
4077 		//	update attributes for all note objects
4078         ScDetectiveFunc::UpdateAllComments( *this );
4079 	}
4080 }
4081 
4082 
4083 sal_Bool ScDocument::IsStyleSheetUsed( const ScStyleSheet& rStyle, sal_Bool bGatherAllStyles ) const
4084 {
4085     if ( bStyleSheetUsageInvalid || rStyle.GetUsage() == ScStyleSheet::UNKNOWN )
4086     {
4087         if ( bGatherAllStyles )
4088         {
4089             SfxStyleSheetIterator aIter( xPoolHelper->GetStylePool(),
4090                     SFX_STYLE_FAMILY_PARA );
4091             for ( const SfxStyleSheetBase* pStyle = aIter.First(); pStyle;
4092                                            pStyle = aIter.Next() )
4093             {
4094                 const ScStyleSheet* pScStyle = PTR_CAST( ScStyleSheet, pStyle );
4095                 if ( pScStyle )
4096                     pScStyle->SetUsage( ScStyleSheet::NOTUSED );
4097             }
4098         }
4099 
4100         sal_Bool bIsUsed = sal_False;
4101 
4102         for ( SCTAB i=0; i<=MAXTAB; i++ )
4103         {
4104             if ( pTab[i] )
4105             {
4106                 if ( pTab[i]->IsStyleSheetUsed( rStyle, bGatherAllStyles ) )
4107                 {
4108                     if ( !bGatherAllStyles )
4109                         return sal_True;
4110                     bIsUsed = sal_True;
4111                 }
4112             }
4113         }
4114 
4115         if ( bGatherAllStyles )
4116             bStyleSheetUsageInvalid = sal_False;
4117 
4118         return bIsUsed;
4119     }
4120 
4121     return rStyle.GetUsage() == ScStyleSheet::USED;
4122 }
4123 
4124 
4125 sal_Bool ScDocument::ApplyFlagsTab( SCCOL nStartCol, SCROW nStartRow,
4126 						SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, sal_Int16 nFlags )
4127 {
4128 	if (VALIDTAB(nTab))
4129 		if (pTab[nTab])
4130 			return pTab[nTab]->ApplyFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
4131 
4132 	DBG_ERROR("ApplyFlags: falsche Tabelle");
4133 	return sal_False;
4134 }
4135 
4136 
4137 sal_Bool ScDocument::RemoveFlagsTab( SCCOL nStartCol, SCROW nStartRow,
4138 						SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, sal_Int16 nFlags )
4139 {
4140 	if (VALIDTAB(nTab))
4141 		if (pTab[nTab])
4142 			return pTab[nTab]->RemoveFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
4143 
4144 	DBG_ERROR("RemoveFlags: falsche Tabelle");
4145 	return sal_False;
4146 }
4147 
4148 
4149 void ScDocument::SetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr,
4150 								sal_Bool bPutToPool )
4151 {
4152 	if (VALIDTAB(nTab))
4153 		if (pTab[nTab])
4154 			pTab[nTab]->SetPattern( nCol, nRow, rAttr, bPutToPool );
4155 }
4156 
4157 
4158 void ScDocument::SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr,
4159 								sal_Bool bPutToPool )
4160 {
4161 	SCTAB nTab = rPos.Tab();
4162 	if (pTab[nTab])
4163 		pTab[nTab]->SetPattern( rPos, rAttr, bPutToPool );
4164 }
4165 
4166 
4167 ScPatternAttr* ScDocument::CreateSelectionPattern( const ScMarkData& rMark, sal_Bool bDeep )
4168 {
4169     ScMergePatternState aState;
4170 
4171 	if ( rMark.IsMultiMarked() )								// multi selection
4172 	{
4173 		for (SCTAB i=0; i<=MAXTAB; i++)
4174 			if (pTab[i] && rMark.GetTableSelect(i))
4175 				pTab[i]->MergeSelectionPattern( aState, rMark, bDeep );
4176 	}
4177 	if ( rMark.IsMarked() )										// simle selection
4178 	{
4179 		ScRange aRange;
4180 		rMark.GetMarkArea(aRange);
4181 		for (SCTAB i=0; i<=MAXTAB; i++)
4182 			if (pTab[i] && rMark.GetTableSelect(i))
4183 				pTab[i]->MergePatternArea( aState,
4184 								aRange.aStart.Col(), aRange.aStart.Row(),
4185 								aRange.aEnd.Col(), aRange.aEnd.Row(), bDeep );
4186 	}
4187 
4188 	DBG_ASSERT( aState.pItemSet, "SelectionPattern Null" );
4189 	if (aState.pItemSet)
4190 		return new ScPatternAttr( aState.pItemSet );
4191 	else
4192 		return new ScPatternAttr( GetPool() );		// empty
4193 }
4194 
4195 
4196 const ScPatternAttr* ScDocument::GetSelectionPattern( const ScMarkData& rMark, sal_Bool bDeep )
4197 {
4198 	delete pSelectionAttr;
4199 	pSelectionAttr = CreateSelectionPattern( rMark, bDeep );
4200 	return pSelectionAttr;
4201 }
4202 
4203 
4204 void ScDocument::GetSelectionFrame( const ScMarkData& rMark,
4205 									SvxBoxItem&		rLineOuter,
4206 									SvxBoxInfoItem&	rLineInner )
4207 {
4208 	rLineOuter.SetLine(NULL, BOX_LINE_TOP);
4209 	rLineOuter.SetLine(NULL, BOX_LINE_BOTTOM);
4210 	rLineOuter.SetLine(NULL, BOX_LINE_LEFT);
4211 	rLineOuter.SetLine(NULL, BOX_LINE_RIGHT);
4212 	rLineOuter.SetDistance(0);
4213 
4214 	rLineInner.SetLine(NULL, BOXINFO_LINE_HORI);
4215 	rLineInner.SetLine(NULL, BOXINFO_LINE_VERT);
4216 	rLineInner.SetTable(sal_True);
4217     rLineInner.SetDist(sal_True);
4218     rLineInner.SetMinDist(sal_False);
4219 
4220 	ScLineFlags aFlags;
4221 
4222 	if (rMark.IsMarked())
4223 	{
4224 		ScRange aRange;
4225 		rMark.GetMarkArea(aRange);
4226         rLineInner.EnableHor( aRange.aStart.Row() != aRange.aEnd.Row() );
4227         rLineInner.EnableVer( aRange.aStart.Col() != aRange.aEnd.Col() );
4228 		for (SCTAB i=0; i<=MAXTAB; i++)
4229 			if (pTab[i] && rMark.GetTableSelect(i))
4230 				pTab[i]->MergeBlockFrame( &rLineOuter, &rLineInner, aFlags,
4231 										  aRange.aStart.Col(), aRange.aStart.Row(),
4232 										  aRange.aEnd.Col(),   aRange.aEnd.Row() );
4233 	}
4234 
4235 		//	Don't care Status auswerten
4236 
4237 	rLineInner.SetValid( VALID_LEFT,   ( aFlags.nLeft != SC_LINE_DONTCARE ) );
4238 	rLineInner.SetValid( VALID_RIGHT,  ( aFlags.nRight != SC_LINE_DONTCARE ) );
4239 	rLineInner.SetValid( VALID_TOP,    ( aFlags.nTop != SC_LINE_DONTCARE ) );
4240 	rLineInner.SetValid( VALID_BOTTOM, ( aFlags.nBottom != SC_LINE_DONTCARE ) );
4241 	rLineInner.SetValid( VALID_HORI,   ( aFlags.nHori != SC_LINE_DONTCARE ) );
4242 	rLineInner.SetValid( VALID_VERT,   ( aFlags.nVert != SC_LINE_DONTCARE ) );
4243 }
4244 
4245 
4246 bool ScDocument::HasAttrib( SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
4247                             SCCOL nCol2, SCROW nRow2, SCTAB nTab2, sal_uInt16 nMask )
4248 {
4249     if ( nMask & HASATTR_ROTATE )
4250     {
4251         //  Attribut im Dokument ueberhaupt verwendet?
4252         //  (wie in fillinfo)
4253 
4254         ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4255 
4256         sal_Bool bAnyItem = sal_False;
4257         sal_uInt32 nRotCount = pPool->GetItemCount2( ATTR_ROTATE_VALUE );
4258         for (sal_uInt32 nItem=0; nItem<nRotCount; nItem++)
4259         {
4260             const SfxPoolItem* pItem = pPool->GetItem2( ATTR_ROTATE_VALUE, nItem );
4261             if ( pItem )
4262             {
4263                 // 90 or 270 degrees is former SvxOrientationItem - only look for other values
4264                 // (see ScPatternAttr::GetCellOrientation)
4265                 sal_Int32 nAngle = static_cast<const SfxInt32Item*>(pItem)->GetValue();
4266                 if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
4267                 {
4268                     bAnyItem = sal_True;
4269                     break;
4270                 }
4271             }
4272         }
4273         if (!bAnyItem)
4274             nMask &= ~HASATTR_ROTATE;
4275     }
4276 
4277     if ( nMask & HASATTR_RTL )
4278     {
4279         //  first check if right-to left is in the pool at all
4280         //  (the same item is used in cell and page format)
4281 
4282         ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4283 
4284         sal_Bool bHasRtl = sal_False;
4285         sal_uInt32 nDirCount = pPool->GetItemCount2( ATTR_WRITINGDIR );
4286         for (sal_uInt32 nItem=0; nItem<nDirCount; nItem++)
4287         {
4288             const SfxPoolItem* pItem = pPool->GetItem2( ATTR_WRITINGDIR, nItem );
4289             if ( pItem && ((const SvxFrameDirectionItem*)pItem)->GetValue() == FRMDIR_HORI_RIGHT_TOP )
4290             {
4291                 bHasRtl = sal_True;
4292                 break;
4293             }
4294         }
4295         if (!bHasRtl)
4296             nMask &= ~HASATTR_RTL;
4297     }
4298 
4299     if (!nMask)
4300         return false;
4301 
4302     bool bFound = false;
4303     for (SCTAB i=nTab1; i<=nTab2 && !bFound; i++)
4304         if (pTab[i])
4305         {
4306             if ( nMask & HASATTR_RTL )
4307             {
4308                 if ( GetEditTextDirection(i) == EE_HTEXTDIR_R2L )       // sheet default
4309                     bFound = true;
4310             }
4311             if ( nMask & HASATTR_RIGHTORCENTER )
4312             {
4313                 //  On a RTL sheet, don't start to look for the default left value
4314                 //  (which is then logically right), instead always assume sal_True.
4315                 //  That way, ScAttrArray::HasAttrib doesn't have to handle RTL sheets.
4316 
4317                 if ( IsLayoutRTL(i) )
4318                     bFound = true;
4319             }
4320 
4321             if ( !bFound )
4322                 bFound = pTab[i]->HasAttrib( nCol1, nRow1, nCol2, nRow2, nMask );
4323         }
4324 
4325     return bFound;
4326 }
4327 
4328 bool ScDocument::HasAttrib( const ScRange& rRange, sal_uInt16 nMask )
4329 {
4330     return HasAttrib( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
4331                       rRange.aEnd.Col(),   rRange.aEnd.Row(),   rRange.aEnd.Tab(),
4332                       nMask );
4333 }
4334 
4335 void ScDocument::FindMaxRotCol( SCTAB nTab, RowInfo* pRowInfo, SCSIZE nArrCount,
4336 								SCCOL nX1, SCCOL nX2 ) const
4337 {
4338 	if ( ValidTab(nTab)  && pTab[nTab] )
4339 		pTab[nTab]->FindMaxRotCol( pRowInfo, nArrCount, nX1, nX2 );
4340 	else
4341 	{
4342 		DBG_ERRORFILE("FindMaxRotCol: falsche Tabelle");
4343 	}
4344 }
4345 
4346 void ScDocument::GetBorderLines( SCCOL nCol, SCROW nRow, SCTAB nTab,
4347 						const SvxBorderLine** ppLeft, const SvxBorderLine** ppTop,
4348 						const SvxBorderLine** ppRight, const SvxBorderLine** ppBottom ) const
4349 {
4350 	//!	Seitengrenzen fuer Druck beruecksichtigen !!!!!
4351 
4352 	const SvxBoxItem* pThisAttr = (const SvxBoxItem*) GetEffItem( nCol, nRow, nTab, ATTR_BORDER );
4353 	DBG_ASSERT(pThisAttr,"wo ist das Attribut?");
4354 
4355 	const SvxBorderLine* pLeftLine   = pThisAttr->GetLeft();
4356 	const SvxBorderLine* pTopLine    = pThisAttr->GetTop();
4357 	const SvxBorderLine* pRightLine  = pThisAttr->GetRight();
4358 	const SvxBorderLine* pBottomLine = pThisAttr->GetBottom();
4359 
4360 	if ( nCol > 0 )
4361 	{
4362 		const SvxBorderLine* pOther = ((const SvxBoxItem*)
4363 								GetEffItem( nCol-1, nRow, nTab, ATTR_BORDER ))->GetRight();
4364 		if ( ScHasPriority( pOther, pLeftLine ) )
4365 			pLeftLine = pOther;
4366 	}
4367 	if ( nRow > 0 )
4368 	{
4369 		const SvxBorderLine* pOther = ((const SvxBoxItem*)
4370 								GetEffItem( nCol, nRow-1, nTab, ATTR_BORDER ))->GetBottom();
4371 		if ( ScHasPriority( pOther, pTopLine ) )
4372 			pTopLine = pOther;
4373 	}
4374 	if ( nCol < MAXCOL )
4375 	{
4376 		const SvxBorderLine* pOther = ((const SvxBoxItem*)
4377 								GetEffItem( nCol+1, nRow, nTab, ATTR_BORDER ))->GetLeft();
4378 		if ( ScHasPriority( pOther, pRightLine ) )
4379 			pRightLine = pOther;
4380 	}
4381 	if ( nRow < MAXROW )
4382 	{
4383 		const SvxBorderLine* pOther = ((const SvxBoxItem*)
4384 								GetEffItem( nCol, nRow+1, nTab, ATTR_BORDER ))->GetTop();
4385 		if ( ScHasPriority( pOther, pBottomLine ) )
4386 			pBottomLine = pOther;
4387 	}
4388 
4389 	if (ppLeft)
4390 		*ppLeft = pLeftLine;
4391 	if (ppTop)
4392 		*ppTop = pTopLine;
4393 	if (ppRight)
4394 		*ppRight = pRightLine;
4395 	if (ppBottom)
4396 		*ppBottom = pBottomLine;
4397 }
4398 
4399 sal_Bool ScDocument::IsBlockEmpty( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
4400 										SCCOL nEndCol, SCROW nEndRow, bool bIgnoreNotes ) const
4401 {
4402 	if (VALIDTAB(nTab))
4403 		if (pTab[nTab])
4404 			return pTab[nTab]->IsBlockEmpty( nStartCol, nStartRow, nEndCol, nEndRow, bIgnoreNotes );
4405 
4406 	DBG_ERROR("Falsche Tabellennummer");
4407 	return sal_False;
4408 }
4409 
4410 
4411 void ScDocument::LockTable(SCTAB nTab)
4412 {
4413 	if ( ValidTab(nTab)  && pTab[nTab] )
4414 		pTab[nTab]->LockTable();
4415 	else
4416 	{
4417 		DBG_ERROR("Falsche Tabellennummer");
4418 	}
4419 }
4420 
4421 
4422 void ScDocument::UnlockTable(SCTAB nTab)
4423 {
4424 	if ( ValidTab(nTab)  && pTab[nTab] )
4425 		pTab[nTab]->UnlockTable();
4426 	else
4427 	{
4428 		DBG_ERROR("Falsche Tabellennummer");
4429 	}
4430 }
4431 
4432 
4433 sal_Bool ScDocument::IsBlockEditable( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
4434 										SCCOL nEndCol, SCROW nEndRow,
4435 										sal_Bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
4436 {
4437     // import into read-only document is possible
4438     if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
4439 	{
4440 		if ( pOnlyNotBecauseOfMatrix )
4441 			*pOnlyNotBecauseOfMatrix = sal_False;
4442 		return sal_False;
4443 	}
4444 
4445 	if (VALIDTAB(nTab))
4446 		if (pTab[nTab])
4447 			return pTab[nTab]->IsBlockEditable( nStartCol, nStartRow, nEndCol,
4448 				nEndRow, pOnlyNotBecauseOfMatrix );
4449 
4450 	DBG_ERROR("Falsche Tabellennummer");
4451 	if ( pOnlyNotBecauseOfMatrix )
4452 		*pOnlyNotBecauseOfMatrix = sal_False;
4453 	return sal_False;
4454 }
4455 
4456 
4457 sal_Bool ScDocument::IsSelectionEditable( const ScMarkData& rMark,
4458 			sal_Bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
4459 {
4460     // import into read-only document is possible
4461     if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
4462 	{
4463 		if ( pOnlyNotBecauseOfMatrix )
4464 			*pOnlyNotBecauseOfMatrix = sal_False;
4465 		return sal_False;
4466 	}
4467 
4468 	ScRange aRange;
4469 	rMark.GetMarkArea(aRange);
4470 
4471 	sal_Bool bOk = sal_True;
4472 	sal_Bool bMatrix = ( pOnlyNotBecauseOfMatrix != NULL );
4473 	for ( SCTAB i=0; i<=MAXTAB && (bOk || bMatrix); i++ )
4474 	{
4475 		if ( pTab[i] && rMark.GetTableSelect(i) )
4476 		{
4477 			if (rMark.IsMarked())
4478 			{
4479 				if ( !pTab[i]->IsBlockEditable( aRange.aStart.Col(),
4480 						aRange.aStart.Row(), aRange.aEnd.Col(),
4481 						aRange.aEnd.Row(), pOnlyNotBecauseOfMatrix ) )
4482 				{
4483 					bOk = sal_False;
4484 					if ( pOnlyNotBecauseOfMatrix )
4485 						bMatrix = *pOnlyNotBecauseOfMatrix;
4486 				}
4487 			}
4488 			if (rMark.IsMultiMarked())
4489 			{
4490 				if ( !pTab[i]->IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix ) )
4491 				{
4492 					bOk = sal_False;
4493 					if ( pOnlyNotBecauseOfMatrix )
4494 						bMatrix = *pOnlyNotBecauseOfMatrix;
4495 				}
4496 			}
4497 		}
4498 	}
4499 
4500 	if ( pOnlyNotBecauseOfMatrix )
4501 		*pOnlyNotBecauseOfMatrix = ( !bOk && bMatrix );
4502 
4503 	return bOk;
4504 }
4505 
4506 
4507 sal_Bool ScDocument::HasSelectedBlockMatrixFragment( SCCOL nStartCol, SCROW nStartRow,
4508 								SCCOL nEndCol, SCROW nEndRow,
4509 								const ScMarkData& rMark ) const
4510 {
4511 	sal_Bool bOk = sal_True;
4512 	for (SCTAB i=0; i<=MAXTAB && bOk; i++)
4513 		if (pTab[i])
4514 			if (rMark.GetTableSelect(i))
4515 				if (pTab[i]->HasBlockMatrixFragment( nStartCol, nStartRow, nEndCol, nEndRow ))
4516 					bOk = sal_False;
4517 
4518 	return !bOk;
4519 }
4520 
4521 
4522 sal_Bool ScDocument::GetMatrixFormulaRange( const ScAddress& rCellPos, ScRange& rMatrix )
4523 {
4524 	//	if rCell is part of a matrix formula, return its complete range
4525 
4526 	sal_Bool bRet = sal_False;
4527 	ScBaseCell* pCell = GetCell( rCellPos );
4528 	if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
4529 	{
4530 		ScAddress aOrigin = rCellPos;
4531 		if ( ((ScFormulaCell*)pCell)->GetMatrixOrigin( aOrigin ) )
4532 		{
4533 			if ( aOrigin != rCellPos )
4534 				pCell = GetCell( aOrigin );
4535 			if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
4536 			{
4537 				SCCOL nSizeX;
4538                 SCROW nSizeY;
4539 				((ScFormulaCell*)pCell)->GetMatColsRows(nSizeX,nSizeY);
4540 				if ( !(nSizeX > 0 && nSizeY > 0) )
4541 				{
4542 					// GetMatrixEdge computes also dimensions of the matrix
4543 					// if not already done (may occur if document is loaded
4544 					// from old file format).
4545 					// Needs an "invalid" initialized address.
4546 					aOrigin.SetInvalid();
4547 					((ScFormulaCell*)pCell)->GetMatrixEdge(aOrigin);
4548 					((ScFormulaCell*)pCell)->GetMatColsRows(nSizeX,nSizeY);
4549 				}
4550 				if ( nSizeX > 0 && nSizeY > 0 )
4551 				{
4552 					ScAddress aEnd( aOrigin.Col() + nSizeX - 1,
4553 									aOrigin.Row() + nSizeY - 1,
4554 									aOrigin.Tab() );
4555 
4556 					rMatrix.aStart = aOrigin;
4557 					rMatrix.aEnd = aEnd;
4558 					bRet = sal_True;
4559 				}
4560 			}
4561 		}
4562 	}
4563 	return bRet;
4564 }
4565 
4566 
4567 sal_Bool ScDocument::ExtendOverlapped( SCCOL& rStartCol, SCROW& rStartRow,
4568 								SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
4569 {
4570 	sal_Bool bFound = sal_False;
4571 	if ( ValidColRow(rStartCol,rStartRow) && ValidColRow(nEndCol,nEndRow) && ValidTab(nTab) )
4572 	{
4573 		if (pTab[nTab])
4574 		{
4575 			SCCOL nCol;
4576 			SCCOL nOldCol = rStartCol;
4577 			SCROW nOldRow = rStartRow;
4578 			for (nCol=nOldCol; nCol<=nEndCol; nCol++)
4579 				while (((ScMergeFlagAttr*)GetAttr(nCol,rStartRow,nTab,ATTR_MERGE_FLAG))->
4580 							IsVerOverlapped())
4581 					--rStartRow;
4582 
4583 			//!		weiterreichen ?
4584 
4585 			ScAttrArray* pAttrArray = pTab[nTab]->aCol[nOldCol].pAttrArray;
4586 			SCSIZE nIndex;
4587 			pAttrArray->Search( nOldRow, nIndex );
4588 			SCROW nAttrPos = nOldRow;
4589 			while (nAttrPos<=nEndRow)
4590 			{
4591 				DBG_ASSERT( nIndex < pAttrArray->nCount, "Falscher Index im AttrArray" );
4592 
4593 				if (((ScMergeFlagAttr&)pAttrArray->pData[nIndex].pPattern->
4594 						GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped())
4595 				{
4596 					SCROW nLoopEndRow = Min( nEndRow, pAttrArray->pData[nIndex].nRow );
4597 					for (SCROW nAttrRow = nAttrPos; nAttrRow <= nLoopEndRow; nAttrRow++)
4598 					{
4599 						SCCOL nTempCol = nOldCol;
4600 						do
4601 							--nTempCol;
4602 						while (((ScMergeFlagAttr*)GetAttr(nTempCol,nAttrRow,nTab,ATTR_MERGE_FLAG))
4603 								->IsHorOverlapped());
4604 						if (nTempCol < rStartCol)
4605 							rStartCol = nTempCol;
4606 					}
4607 				}
4608 				nAttrPos = pAttrArray->pData[nIndex].nRow + 1;
4609 				++nIndex;
4610 			}
4611 		}
4612 	}
4613 	else
4614 	{
4615 		DBG_ERROR("ExtendOverlapped: falscher Bereich");
4616 	}
4617 
4618 	return bFound;
4619 }
4620 
4621 
4622 sal_Bool ScDocument::ExtendMergeSel( SCCOL nStartCol, SCROW nStartRow,
4623                               SCCOL& rEndCol, SCROW& rEndRow,
4624                               const ScMarkData& rMark, sal_Bool bRefresh, sal_Bool bAttrs )
4625 {
4626     // use all selected sheets from rMark
4627 
4628     sal_Bool bFound = sal_False;
4629     SCCOL nOldEndCol = rEndCol;
4630     SCROW nOldEndRow = rEndRow;
4631 
4632     for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
4633         if ( pTab[nTab] && rMark.GetTableSelect(nTab) )
4634         {
4635             SCCOL nThisEndCol = nOldEndCol;
4636             SCROW nThisEndRow = nOldEndRow;
4637             if ( ExtendMerge( nStartCol, nStartRow, nThisEndCol, nThisEndRow, nTab, bRefresh, bAttrs ) )
4638                 bFound = sal_True;
4639             if ( nThisEndCol > rEndCol )
4640                 rEndCol = nThisEndCol;
4641             if ( nThisEndRow > rEndRow )
4642                 rEndRow = nThisEndRow;
4643         }
4644 
4645     return bFound;
4646 }
4647 
4648 
4649 sal_Bool ScDocument::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
4650 							  SCCOL& rEndCol,  SCROW& rEndRow,
4651 							  SCTAB nTab, sal_Bool bRefresh, sal_Bool bAttrs )
4652 {
4653 	sal_Bool bFound = sal_False;
4654 	if ( ValidColRow(nStartCol,nStartRow) && ValidColRow(rEndCol,rEndRow) && ValidTab(nTab) )
4655 	{
4656 		if (pTab[nTab])
4657 			bFound = pTab[nTab]->ExtendMerge( nStartCol, nStartRow, rEndCol, rEndRow, bRefresh, bAttrs );
4658 
4659 		if (bRefresh)
4660 			RefreshAutoFilter( nStartCol, nStartRow, rEndCol, rEndRow, nTab );
4661 	}
4662 	else
4663 	{
4664 		DBG_ERROR("ExtendMerge: falscher Bereich");
4665 	}
4666 
4667 	return bFound;
4668 }
4669 
4670 
4671 sal_Bool ScDocument::ExtendMerge( ScRange& rRange, sal_Bool bRefresh, sal_Bool bAttrs )
4672 {
4673 	sal_Bool bFound = sal_False;
4674 	SCTAB nStartTab = rRange.aStart.Tab();
4675 	SCTAB nEndTab   = rRange.aEnd.Tab();
4676 	SCCOL nEndCol   = rRange.aEnd.Col();
4677 	SCROW nEndRow   = rRange.aEnd.Row();
4678 
4679 	PutInOrder( nStartTab, nEndTab );
4680 	for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++ )
4681 	{
4682 		SCCOL nExtendCol = rRange.aEnd.Col();
4683 		SCROW nExtendRow = rRange.aEnd.Row();
4684 		if (ExtendMerge( rRange.aStart.Col(), rRange.aStart.Row(),
4685 						 nExtendCol,          nExtendRow,
4686 						 nTab, bRefresh, bAttrs ) )
4687 		{
4688 			bFound = sal_True;
4689 			if (nExtendCol > nEndCol) nEndCol = nExtendCol;
4690 			if (nExtendRow > nEndRow) nEndRow = nExtendRow;
4691 		}
4692 	}
4693 
4694 	rRange.aEnd.SetCol(nEndCol);
4695 	rRange.aEnd.SetRow(nEndRow);
4696 
4697 	return bFound;
4698 }
4699 
4700 sal_Bool ScDocument::ExtendTotalMerge( ScRange& rRange )
4701 {
4702 	//	Bereich genau dann auf zusammengefasste Zellen erweitern, wenn
4703 	//	dadurch keine neuen nicht-ueberdeckten Zellen getroffen werden
4704 
4705 	sal_Bool bRet = sal_False;
4706 	ScRange aExt = rRange;
4707 	if (ExtendMerge(aExt))
4708 	{
4709 		if ( aExt.aEnd.Row() > rRange.aEnd.Row() )
4710 		{
4711 			ScRange aTest = aExt;
4712 			aTest.aStart.SetRow( rRange.aEnd.Row() + 1 );
4713 			if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
4714 				aExt.aEnd.SetRow(rRange.aEnd.Row());
4715 		}
4716 		if ( aExt.aEnd.Col() > rRange.aEnd.Col() )
4717 		{
4718 			ScRange aTest = aExt;
4719 			aTest.aStart.SetCol( rRange.aEnd.Col() + 1 );
4720 			if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
4721 				aExt.aEnd.SetCol(rRange.aEnd.Col());
4722 		}
4723 
4724 		bRet = ( aExt.aEnd != rRange.aEnd );
4725 		rRange = aExt;
4726 	}
4727 	return bRet;
4728 }
4729 
4730 sal_Bool ScDocument::ExtendOverlapped( ScRange& rRange )
4731 {
4732 	sal_Bool bFound = sal_False;
4733 	SCTAB nStartTab = rRange.aStart.Tab();
4734 	SCTAB nEndTab   = rRange.aEnd.Tab();
4735 	SCCOL nStartCol = rRange.aStart.Col();
4736 	SCROW nStartRow = rRange.aStart.Row();
4737 
4738 	PutInOrder( nStartTab, nEndTab );
4739 	for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++ )
4740 	{
4741 		SCCOL nExtendCol = rRange.aStart.Col();
4742 		SCROW nExtendRow = rRange.aStart.Row();
4743 		ExtendOverlapped( nExtendCol, nExtendRow,
4744 								rRange.aEnd.Col(), rRange.aEnd.Row(), nTab );
4745 		if (nExtendCol < nStartCol)
4746 		{
4747 			nStartCol = nExtendCol;
4748 			bFound = sal_True;
4749 		}
4750 		if (nExtendRow < nStartRow)
4751 		{
4752 			nStartRow = nExtendRow;
4753 			bFound = sal_True;
4754 		}
4755 	}
4756 
4757 	rRange.aStart.SetCol(nStartCol);
4758 	rRange.aStart.SetRow(nStartRow);
4759 
4760 	return bFound;
4761 }
4762 
4763 sal_Bool ScDocument::RefreshAutoFilter( SCCOL nStartCol, SCROW nStartRow,
4764 									SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
4765 {
4766 	sal_uInt16 nCount = pDBCollection->GetCount();
4767 	sal_uInt16 i;
4768 	ScDBData* pData;
4769 	SCTAB nDBTab;
4770 	SCCOL nDBStartCol;
4771 	SCROW nDBStartRow;
4772 	SCCOL nDBEndCol;
4773 	SCROW nDBEndRow;
4774 
4775 	//		Autofilter loeschen
4776 
4777 	sal_Bool bChange = RemoveFlagsTab( nStartCol,nStartRow, nEndCol,nEndRow, nTab, SC_MF_AUTO );
4778 
4779 	//		Autofilter setzen
4780 
4781 	for (i=0; i<nCount; i++)
4782 	{
4783 		pData = (*pDBCollection)[i];
4784 		if (pData->HasAutoFilter())
4785 		{
4786 			pData->GetArea( nDBTab, nDBStartCol,nDBStartRow, nDBEndCol,nDBEndRow );
4787 			if ( nDBTab==nTab && nDBStartRow<=nEndRow && nDBEndRow>=nStartRow &&
4788 									nDBStartCol<=nEndCol && nDBEndCol>=nStartCol )
4789 			{
4790 				if (ApplyFlagsTab( nDBStartCol,nDBStartRow, nDBEndCol,nDBStartRow,
4791 									nDBTab, SC_MF_AUTO ))
4792 					bChange = sal_True;
4793 			}
4794 		}
4795 	}
4796 	return bChange;
4797 }
4798 
4799 
4800 sal_Bool ScDocument::IsHorOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4801 {
4802 	const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
4803 										GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
4804 	if (pAttr)
4805 		return pAttr->IsHorOverlapped();
4806 	else
4807 	{
4808 		DBG_ERROR("Overlapped: Attr==0");
4809 		return sal_False;
4810 	}
4811 }
4812 
4813 
4814 sal_Bool ScDocument::IsVerOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4815 {
4816 	const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
4817 										GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
4818 	if (pAttr)
4819 		return pAttr->IsVerOverlapped();
4820 	else
4821 	{
4822 		DBG_ERROR("Overlapped: Attr==0");
4823 		return sal_False;
4824 	}
4825 }
4826 
4827 
4828 void ScDocument::ApplySelectionFrame( const ScMarkData& rMark,
4829 									  const SvxBoxItem* pLineOuter,
4830 									  const SvxBoxInfoItem* pLineInner )
4831 {
4832 	ScRangeList aRangeList;
4833 	rMark.FillRangeListWithMarks( &aRangeList, sal_False );
4834 	sal_uLong nRangeCount = aRangeList.Count();
4835 	for (SCTAB i=0; i<=MAXTAB; i++)
4836 	{
4837 		if (pTab[i] && rMark.GetTableSelect(i))
4838 		{
4839 			for (sal_uLong j=0; j<nRangeCount; j++)
4840 			{
4841 				ScRange aRange = *aRangeList.GetObject(j);
4842 				pTab[i]->ApplyBlockFrame( pLineOuter, pLineInner,
4843 					aRange.aStart.Col(), aRange.aStart.Row(),
4844 					aRange.aEnd.Col(),   aRange.aEnd.Row() );
4845 			}
4846 		}
4847 	}
4848 }
4849 
4850 
4851 void ScDocument::ApplyFrameAreaTab( const ScRange& rRange,
4852 									const SvxBoxItem* pLineOuter,
4853 									const SvxBoxInfoItem* pLineInner )
4854 {
4855 	SCTAB nStartTab = rRange.aStart.Tab();
4856 	SCTAB nEndTab = rRange.aStart.Tab();
4857 	for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
4858 		if (pTab[nTab])
4859 			pTab[nTab]->ApplyBlockFrame( pLineOuter, pLineInner,
4860 										 rRange.aStart.Col(), rRange.aStart.Row(),
4861 										 rRange.aEnd.Col(),   rRange.aEnd.Row() );
4862 }
4863 
4864 
4865 void ScDocument::ApplySelectionPattern( const ScPatternAttr& rAttr, const ScMarkData& rMark )
4866 {
4867 	const SfxItemSet* pSet = &rAttr.GetItemSet();
4868 	sal_Bool bSet = sal_False;
4869 	sal_uInt16 i;
4870 	for (i=ATTR_PATTERN_START; i<=ATTR_PATTERN_END && !bSet; i++)
4871 		if (pSet->GetItemState(i) == SFX_ITEM_SET)
4872 			bSet = sal_True;
4873 
4874 	if (bSet)
4875 	{
4876 		// ApplySelectionCache needs multi mark
4877 		if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
4878 		{
4879 			ScRange aRange;
4880 			rMark.GetMarkArea( aRange );
4881 			ApplyPatternArea( aRange.aStart.Col(), aRange.aStart.Row(),
4882 							  aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rAttr );
4883 		}
4884 		else
4885 		{
4886 			SfxItemPoolCache aCache( xPoolHelper->GetDocPool(), pSet );
4887             for (SCTAB nTab=0; nTab<=MAXTAB; nTab++)
4888                 if (pTab[nTab])
4889                     if (rMark.GetTableSelect(nTab))
4890                         pTab[nTab]->ApplySelectionCache( &aCache, rMark );
4891 		}
4892 	}
4893 }
4894 
4895 
4896 void ScDocument::ChangeSelectionIndent( sal_Bool bIncrement, const ScMarkData& rMark )
4897 {
4898 	for (SCTAB i=0; i<=MAXTAB; i++)
4899 		if (pTab[i] && rMark.GetTableSelect(i))
4900 			pTab[i]->ChangeSelectionIndent( bIncrement, rMark );
4901 }
4902 
4903 
4904 void ScDocument::ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark )
4905 {
4906 	for (SCTAB i=0; i<=MAXTAB; i++)
4907 		if (pTab[i] && rMark.GetTableSelect(i))
4908 			pTab[i]->ClearSelectionItems( pWhich, rMark );
4909 }
4910 
4911 
4912 void ScDocument::DeleteSelection( sal_uInt16 nDelFlag, const ScMarkData& rMark )
4913 {
4914 	for (SCTAB i=0; i<=MAXTAB; i++)
4915 		if (pTab[i] && rMark.GetTableSelect(i))
4916             pTab[i]->DeleteSelection( nDelFlag, rMark );
4917 }
4918 
4919 
4920 void ScDocument::DeleteSelectionTab( SCTAB nTab, sal_uInt16 nDelFlag, const ScMarkData& rMark )
4921 {
4922 	if (ValidTab(nTab)  && pTab[nTab])
4923 		pTab[nTab]->DeleteSelection( nDelFlag, rMark );
4924 	else
4925 	{
4926 		DBG_ERROR("Falsche Tabelle");
4927 	}
4928 }
4929 
4930 
4931 ScPatternAttr* ScDocument::GetDefPattern() const
4932 {
4933 	return (ScPatternAttr*) &xPoolHelper->GetDocPool()->GetDefaultItem(ATTR_PATTERN);
4934 }
4935 
4936 
4937 ScDocumentPool* ScDocument::GetPool()
4938 {
4939 	return xPoolHelper->GetDocPool();
4940 }
4941 
4942 
4943 
4944 ScStyleSheetPool* ScDocument::GetStyleSheetPool() const
4945 {
4946 	return xPoolHelper->GetStylePool();
4947 }
4948 
4949 
4950 SCSIZE ScDocument::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
4951 							SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, ScDirection eDir )
4952 {
4953 	PutInOrder(nStartCol, nEndCol);
4954 	PutInOrder(nStartRow, nEndRow);
4955 	PutInOrder(nStartTab, nEndTab);
4956 	if (VALIDTAB(nStartTab))
4957 	{
4958 		if (pTab[nStartTab])
4959 			return pTab[nStartTab]->GetEmptyLinesInBlock(nStartCol, nStartRow, nEndCol, nEndRow, eDir);
4960 		else
4961 			return 0;
4962 	}
4963 	else
4964 		return 0;
4965 }
4966 
4967 
4968 void ScDocument::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY )
4969 {
4970 	if (ValidTab(nTab) && pTab[nTab])
4971 		pTab[nTab]->FindAreaPos( rCol, rRow, nMovX, nMovY );
4972 }
4973 
4974 
4975 void ScDocument::GetNextPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY,
4976 								sal_Bool bMarked, sal_Bool bUnprotected, const ScMarkData& rMark )
4977 {
4978 	DBG_ASSERT( !nMovX || !nMovY, "GetNextPos: nur X oder Y" );
4979 
4980 	ScMarkData aCopyMark = rMark;
4981 	aCopyMark.SetMarking(sal_False);
4982 	aCopyMark.MarkToMulti();
4983 
4984 	if (ValidTab(nTab) && pTab[nTab])
4985 		pTab[nTab]->GetNextPos( rCol, rRow, nMovX, nMovY, bMarked, bUnprotected, aCopyMark );
4986 }
4987 
4988 //
4989 //	Datei-Operationen
4990 //
4991 
4992 
4993 void ScDocument::UpdStlShtPtrsFrmNms()
4994 {
4995 	ScPatternAttr::pDoc = this;
4996 
4997 	ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4998 
4999 	sal_uInt32 nCount = pPool->GetItemCount2(ATTR_PATTERN);
5000 	ScPatternAttr* pPattern;
5001 	for (sal_uInt32 i=0; i<nCount; i++)
5002 	{
5003 		pPattern = (ScPatternAttr*)pPool->GetItem2(ATTR_PATTERN, i);
5004 		if (pPattern)
5005 			pPattern->UpdateStyleSheet();
5006 	}
5007 	((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).UpdateStyleSheet();
5008 }
5009 
5010 
5011 void ScDocument::StylesToNames()
5012 {
5013 	ScPatternAttr::pDoc = this;
5014 
5015 	ScDocumentPool* pPool = xPoolHelper->GetDocPool();
5016 
5017 	sal_uInt32 nCount = pPool->GetItemCount2(ATTR_PATTERN);
5018 	ScPatternAttr* pPattern;
5019 	for (sal_uInt32 i=0; i<nCount; i++)
5020 	{
5021 		pPattern = (ScPatternAttr*)pPool->GetItem2(ATTR_PATTERN, i);
5022 		if (pPattern)
5023 			pPattern->StyleToName();
5024 	}
5025 	((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).StyleToName();
5026 }
5027 
5028 
5029 sal_uLong ScDocument::GetCellCount() const
5030 {
5031 	sal_uLong nCellCount = 0L;
5032 
5033 	for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
5034 		if ( pTab[nTab] )
5035 			nCellCount += pTab[nTab]->GetCellCount();
5036 
5037 	return nCellCount;
5038 }
5039 
5040 SCSIZE ScDocument::GetCellCount(SCTAB nTab, SCCOL nCol) const
5041 {
5042     if (!ValidTab(nTab) || !pTab[nTab])
5043         return 0;
5044 
5045     return pTab[nTab]->GetCellCount(nCol);
5046 }
5047 
5048 sal_uLong ScDocument::GetCodeCount() const
5049 {
5050 	sal_uLong nCodeCount = 0;
5051 
5052 	for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
5053 		if ( pTab[nTab] )
5054 			nCodeCount += pTab[nTab]->GetCodeCount();
5055 
5056 	return nCodeCount;
5057 }
5058 
5059 
5060 sal_uLong ScDocument::GetWeightedCount() const
5061 {
5062 	sal_uLong nCellCount = 0L;
5063 
5064 	for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
5065 		if ( pTab[nTab] )
5066 			nCellCount += pTab[nTab]->GetWeightedCount();
5067 
5068 	return nCellCount;
5069 }
5070 
5071 
5072 void ScDocument::PageStyleModified( SCTAB nTab, const String& rNewName )
5073 {
5074 	if ( ValidTab(nTab)  && pTab[nTab] )
5075 		pTab[nTab]->PageStyleModified( rNewName );
5076 }
5077 
5078 
5079 void ScDocument::SetPageStyle( SCTAB nTab, const String& rName )
5080 {
5081 	if ( ValidTab(nTab)  && pTab[nTab] )
5082 		pTab[nTab]->SetPageStyle( rName );
5083 }
5084 
5085 
5086 const String& ScDocument::GetPageStyle( SCTAB nTab ) const
5087 {
5088 	if ( ValidTab(nTab)  && pTab[nTab] )
5089 		return pTab[nTab]->GetPageStyle();
5090 
5091 	return EMPTY_STRING;
5092 }
5093 
5094 
5095 void ScDocument::SetPageSize( SCTAB nTab, const Size& rSize )
5096 {
5097 	if ( ValidTab(nTab)  && pTab[nTab] )
5098 		pTab[nTab]->SetPageSize( rSize );
5099 }
5100 
5101 Size ScDocument::GetPageSize( SCTAB nTab ) const
5102 {
5103 	if ( ValidTab(nTab)  && pTab[nTab] )
5104 		return pTab[nTab]->GetPageSize();
5105 
5106 	DBG_ERROR("falsche Tab");
5107 	return Size();
5108 }
5109 
5110 
5111 void ScDocument::SetRepeatArea( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow )
5112 {
5113 	if ( ValidTab(nTab)  && pTab[nTab] )
5114 		pTab[nTab]->SetRepeatArea( nStartCol, nEndCol, nStartRow, nEndRow );
5115 }
5116 
5117 void ScDocument::InvalidatePageBreaks(SCTAB nTab)
5118 {
5119     if (ValidTab(nTab) && pTab[nTab])
5120         pTab[nTab]->InvalidatePageBreaks();
5121 }
5122 
5123 void ScDocument::UpdatePageBreaks( SCTAB nTab, const ScRange* pUserArea )
5124 {
5125 	if ( ValidTab(nTab)  && pTab[nTab] )
5126 		pTab[nTab]->UpdatePageBreaks( pUserArea );
5127 }
5128 
5129 void ScDocument::RemoveManualBreaks( SCTAB nTab )
5130 {
5131 	if ( ValidTab(nTab)  && pTab[nTab] )
5132 		pTab[nTab]->RemoveManualBreaks();
5133 }
5134 
5135 sal_Bool ScDocument::HasManualBreaks( SCTAB nTab ) const
5136 {
5137 	if ( ValidTab(nTab)  && pTab[nTab] )
5138 		return pTab[nTab]->HasManualBreaks();
5139 
5140 	DBG_ERROR("falsche Tab");
5141 	return sal_False;
5142 }
5143 
5144 
5145 void ScDocument::GetDocStat( ScDocStat& rDocStat )
5146 {
5147 	rDocStat.nTableCount = GetTableCount();
5148 	rDocStat.aDocName	 = aDocName;
5149 	rDocStat.nCellCount	 = GetCellCount();
5150 }
5151 
5152 
5153 sal_Bool ScDocument::HasPrintRange()
5154 {
5155 	sal_Bool bResult = sal_False;
5156 
5157 	for ( SCTAB i=0; !bResult && i<nMaxTableNumber; i++ )
5158 		if ( pTab[i] )
5159             bResult = pTab[i]->IsPrintEntireSheet() || (pTab[i]->GetPrintRangeCount() > 0);
5160 
5161 	return bResult;
5162 }
5163 
5164 
5165 sal_Bool ScDocument::IsPrintEntireSheet( SCTAB nTab ) const
5166 {
5167     return (ValidTab(nTab) ) && pTab[nTab] && pTab[nTab]->IsPrintEntireSheet();
5168 }
5169 
5170 
5171 sal_uInt16 ScDocument::GetPrintRangeCount( SCTAB nTab )
5172 {
5173 	if (ValidTab(nTab) && pTab[nTab])
5174 		return pTab[nTab]->GetPrintRangeCount();
5175 
5176 	return 0;
5177 }
5178 
5179 
5180 const ScRange* ScDocument::GetPrintRange( SCTAB nTab, sal_uInt16 nPos )
5181 {
5182 	if (ValidTab(nTab) && pTab[nTab])
5183 		return pTab[nTab]->GetPrintRange(nPos);
5184 
5185 	return NULL;
5186 }
5187 
5188 
5189 const ScRange* ScDocument::GetRepeatColRange( SCTAB nTab )
5190 {
5191 	if (ValidTab(nTab) && pTab[nTab])
5192 		return pTab[nTab]->GetRepeatColRange();
5193 
5194 	return NULL;
5195 }
5196 
5197 
5198 const ScRange* ScDocument::GetRepeatRowRange( SCTAB nTab )
5199 {
5200 	if (ValidTab(nTab) && pTab[nTab])
5201 		return pTab[nTab]->GetRepeatRowRange();
5202 
5203 	return NULL;
5204 }
5205 
5206 
5207 void ScDocument::ClearPrintRanges( SCTAB nTab )
5208 {
5209     if (ValidTab(nTab) && pTab[nTab])
5210         pTab[nTab]->ClearPrintRanges();
5211 }
5212 
5213 
5214 void ScDocument::AddPrintRange( SCTAB nTab, const ScRange& rNew )
5215 {
5216 	if (ValidTab(nTab) && pTab[nTab])
5217         pTab[nTab]->AddPrintRange( rNew );
5218 }
5219 
5220 
5221 //UNUSED2009-05 void ScDocument::SetPrintRange( SCTAB nTab, const ScRange& rNew )
5222 //UNUSED2009-05 {
5223 //UNUSED2009-05     if (ValidTab(nTab) && pTab[nTab])
5224 //UNUSED2009-05         pTab[nTab]->SetPrintRange( rNew );
5225 //UNUSED2009-05 }
5226 
5227 
5228 void ScDocument::SetPrintEntireSheet( SCTAB nTab )
5229 {
5230     if (ValidTab(nTab) && pTab[nTab])
5231         pTab[nTab]->SetPrintEntireSheet();
5232 }
5233 
5234 
5235 void ScDocument::SetRepeatColRange( SCTAB nTab, const ScRange* pNew )
5236 {
5237 	if (ValidTab(nTab) && pTab[nTab])
5238 		pTab[nTab]->SetRepeatColRange( pNew );
5239 }
5240 
5241 
5242 void ScDocument::SetRepeatRowRange( SCTAB nTab, const ScRange* pNew )
5243 {
5244 	if (ValidTab(nTab) && pTab[nTab])
5245 		pTab[nTab]->SetRepeatRowRange( pNew );
5246 }
5247 
5248 
5249 ScPrintRangeSaver* ScDocument::CreatePrintRangeSaver() const
5250 {
5251 	SCTAB nCount = GetTableCount();
5252 	ScPrintRangeSaver* pNew = new ScPrintRangeSaver( nCount );
5253 	for (SCTAB i=0; i<nCount; i++)
5254 		if (pTab[i])
5255 			pTab[i]->FillPrintSaver( pNew->GetTabData(i) );
5256 	return pNew;
5257 }
5258 
5259 
5260 void ScDocument::RestorePrintRanges( const ScPrintRangeSaver& rSaver )
5261 {
5262 	SCTAB nCount = rSaver.GetTabCount();
5263 	for (SCTAB i=0; i<nCount; i++)
5264 		if (pTab[i])
5265 			pTab[i]->RestorePrintRanges( rSaver.GetTabData(i) );
5266 }
5267 
5268 
5269 sal_Bool ScDocument::NeedPageResetAfterTab( SCTAB nTab ) const
5270 {
5271     //  Die Seitennummern-Zaehlung faengt bei einer Tabelle neu an, wenn eine
5272 	//	andere Vorlage als bei der vorherigen gesetzt ist (nur Namen vergleichen)
5273 	//	und eine Seitennummer angegeben ist (nicht 0)
5274 
5275 	if ( nTab < MAXTAB && pTab[nTab] && pTab[nTab+1] )
5276 	{
5277 		String aNew = pTab[nTab+1]->GetPageStyle();
5278 		if ( aNew != pTab[nTab]->GetPageStyle() )
5279 		{
5280 			SfxStyleSheetBase* pStyle = xPoolHelper->GetStylePool()->Find( aNew, SFX_STYLE_FAMILY_PAGE );
5281 			if ( pStyle )
5282 			{
5283 				const SfxItemSet& rSet = pStyle->GetItemSet();
5284 				sal_uInt16 nFirst = ((const SfxUInt16Item&)rSet.Get(ATTR_PAGE_FIRSTPAGENO)).GetValue();
5285 				if ( nFirst != 0 )
5286 					return sal_True;		// Seitennummer in neuer Vorlage angegeben
5287 			}
5288 		}
5289 	}
5290 
5291 	return sal_False;		// sonst nicht
5292 }
5293 
5294 SfxUndoManager* ScDocument::GetUndoManager()
5295 {
5296 	if (!mpUndoManager)
5297 		mpUndoManager = new SfxUndoManager;
5298 	return mpUndoManager;
5299 }
5300 
5301 ScRowBreakIterator* ScDocument::GetRowBreakIterator(SCTAB nTab) const
5302 {
5303     if (ValidTab(nTab) && pTab[nTab])
5304         return new ScRowBreakIterator(pTab[nTab]->maRowPageBreaks);
5305     return NULL;
5306 }
5307 
5308 void ScDocument::EnableUndo( bool bVal )
5309 {
5310 	GetUndoManager()->EnableUndo(bVal);
5311 	if( pDrawLayer ) pDrawLayer->EnableUndo(bVal);
5312 	mbUndoEnabled = bVal;
5313 }
5314 
5315 bool ScDocument::IsInVBAMode() const
5316 {
5317     bool bResult = false;
5318     if ( pShell )
5319     {
5320         com::sun::star::uno::Reference< com::sun::star::script::vba::XVBACompatibility > xVBA( pShell->GetBasicContainer(), com::sun::star::uno::UNO_QUERY );
5321         bResult = xVBA.is() && xVBA->getVBACompatibilityMode();
5322     }
5323     return bResult;
5324 }
5325