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