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