xref: /trunk/main/sc/source/core/data/document.cxx (revision b4df81e3)
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::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
3945 		const ScMarkData& rMark, const ScPatternAttr& rPattern, short nNewType )
3946 {
3947 	for (SCTAB i=0; i <= MAXTAB; i++)
3948 		if (pTab[i])
3949 			if (rMark.GetTableSelect(i))
3950 				pTab[i]->ApplyPatternIfNumberformatIncompatible( rRange, rPattern, nNewType );
3951 }
3952 
3953 
3954 void ScDocument::ApplyStyle( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScStyleSheet& rStyle)
3955 {
3956 	if (VALIDTAB(nTab))
3957 		if (pTab[nTab])
3958 			pTab[nTab]->ApplyStyle( nCol, nRow, rStyle );
3959 }
3960 
3961 
3962 void ScDocument::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow,
3963 						SCCOL nEndCol, SCROW nEndRow,
3964 						const ScMarkData& rMark,
3965 						const ScStyleSheet& rStyle)
3966 {
3967 	for (SCTAB i=0; i <= MAXTAB; i++)
3968 		if (pTab[i])
3969 			if (rMark.GetTableSelect(i))
3970 				pTab[i]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
3971 }
3972 
3973 
3974 void ScDocument::ApplyStyleAreaTab( SCCOL nStartCol, SCROW nStartRow,
3975 						SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScStyleSheet& rStyle)
3976 {
3977 	if (VALIDTAB(nTab))
3978 		if (pTab[nTab])
3979 			pTab[nTab]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
3980 }
3981 
3982 
3983 void ScDocument::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
3984 {
3985 	// ApplySelectionStyle needs multi mark
3986 	if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
3987 	{
3988 		ScRange aRange;
3989 		rMark.GetMarkArea( aRange );
3990 		ApplyStyleArea( aRange.aStart.Col(), aRange.aStart.Row(),
3991 						  aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rStyle );
3992 	}
3993 	else
3994 	{
3995 		for (SCTAB i=0; i<=MAXTAB; i++)
3996 			if ( pTab[i] && rMark.GetTableSelect(i) )
3997 					pTab[i]->ApplySelectionStyle( rStyle, rMark );
3998 	}
3999 }
4000 
4001 
4002 void ScDocument::ApplySelectionLineStyle( const ScMarkData& rMark,
4003 					const SvxBorderLine* pLine, sal_Bool bColorOnly )
4004 {
4005 	if ( bColorOnly && !pLine )
4006 		return;
4007 
4008 	for (SCTAB i=0; i<=MAXTAB; i++)
4009 		if (pTab[i])
4010 			if (rMark.GetTableSelect(i))
4011 				pTab[i]->ApplySelectionLineStyle( rMark, pLine, bColorOnly );
4012 }
4013 
4014 
4015 const ScStyleSheet*	ScDocument::GetStyle( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4016 {
4017 	if ( VALIDTAB(nTab) && pTab[nTab] )
4018 		return pTab[nTab]->GetStyle(nCol, nRow);
4019 	else
4020 		return NULL;
4021 }
4022 
4023 
4024 const ScStyleSheet*	ScDocument::GetSelectionStyle( const ScMarkData& rMark ) const
4025 {
4026 	sal_Bool	bEqual = sal_True;
4027 	sal_Bool	bFound;
4028 
4029 	const ScStyleSheet* pStyle = NULL;
4030 	const ScStyleSheet* pNewStyle;
4031 
4032 	if ( rMark.IsMultiMarked() )
4033 		for (SCTAB i=0; i<=MAXTAB && bEqual; i++)
4034 			if (pTab[i] && rMark.GetTableSelect(i))
4035 			{
4036 				pNewStyle = pTab[i]->GetSelectionStyle( rMark, bFound );
4037 				if (bFound)
4038 				{
4039 					if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
4040 						bEqual = sal_False;												// unterschiedliche
4041 					pStyle = pNewStyle;
4042 				}
4043 			}
4044 	if ( rMark.IsMarked() )
4045 	{
4046 		ScRange aRange;
4047 		rMark.GetMarkArea( aRange );
4048 		for (SCTAB i=aRange.aStart.Tab(); i<=aRange.aEnd.Tab() && bEqual; i++)
4049 			if (pTab[i] && rMark.GetTableSelect(i))
4050 			{
4051 				pNewStyle = pTab[i]->GetAreaStyle( bFound,
4052 										aRange.aStart.Col(), aRange.aStart.Row(),
4053 										aRange.aEnd.Col(),   aRange.aEnd.Row()   );
4054 				if (bFound)
4055 				{
4056 					if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
4057 						bEqual = sal_False;												// unterschiedliche
4058 					pStyle = pNewStyle;
4059 				}
4060 			}
4061 	}
4062 
4063 	return bEqual ? pStyle : NULL;
4064 }
4065 
4066 
4067 void ScDocument::StyleSheetChanged( const SfxStyleSheetBase* pStyleSheet, sal_Bool bRemoved,
4068 									OutputDevice* pDev,
4069 									double nPPTX, double nPPTY,
4070 									const Fraction& rZoomX, const Fraction& rZoomY )
4071 {
4072 	for (SCTAB i=0; i <= MAXTAB; i++)
4073 		if (pTab[i])
4074 			pTab[i]->StyleSheetChanged
4075 				( pStyleSheet, bRemoved, pDev, nPPTX, nPPTY, rZoomX, rZoomY );
4076 
4077 	if ( pStyleSheet && pStyleSheet->GetName() == ScGlobal::GetRscString(STR_STYLENAME_STANDARD) )
4078 	{
4079 		//	update attributes for all note objects
4080         ScDetectiveFunc::UpdateAllComments( *this );
4081 	}
4082 }
4083 
4084 
4085 sal_Bool ScDocument::IsStyleSheetUsed( const ScStyleSheet& rStyle, sal_Bool bGatherAllStyles ) const
4086 {
4087     if ( bStyleSheetUsageInvalid || rStyle.GetUsage() == ScStyleSheet::UNKNOWN )
4088     {
4089         if ( bGatherAllStyles )
4090         {
4091             SfxStyleSheetIterator aIter( xPoolHelper->GetStylePool(),
4092                     SFX_STYLE_FAMILY_PARA );
4093             for ( const SfxStyleSheetBase* pStyle = aIter.First(); pStyle;
4094                                            pStyle = aIter.Next() )
4095             {
4096                 const ScStyleSheet* pScStyle = PTR_CAST( ScStyleSheet, pStyle );
4097                 if ( pScStyle )
4098                     pScStyle->SetUsage( ScStyleSheet::NOTUSED );
4099             }
4100         }
4101 
4102         sal_Bool bIsUsed = sal_False;
4103 
4104         for ( SCTAB i=0; i<=MAXTAB; i++ )
4105         {
4106             if ( pTab[i] )
4107             {
4108                 if ( pTab[i]->IsStyleSheetUsed( rStyle, bGatherAllStyles ) )
4109                 {
4110                     if ( !bGatherAllStyles )
4111                         return sal_True;
4112                     bIsUsed = sal_True;
4113                 }
4114             }
4115         }
4116 
4117         if ( bGatherAllStyles )
4118             bStyleSheetUsageInvalid = sal_False;
4119 
4120         return bIsUsed;
4121     }
4122 
4123     return rStyle.GetUsage() == ScStyleSheet::USED;
4124 }
4125 
4126 
4127 sal_Bool ScDocument::ApplyFlagsTab( SCCOL nStartCol, SCROW nStartRow,
4128 						SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, sal_Int16 nFlags )
4129 {
4130 	if (VALIDTAB(nTab))
4131 		if (pTab[nTab])
4132 			return pTab[nTab]->ApplyFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
4133 
4134 	DBG_ERROR("ApplyFlags: falsche Tabelle");
4135 	return sal_False;
4136 }
4137 
4138 
4139 sal_Bool ScDocument::RemoveFlagsTab( SCCOL nStartCol, SCROW nStartRow,
4140 						SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, sal_Int16 nFlags )
4141 {
4142 	if (VALIDTAB(nTab))
4143 		if (pTab[nTab])
4144 			return pTab[nTab]->RemoveFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
4145 
4146 	DBG_ERROR("RemoveFlags: falsche Tabelle");
4147 	return sal_False;
4148 }
4149 
4150 
4151 void ScDocument::SetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr,
4152 								sal_Bool bPutToPool )
4153 {
4154 	if (VALIDTAB(nTab))
4155 		if (pTab[nTab])
4156 			pTab[nTab]->SetPattern( nCol, nRow, rAttr, bPutToPool );
4157 }
4158 
4159 
4160 void ScDocument::SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr,
4161 								sal_Bool bPutToPool )
4162 {
4163 	SCTAB nTab = rPos.Tab();
4164 	if (pTab[nTab])
4165 		pTab[nTab]->SetPattern( rPos, rAttr, bPutToPool );
4166 }
4167 
4168 
4169 ScPatternAttr* ScDocument::CreateSelectionPattern( const ScMarkData& rMark, sal_Bool bDeep )
4170 {
4171     ScMergePatternState aState;
4172 
4173 	if ( rMark.IsMultiMarked() )								// multi selection
4174 	{
4175 		for (SCTAB i=0; i<=MAXTAB; i++)
4176 			if (pTab[i] && rMark.GetTableSelect(i))
4177 				pTab[i]->MergeSelectionPattern( aState, rMark, bDeep );
4178 	}
4179 	if ( rMark.IsMarked() )										// simle selection
4180 	{
4181 		ScRange aRange;
4182 		rMark.GetMarkArea(aRange);
4183 		for (SCTAB i=0; i<=MAXTAB; i++)
4184 			if (pTab[i] && rMark.GetTableSelect(i))
4185 				pTab[i]->MergePatternArea( aState,
4186 								aRange.aStart.Col(), aRange.aStart.Row(),
4187 								aRange.aEnd.Col(), aRange.aEnd.Row(), bDeep );
4188 	}
4189 
4190 	DBG_ASSERT( aState.pItemSet, "SelectionPattern Null" );
4191 	if (aState.pItemSet)
4192 		return new ScPatternAttr( aState.pItemSet );
4193 	else
4194 		return new ScPatternAttr( GetPool() );		// empty
4195 }
4196 
4197 
4198 const ScPatternAttr* ScDocument::GetSelectionPattern( const ScMarkData& rMark, sal_Bool bDeep )
4199 {
4200 	delete pSelectionAttr;
4201 	pSelectionAttr = CreateSelectionPattern( rMark, bDeep );
4202 	return pSelectionAttr;
4203 }
4204 
4205 
4206 void ScDocument::GetSelectionFrame( const ScMarkData& rMark,
4207 									SvxBoxItem&		rLineOuter,
4208 									SvxBoxInfoItem&	rLineInner )
4209 {
4210 	rLineOuter.SetLine(NULL, BOX_LINE_TOP);
4211 	rLineOuter.SetLine(NULL, BOX_LINE_BOTTOM);
4212 	rLineOuter.SetLine(NULL, BOX_LINE_LEFT);
4213 	rLineOuter.SetLine(NULL, BOX_LINE_RIGHT);
4214 	rLineOuter.SetDistance(0);
4215 
4216 	rLineInner.SetLine(NULL, BOXINFO_LINE_HORI);
4217 	rLineInner.SetLine(NULL, BOXINFO_LINE_VERT);
4218 	rLineInner.SetTable(sal_True);
4219     rLineInner.SetDist(sal_True);
4220     rLineInner.SetMinDist(sal_False);
4221 
4222 	ScLineFlags aFlags;
4223 
4224 	if (rMark.IsMarked())
4225 	{
4226 		ScRange aRange;
4227 		rMark.GetMarkArea(aRange);
4228         rLineInner.EnableHor( aRange.aStart.Row() != aRange.aEnd.Row() );
4229         rLineInner.EnableVer( aRange.aStart.Col() != aRange.aEnd.Col() );
4230 		for (SCTAB i=0; i<=MAXTAB; i++)
4231 			if (pTab[i] && rMark.GetTableSelect(i))
4232 				pTab[i]->MergeBlockFrame( &rLineOuter, &rLineInner, aFlags,
4233 										  aRange.aStart.Col(), aRange.aStart.Row(),
4234 										  aRange.aEnd.Col(),   aRange.aEnd.Row() );
4235 	}
4236 
4237 		//	Don't care Status auswerten
4238 
4239 	rLineInner.SetValid( VALID_LEFT,   ( aFlags.nLeft != SC_LINE_DONTCARE ) );
4240 	rLineInner.SetValid( VALID_RIGHT,  ( aFlags.nRight != SC_LINE_DONTCARE ) );
4241 	rLineInner.SetValid( VALID_TOP,    ( aFlags.nTop != SC_LINE_DONTCARE ) );
4242 	rLineInner.SetValid( VALID_BOTTOM, ( aFlags.nBottom != SC_LINE_DONTCARE ) );
4243 	rLineInner.SetValid( VALID_HORI,   ( aFlags.nHori != SC_LINE_DONTCARE ) );
4244 	rLineInner.SetValid( VALID_VERT,   ( aFlags.nVert != SC_LINE_DONTCARE ) );
4245 }
4246 
4247 
4248 bool ScDocument::HasAttrib( SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
4249                             SCCOL nCol2, SCROW nRow2, SCTAB nTab2, sal_uInt16 nMask )
4250 {
4251     if ( nMask & HASATTR_ROTATE )
4252     {
4253         //  Attribut im Dokument ueberhaupt verwendet?
4254         //  (wie in fillinfo)
4255 
4256         ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4257 
4258         sal_Bool bAnyItem = sal_False;
4259         sal_uInt32 nRotCount = pPool->GetItemCount2( ATTR_ROTATE_VALUE );
4260         for (sal_uInt32 nItem=0; nItem<nRotCount; nItem++)
4261         {
4262             const SfxPoolItem* pItem = pPool->GetItem2( ATTR_ROTATE_VALUE, nItem );
4263             if ( pItem )
4264             {
4265                 // 90 or 270 degrees is former SvxOrientationItem - only look for other values
4266                 // (see ScPatternAttr::GetCellOrientation)
4267                 sal_Int32 nAngle = static_cast<const SfxInt32Item*>(pItem)->GetValue();
4268                 if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
4269                 {
4270                     bAnyItem = sal_True;
4271                     break;
4272                 }
4273             }
4274         }
4275         if (!bAnyItem)
4276             nMask &= ~HASATTR_ROTATE;
4277     }
4278 
4279     if ( nMask & HASATTR_RTL )
4280     {
4281         //  first check if right-to left is in the pool at all
4282         //  (the same item is used in cell and page format)
4283 
4284         ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4285 
4286         sal_Bool bHasRtl = sal_False;
4287         sal_uInt32 nDirCount = pPool->GetItemCount2( ATTR_WRITINGDIR );
4288         for (sal_uInt32 nItem=0; nItem<nDirCount; nItem++)
4289         {
4290             const SfxPoolItem* pItem = pPool->GetItem2( ATTR_WRITINGDIR, nItem );
4291             if ( pItem && ((const SvxFrameDirectionItem*)pItem)->GetValue() == FRMDIR_HORI_RIGHT_TOP )
4292             {
4293                 bHasRtl = sal_True;
4294                 break;
4295             }
4296         }
4297         if (!bHasRtl)
4298             nMask &= ~HASATTR_RTL;
4299     }
4300 
4301     if (!nMask)
4302         return false;
4303 
4304     bool bFound = false;
4305     for (SCTAB i=nTab1; i<=nTab2 && !bFound; i++)
4306         if (pTab[i])
4307         {
4308             if ( nMask & HASATTR_RTL )
4309             {
4310                 if ( GetEditTextDirection(i) == EE_HTEXTDIR_R2L )       // sheet default
4311                     bFound = true;
4312             }
4313             if ( nMask & HASATTR_RIGHTORCENTER )
4314             {
4315                 //  On a RTL sheet, don't start to look for the default left value
4316                 //  (which is then logically right), instead always assume sal_True.
4317                 //  That way, ScAttrArray::HasAttrib doesn't have to handle RTL sheets.
4318 
4319                 if ( IsLayoutRTL(i) )
4320                     bFound = true;
4321             }
4322 
4323             if ( !bFound )
4324                 bFound = pTab[i]->HasAttrib( nCol1, nRow1, nCol2, nRow2, nMask );
4325         }
4326 
4327     return bFound;
4328 }
4329 
4330 bool ScDocument::HasAttrib( const ScRange& rRange, sal_uInt16 nMask )
4331 {
4332     return HasAttrib( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
4333                       rRange.aEnd.Col(),   rRange.aEnd.Row(),   rRange.aEnd.Tab(),
4334                       nMask );
4335 }
4336 
4337 void ScDocument::FindMaxRotCol( SCTAB nTab, RowInfo* pRowInfo, SCSIZE nArrCount,
4338 								SCCOL nX1, SCCOL nX2 ) const
4339 {
4340 	if ( ValidTab(nTab)  && pTab[nTab] )
4341 		pTab[nTab]->FindMaxRotCol( pRowInfo, nArrCount, nX1, nX2 );
4342 	else
4343 	{
4344 		DBG_ERRORFILE("FindMaxRotCol: falsche Tabelle");
4345 	}
4346 }
4347 
4348 void ScDocument::GetBorderLines( SCCOL nCol, SCROW nRow, SCTAB nTab,
4349 						const SvxBorderLine** ppLeft, const SvxBorderLine** ppTop,
4350 						const SvxBorderLine** ppRight, const SvxBorderLine** ppBottom ) const
4351 {
4352 	//!	Seitengrenzen fuer Druck beruecksichtigen !!!!!
4353 
4354 	const SvxBoxItem* pThisAttr = (const SvxBoxItem*) GetEffItem( nCol, nRow, nTab, ATTR_BORDER );
4355 	DBG_ASSERT(pThisAttr,"wo ist das Attribut?");
4356 
4357 	const SvxBorderLine* pLeftLine   = pThisAttr->GetLeft();
4358 	const SvxBorderLine* pTopLine    = pThisAttr->GetTop();
4359 	const SvxBorderLine* pRightLine  = pThisAttr->GetRight();
4360 	const SvxBorderLine* pBottomLine = pThisAttr->GetBottom();
4361 
4362 	if ( nCol > 0 )
4363 	{
4364 		const SvxBorderLine* pOther = ((const SvxBoxItem*)
4365 								GetEffItem( nCol-1, nRow, nTab, ATTR_BORDER ))->GetRight();
4366 		if ( ScHasPriority( pOther, pLeftLine ) )
4367 			pLeftLine = pOther;
4368 	}
4369 	if ( nRow > 0 )
4370 	{
4371 		const SvxBorderLine* pOther = ((const SvxBoxItem*)
4372 								GetEffItem( nCol, nRow-1, nTab, ATTR_BORDER ))->GetBottom();
4373 		if ( ScHasPriority( pOther, pTopLine ) )
4374 			pTopLine = pOther;
4375 	}
4376 	if ( nCol < MAXCOL )
4377 	{
4378 		const SvxBorderLine* pOther = ((const SvxBoxItem*)
4379 								GetEffItem( nCol+1, nRow, nTab, ATTR_BORDER ))->GetLeft();
4380 		if ( ScHasPriority( pOther, pRightLine ) )
4381 			pRightLine = pOther;
4382 	}
4383 	if ( nRow < MAXROW )
4384 	{
4385 		const SvxBorderLine* pOther = ((const SvxBoxItem*)
4386 								GetEffItem( nCol, nRow+1, nTab, ATTR_BORDER ))->GetTop();
4387 		if ( ScHasPriority( pOther, pBottomLine ) )
4388 			pBottomLine = pOther;
4389 	}
4390 
4391 	if (ppLeft)
4392 		*ppLeft = pLeftLine;
4393 	if (ppTop)
4394 		*ppTop = pTopLine;
4395 	if (ppRight)
4396 		*ppRight = pRightLine;
4397 	if (ppBottom)
4398 		*ppBottom = pBottomLine;
4399 }
4400 
4401 sal_Bool ScDocument::IsBlockEmpty( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
4402 										SCCOL nEndCol, SCROW nEndRow, bool bIgnoreNotes ) const
4403 {
4404 	if (VALIDTAB(nTab))
4405 		if (pTab[nTab])
4406 			return pTab[nTab]->IsBlockEmpty( nStartCol, nStartRow, nEndCol, nEndRow, bIgnoreNotes );
4407 
4408 	DBG_ERROR("Falsche Tabellennummer");
4409 	return sal_False;
4410 }
4411 
4412 
4413 void ScDocument::LockTable(SCTAB nTab)
4414 {
4415 	if ( ValidTab(nTab)  && pTab[nTab] )
4416 		pTab[nTab]->LockTable();
4417 	else
4418 	{
4419 		DBG_ERROR("Falsche Tabellennummer");
4420 	}
4421 }
4422 
4423 
4424 void ScDocument::UnlockTable(SCTAB nTab)
4425 {
4426 	if ( ValidTab(nTab)  && pTab[nTab] )
4427 		pTab[nTab]->UnlockTable();
4428 	else
4429 	{
4430 		DBG_ERROR("Falsche Tabellennummer");
4431 	}
4432 }
4433 
4434 
4435 sal_Bool ScDocument::IsBlockEditable( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
4436 										SCCOL nEndCol, SCROW nEndRow,
4437 										sal_Bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
4438 {
4439     // import into read-only document is possible
4440     if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
4441 	{
4442 		if ( pOnlyNotBecauseOfMatrix )
4443 			*pOnlyNotBecauseOfMatrix = sal_False;
4444 		return sal_False;
4445 	}
4446 
4447 	if (VALIDTAB(nTab))
4448 		if (pTab[nTab])
4449 			return pTab[nTab]->IsBlockEditable( nStartCol, nStartRow, nEndCol,
4450 				nEndRow, pOnlyNotBecauseOfMatrix );
4451 
4452 	DBG_ERROR("Falsche Tabellennummer");
4453 	if ( pOnlyNotBecauseOfMatrix )
4454 		*pOnlyNotBecauseOfMatrix = sal_False;
4455 	return sal_False;
4456 }
4457 
4458 
4459 sal_Bool ScDocument::IsSelectionEditable( const ScMarkData& rMark,
4460 			sal_Bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
4461 {
4462     // import into read-only document is possible
4463     if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
4464 	{
4465 		if ( pOnlyNotBecauseOfMatrix )
4466 			*pOnlyNotBecauseOfMatrix = sal_False;
4467 		return sal_False;
4468 	}
4469 
4470 	ScRange aRange;
4471 	rMark.GetMarkArea(aRange);
4472 
4473 	sal_Bool bOk = sal_True;
4474 	sal_Bool bMatrix = ( pOnlyNotBecauseOfMatrix != NULL );
4475 	for ( SCTAB i=0; i<=MAXTAB && (bOk || bMatrix); i++ )
4476 	{
4477 		if ( pTab[i] && rMark.GetTableSelect(i) )
4478 		{
4479 			if (rMark.IsMarked())
4480 			{
4481 				if ( !pTab[i]->IsBlockEditable( aRange.aStart.Col(),
4482 						aRange.aStart.Row(), aRange.aEnd.Col(),
4483 						aRange.aEnd.Row(), pOnlyNotBecauseOfMatrix ) )
4484 				{
4485 					bOk = sal_False;
4486 					if ( pOnlyNotBecauseOfMatrix )
4487 						bMatrix = *pOnlyNotBecauseOfMatrix;
4488 				}
4489 			}
4490 			if (rMark.IsMultiMarked())
4491 			{
4492 				if ( !pTab[i]->IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix ) )
4493 				{
4494 					bOk = sal_False;
4495 					if ( pOnlyNotBecauseOfMatrix )
4496 						bMatrix = *pOnlyNotBecauseOfMatrix;
4497 				}
4498 			}
4499 		}
4500 	}
4501 
4502 	if ( pOnlyNotBecauseOfMatrix )
4503 		*pOnlyNotBecauseOfMatrix = ( !bOk && bMatrix );
4504 
4505 	return bOk;
4506 }
4507 
4508 
4509 sal_Bool ScDocument::HasSelectedBlockMatrixFragment( SCCOL nStartCol, SCROW nStartRow,
4510 								SCCOL nEndCol, SCROW nEndRow,
4511 								const ScMarkData& rMark ) const
4512 {
4513 	sal_Bool bOk = sal_True;
4514 	for (SCTAB i=0; i<=MAXTAB && bOk; i++)
4515 		if (pTab[i])
4516 			if (rMark.GetTableSelect(i))
4517 				if (pTab[i]->HasBlockMatrixFragment( nStartCol, nStartRow, nEndCol, nEndRow ))
4518 					bOk = sal_False;
4519 
4520 	return !bOk;
4521 }
4522 
4523 
4524 sal_Bool ScDocument::GetMatrixFormulaRange( const ScAddress& rCellPos, ScRange& rMatrix )
4525 {
4526 	//	if rCell is part of a matrix formula, return its complete range
4527 
4528 	sal_Bool bRet = sal_False;
4529 	ScBaseCell* pCell = GetCell( rCellPos );
4530 	if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
4531 	{
4532 		ScAddress aOrigin = rCellPos;
4533 		if ( ((ScFormulaCell*)pCell)->GetMatrixOrigin( aOrigin ) )
4534 		{
4535 			if ( aOrigin != rCellPos )
4536 				pCell = GetCell( aOrigin );
4537 			if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
4538 			{
4539 				SCCOL nSizeX;
4540                 SCROW nSizeY;
4541 				((ScFormulaCell*)pCell)->GetMatColsRows(nSizeX,nSizeY);
4542 				if ( !(nSizeX > 0 && nSizeY > 0) )
4543 				{
4544 					// GetMatrixEdge computes also dimensions of the matrix
4545 					// if not already done (may occur if document is loaded
4546 					// from old file format).
4547 					// Needs an "invalid" initialized address.
4548 					aOrigin.SetInvalid();
4549 					((ScFormulaCell*)pCell)->GetMatrixEdge(aOrigin);
4550 					((ScFormulaCell*)pCell)->GetMatColsRows(nSizeX,nSizeY);
4551 				}
4552 				if ( nSizeX > 0 && nSizeY > 0 )
4553 				{
4554 					ScAddress aEnd( aOrigin.Col() + nSizeX - 1,
4555 									aOrigin.Row() + nSizeY - 1,
4556 									aOrigin.Tab() );
4557 
4558 					rMatrix.aStart = aOrigin;
4559 					rMatrix.aEnd = aEnd;
4560 					bRet = sal_True;
4561 				}
4562 			}
4563 		}
4564 	}
4565 	return bRet;
4566 }
4567 
4568 
4569 sal_Bool ScDocument::ExtendOverlapped( SCCOL& rStartCol, SCROW& rStartRow,
4570 								SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
4571 {
4572 	sal_Bool bFound = sal_False;
4573 	if ( ValidColRow(rStartCol,rStartRow) && ValidColRow(nEndCol,nEndRow) && ValidTab(nTab) )
4574 	{
4575 		if (pTab[nTab])
4576 		{
4577 			SCCOL nCol;
4578 			SCCOL nOldCol = rStartCol;
4579 			SCROW nOldRow = rStartRow;
4580 			for (nCol=nOldCol; nCol<=nEndCol; nCol++)
4581 				while (((ScMergeFlagAttr*)GetAttr(nCol,rStartRow,nTab,ATTR_MERGE_FLAG))->
4582 							IsVerOverlapped())
4583 					--rStartRow;
4584 
4585 			//!		weiterreichen ?
4586 
4587 			ScAttrArray* pAttrArray = pTab[nTab]->aCol[nOldCol].pAttrArray;
4588 			SCSIZE nIndex;
4589 			pAttrArray->Search( nOldRow, nIndex );
4590 			SCROW nAttrPos = nOldRow;
4591 			while (nAttrPos<=nEndRow)
4592 			{
4593 				DBG_ASSERT( nIndex < pAttrArray->nCount, "Falscher Index im AttrArray" );
4594 
4595 				if (((ScMergeFlagAttr&)pAttrArray->pData[nIndex].pPattern->
4596 						GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped())
4597 				{
4598 					SCROW nLoopEndRow = Min( nEndRow, pAttrArray->pData[nIndex].nRow );
4599 					for (SCROW nAttrRow = nAttrPos; nAttrRow <= nLoopEndRow; nAttrRow++)
4600 					{
4601 						SCCOL nTempCol = nOldCol;
4602 						do
4603 							--nTempCol;
4604 						while (((ScMergeFlagAttr*)GetAttr(nTempCol,nAttrRow,nTab,ATTR_MERGE_FLAG))
4605 								->IsHorOverlapped());
4606 						if (nTempCol < rStartCol)
4607 							rStartCol = nTempCol;
4608 					}
4609 				}
4610 				nAttrPos = pAttrArray->pData[nIndex].nRow + 1;
4611 				++nIndex;
4612 			}
4613 		}
4614 	}
4615 	else
4616 	{
4617 		DBG_ERROR("ExtendOverlapped: falscher Bereich");
4618 	}
4619 
4620 	return bFound;
4621 }
4622 
4623 
4624 sal_Bool ScDocument::ExtendMergeSel( SCCOL nStartCol, SCROW nStartRow,
4625                               SCCOL& rEndCol, SCROW& rEndRow,
4626                               const ScMarkData& rMark, sal_Bool bRefresh, sal_Bool bAttrs )
4627 {
4628     // use all selected sheets from rMark
4629 
4630     sal_Bool bFound = sal_False;
4631     SCCOL nOldEndCol = rEndCol;
4632     SCROW nOldEndRow = rEndRow;
4633 
4634     for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
4635         if ( pTab[nTab] && rMark.GetTableSelect(nTab) )
4636         {
4637             SCCOL nThisEndCol = nOldEndCol;
4638             SCROW nThisEndRow = nOldEndRow;
4639             if ( ExtendMerge( nStartCol, nStartRow, nThisEndCol, nThisEndRow, nTab, bRefresh, bAttrs ) )
4640                 bFound = sal_True;
4641             if ( nThisEndCol > rEndCol )
4642                 rEndCol = nThisEndCol;
4643             if ( nThisEndRow > rEndRow )
4644                 rEndRow = nThisEndRow;
4645         }
4646 
4647     return bFound;
4648 }
4649 
4650 
4651 sal_Bool ScDocument::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
4652 							  SCCOL& rEndCol,  SCROW& rEndRow,
4653 							  SCTAB nTab, sal_Bool bRefresh, sal_Bool bAttrs )
4654 {
4655 	sal_Bool bFound = sal_False;
4656 	if ( ValidColRow(nStartCol,nStartRow) && ValidColRow(rEndCol,rEndRow) && ValidTab(nTab) )
4657 	{
4658 		if (pTab[nTab])
4659 			bFound = pTab[nTab]->ExtendMerge( nStartCol, nStartRow, rEndCol, rEndRow, bRefresh, bAttrs );
4660 
4661 		if (bRefresh)
4662 			RefreshAutoFilter( nStartCol, nStartRow, rEndCol, rEndRow, nTab );
4663 	}
4664 	else
4665 	{
4666 		DBG_ERROR("ExtendMerge: falscher Bereich");
4667 	}
4668 
4669 	return bFound;
4670 }
4671 
4672 
4673 sal_Bool ScDocument::ExtendMerge( ScRange& rRange, sal_Bool bRefresh, sal_Bool bAttrs )
4674 {
4675 	sal_Bool bFound = sal_False;
4676 	SCTAB nStartTab = rRange.aStart.Tab();
4677 	SCTAB nEndTab   = rRange.aEnd.Tab();
4678 	SCCOL nEndCol   = rRange.aEnd.Col();
4679 	SCROW nEndRow   = rRange.aEnd.Row();
4680 
4681 	PutInOrder( nStartTab, nEndTab );
4682 	for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++ )
4683 	{
4684 		SCCOL nExtendCol = rRange.aEnd.Col();
4685 		SCROW nExtendRow = rRange.aEnd.Row();
4686 		if (ExtendMerge( rRange.aStart.Col(), rRange.aStart.Row(),
4687 						 nExtendCol,          nExtendRow,
4688 						 nTab, bRefresh, bAttrs ) )
4689 		{
4690 			bFound = sal_True;
4691 			if (nExtendCol > nEndCol) nEndCol = nExtendCol;
4692 			if (nExtendRow > nEndRow) nEndRow = nExtendRow;
4693 		}
4694 	}
4695 
4696 	rRange.aEnd.SetCol(nEndCol);
4697 	rRange.aEnd.SetRow(nEndRow);
4698 
4699 	return bFound;
4700 }
4701 
4702 sal_Bool ScDocument::ExtendTotalMerge( ScRange& rRange )
4703 {
4704 	//	Bereich genau dann auf zusammengefasste Zellen erweitern, wenn
4705 	//	dadurch keine neuen nicht-ueberdeckten Zellen getroffen werden
4706 
4707 	sal_Bool bRet = sal_False;
4708 	ScRange aExt = rRange;
4709 	if (ExtendMerge(aExt))
4710 	{
4711 		if ( aExt.aEnd.Row() > rRange.aEnd.Row() )
4712 		{
4713 			ScRange aTest = aExt;
4714 			aTest.aStart.SetRow( rRange.aEnd.Row() + 1 );
4715 			if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
4716 				aExt.aEnd.SetRow(rRange.aEnd.Row());
4717 		}
4718 		if ( aExt.aEnd.Col() > rRange.aEnd.Col() )
4719 		{
4720 			ScRange aTest = aExt;
4721 			aTest.aStart.SetCol( rRange.aEnd.Col() + 1 );
4722 			if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
4723 				aExt.aEnd.SetCol(rRange.aEnd.Col());
4724 		}
4725 
4726 		bRet = ( aExt.aEnd != rRange.aEnd );
4727 		rRange = aExt;
4728 	}
4729 	return bRet;
4730 }
4731 
4732 sal_Bool ScDocument::ExtendOverlapped( ScRange& rRange )
4733 {
4734 	sal_Bool bFound = sal_False;
4735 	SCTAB nStartTab = rRange.aStart.Tab();
4736 	SCTAB nEndTab   = rRange.aEnd.Tab();
4737 	SCCOL nStartCol = rRange.aStart.Col();
4738 	SCROW nStartRow = rRange.aStart.Row();
4739 
4740 	PutInOrder( nStartTab, nEndTab );
4741 	for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++ )
4742 	{
4743 		SCCOL nExtendCol = rRange.aStart.Col();
4744 		SCROW nExtendRow = rRange.aStart.Row();
4745 		ExtendOverlapped( nExtendCol, nExtendRow,
4746 								rRange.aEnd.Col(), rRange.aEnd.Row(), nTab );
4747 		if (nExtendCol < nStartCol)
4748 		{
4749 			nStartCol = nExtendCol;
4750 			bFound = sal_True;
4751 		}
4752 		if (nExtendRow < nStartRow)
4753 		{
4754 			nStartRow = nExtendRow;
4755 			bFound = sal_True;
4756 		}
4757 	}
4758 
4759 	rRange.aStart.SetCol(nStartCol);
4760 	rRange.aStart.SetRow(nStartRow);
4761 
4762 	return bFound;
4763 }
4764 
4765 sal_Bool ScDocument::RefreshAutoFilter( SCCOL nStartCol, SCROW nStartRow,
4766 									SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
4767 {
4768 	sal_uInt16 nCount = pDBCollection->GetCount();
4769 	sal_uInt16 i;
4770 	ScDBData* pData;
4771 	SCTAB nDBTab;
4772 	SCCOL nDBStartCol;
4773 	SCROW nDBStartRow;
4774 	SCCOL nDBEndCol;
4775 	SCROW nDBEndRow;
4776 
4777 	//		Autofilter loeschen
4778 
4779 	sal_Bool bChange = RemoveFlagsTab( nStartCol,nStartRow, nEndCol,nEndRow, nTab, SC_MF_AUTO );
4780 
4781 	//		Autofilter setzen
4782 
4783 	for (i=0; i<nCount; i++)
4784 	{
4785 		pData = (*pDBCollection)[i];
4786 		if (pData->HasAutoFilter())
4787 		{
4788 			pData->GetArea( nDBTab, nDBStartCol,nDBStartRow, nDBEndCol,nDBEndRow );
4789 			if ( nDBTab==nTab && nDBStartRow<=nEndRow && nDBEndRow>=nStartRow &&
4790 									nDBStartCol<=nEndCol && nDBEndCol>=nStartCol )
4791 			{
4792 				if (ApplyFlagsTab( nDBStartCol,nDBStartRow, nDBEndCol,nDBStartRow,
4793 									nDBTab, SC_MF_AUTO ))
4794 					bChange = sal_True;
4795 			}
4796 		}
4797 	}
4798 	return bChange;
4799 }
4800 
4801 
4802 sal_Bool ScDocument::IsHorOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4803 {
4804 	const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
4805 										GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
4806 	if (pAttr)
4807 		return pAttr->IsHorOverlapped();
4808 	else
4809 	{
4810 		DBG_ERROR("Overlapped: Attr==0");
4811 		return sal_False;
4812 	}
4813 }
4814 
4815 
4816 sal_Bool ScDocument::IsVerOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4817 {
4818 	const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
4819 										GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
4820 	if (pAttr)
4821 		return pAttr->IsVerOverlapped();
4822 	else
4823 	{
4824 		DBG_ERROR("Overlapped: Attr==0");
4825 		return sal_False;
4826 	}
4827 }
4828 
4829 
4830 void ScDocument::ApplySelectionFrame( const ScMarkData& rMark,
4831 									  const SvxBoxItem* pLineOuter,
4832 									  const SvxBoxInfoItem* pLineInner )
4833 {
4834 	ScRangeList aRangeList;
4835 	rMark.FillRangeListWithMarks( &aRangeList, sal_False );
4836 	sal_uLong nRangeCount = aRangeList.Count();
4837 	for (SCTAB i=0; i<=MAXTAB; i++)
4838 	{
4839 		if (pTab[i] && rMark.GetTableSelect(i))
4840 		{
4841 			for (sal_uLong j=0; j<nRangeCount; j++)
4842 			{
4843 				ScRange aRange = *aRangeList.GetObject(j);
4844 				pTab[i]->ApplyBlockFrame( pLineOuter, pLineInner,
4845 					aRange.aStart.Col(), aRange.aStart.Row(),
4846 					aRange.aEnd.Col(),   aRange.aEnd.Row() );
4847 			}
4848 		}
4849 	}
4850 }
4851 
4852 
4853 void ScDocument::ApplyFrameAreaTab( const ScRange& rRange,
4854 									const SvxBoxItem* pLineOuter,
4855 									const SvxBoxInfoItem* pLineInner )
4856 {
4857 	SCTAB nStartTab = rRange.aStart.Tab();
4858 	SCTAB nEndTab = rRange.aStart.Tab();
4859 	for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
4860 		if (pTab[nTab])
4861 			pTab[nTab]->ApplyBlockFrame( pLineOuter, pLineInner,
4862 										 rRange.aStart.Col(), rRange.aStart.Row(),
4863 										 rRange.aEnd.Col(),   rRange.aEnd.Row() );
4864 }
4865 
4866 
4867 void ScDocument::ApplySelectionPattern( const ScPatternAttr& rAttr, const ScMarkData& rMark )
4868 {
4869 	const SfxItemSet* pSet = &rAttr.GetItemSet();
4870 	sal_Bool bSet = sal_False;
4871 	sal_uInt16 i;
4872 	for (i=ATTR_PATTERN_START; i<=ATTR_PATTERN_END && !bSet; i++)
4873 		if (pSet->GetItemState(i) == SFX_ITEM_SET)
4874 			bSet = sal_True;
4875 
4876 	if (bSet)
4877 	{
4878 		// ApplySelectionCache needs multi mark
4879 		if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
4880 		{
4881 			ScRange aRange;
4882 			rMark.GetMarkArea( aRange );
4883 			ApplyPatternArea( aRange.aStart.Col(), aRange.aStart.Row(),
4884 							  aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rAttr );
4885 		}
4886 		else
4887 		{
4888 			SfxItemPoolCache aCache( xPoolHelper->GetDocPool(), pSet );
4889             for (SCTAB nTab=0; nTab<=MAXTAB; nTab++)
4890                 if (pTab[nTab])
4891                     if (rMark.GetTableSelect(nTab))
4892                         pTab[nTab]->ApplySelectionCache( &aCache, rMark );
4893 		}
4894 	}
4895 }
4896 
4897 
4898 void ScDocument::ChangeSelectionIndent( sal_Bool bIncrement, const ScMarkData& rMark )
4899 {
4900 	for (SCTAB i=0; i<=MAXTAB; i++)
4901 		if (pTab[i] && rMark.GetTableSelect(i))
4902 			pTab[i]->ChangeSelectionIndent( bIncrement, rMark );
4903 }
4904 
4905 
4906 void ScDocument::ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark )
4907 {
4908 	for (SCTAB i=0; i<=MAXTAB; i++)
4909 		if (pTab[i] && rMark.GetTableSelect(i))
4910 			pTab[i]->ClearSelectionItems( pWhich, rMark );
4911 }
4912 
4913 
4914 void ScDocument::DeleteSelection( sal_uInt16 nDelFlag, const ScMarkData& rMark )
4915 {
4916 	for (SCTAB i=0; i<=MAXTAB; i++)
4917 		if (pTab[i] && rMark.GetTableSelect(i))
4918             pTab[i]->DeleteSelection( nDelFlag, rMark );
4919 }
4920 
4921 
4922 void ScDocument::DeleteSelectionTab( SCTAB nTab, sal_uInt16 nDelFlag, const ScMarkData& rMark )
4923 {
4924 	if (ValidTab(nTab)  && pTab[nTab])
4925 		pTab[nTab]->DeleteSelection( nDelFlag, rMark );
4926 	else
4927 	{
4928 		DBG_ERROR("Falsche Tabelle");
4929 	}
4930 }
4931 
4932 
4933 ScPatternAttr* ScDocument::GetDefPattern() const
4934 {
4935 	return (ScPatternAttr*) &xPoolHelper->GetDocPool()->GetDefaultItem(ATTR_PATTERN);
4936 }
4937 
4938 
4939 ScDocumentPool* ScDocument::GetPool()
4940 {
4941 	return xPoolHelper->GetDocPool();
4942 }
4943 
4944 
4945 
4946 ScStyleSheetPool* ScDocument::GetStyleSheetPool() const
4947 {
4948 	return xPoolHelper->GetStylePool();
4949 }
4950 
4951 
4952 SCSIZE ScDocument::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
4953 							SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, ScDirection eDir )
4954 {
4955 	PutInOrder(nStartCol, nEndCol);
4956 	PutInOrder(nStartRow, nEndRow);
4957 	PutInOrder(nStartTab, nEndTab);
4958 	if (VALIDTAB(nStartTab))
4959 	{
4960 		if (pTab[nStartTab])
4961 			return pTab[nStartTab]->GetEmptyLinesInBlock(nStartCol, nStartRow, nEndCol, nEndRow, eDir);
4962 		else
4963 			return 0;
4964 	}
4965 	else
4966 		return 0;
4967 }
4968 
4969 
4970 void ScDocument::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY )
4971 {
4972 	if (ValidTab(nTab) && pTab[nTab])
4973 		pTab[nTab]->FindAreaPos( rCol, rRow, nMovX, nMovY );
4974 }
4975 
4976 
4977 void ScDocument::GetNextPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY,
4978 								sal_Bool bMarked, sal_Bool bUnprotected, const ScMarkData& rMark )
4979 {
4980 	DBG_ASSERT( !nMovX || !nMovY, "GetNextPos: nur X oder Y" );
4981 
4982 	ScMarkData aCopyMark = rMark;
4983 	aCopyMark.SetMarking(sal_False);
4984 	aCopyMark.MarkToMulti();
4985 
4986 	if (ValidTab(nTab) && pTab[nTab])
4987 		pTab[nTab]->GetNextPos( rCol, rRow, nMovX, nMovY, bMarked, bUnprotected, aCopyMark );
4988 }
4989 
4990 //
4991 //	Datei-Operationen
4992 //
4993 
4994 
4995 void ScDocument::UpdStlShtPtrsFrmNms()
4996 {
4997 	ScPatternAttr::pDoc = this;
4998 
4999 	ScDocumentPool* pPool = xPoolHelper->GetDocPool();
5000 
5001 	sal_uInt32 nCount = pPool->GetItemCount2(ATTR_PATTERN);
5002 	ScPatternAttr* pPattern;
5003 	for (sal_uInt32 i=0; i<nCount; i++)
5004 	{
5005 		pPattern = (ScPatternAttr*)pPool->GetItem2(ATTR_PATTERN, i);
5006 		if (pPattern)
5007 			pPattern->UpdateStyleSheet();
5008 	}
5009 	((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).UpdateStyleSheet();
5010 }
5011 
5012 
5013 void ScDocument::StylesToNames()
5014 {
5015 	ScPatternAttr::pDoc = this;
5016 
5017 	ScDocumentPool* pPool = xPoolHelper->GetDocPool();
5018 
5019 	sal_uInt32 nCount = pPool->GetItemCount2(ATTR_PATTERN);
5020 	ScPatternAttr* pPattern;
5021 	for (sal_uInt32 i=0; i<nCount; i++)
5022 	{
5023 		pPattern = (ScPatternAttr*)pPool->GetItem2(ATTR_PATTERN, i);
5024 		if (pPattern)
5025 			pPattern->StyleToName();
5026 	}
5027 	((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).StyleToName();
5028 }
5029 
5030 
5031 sal_uLong ScDocument::GetCellCount() const
5032 {
5033 	sal_uLong nCellCount = 0L;
5034 
5035 	for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
5036 		if ( pTab[nTab] )
5037 			nCellCount += pTab[nTab]->GetCellCount();
5038 
5039 	return nCellCount;
5040 }
5041 
5042 SCSIZE ScDocument::GetCellCount(SCTAB nTab, SCCOL nCol) const
5043 {
5044     if (!ValidTab(nTab) || !pTab[nTab])
5045         return 0;
5046 
5047     return pTab[nTab]->GetCellCount(nCol);
5048 }
5049 
5050 sal_uLong ScDocument::GetCodeCount() const
5051 {
5052 	sal_uLong nCodeCount = 0;
5053 
5054 	for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
5055 		if ( pTab[nTab] )
5056 			nCodeCount += pTab[nTab]->GetCodeCount();
5057 
5058 	return nCodeCount;
5059 }
5060 
5061 
5062 sal_uLong ScDocument::GetWeightedCount() const
5063 {
5064 	sal_uLong nCellCount = 0L;
5065 
5066 	for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
5067 		if ( pTab[nTab] )
5068 			nCellCount += pTab[nTab]->GetWeightedCount();
5069 
5070 	return nCellCount;
5071 }
5072 
5073 
5074 void ScDocument::PageStyleModified( SCTAB nTab, const String& rNewName )
5075 {
5076 	if ( ValidTab(nTab)  && pTab[nTab] )
5077 		pTab[nTab]->PageStyleModified( rNewName );
5078 }
5079 
5080 
5081 void ScDocument::SetPageStyle( SCTAB nTab, const String& rName )
5082 {
5083 	if ( ValidTab(nTab)  && pTab[nTab] )
5084 		pTab[nTab]->SetPageStyle( rName );
5085 }
5086 
5087 
5088 const String& ScDocument::GetPageStyle( SCTAB nTab ) const
5089 {
5090 	if ( ValidTab(nTab)  && pTab[nTab] )
5091 		return pTab[nTab]->GetPageStyle();
5092 
5093 	return EMPTY_STRING;
5094 }
5095 
5096 
5097 void ScDocument::SetPageSize( SCTAB nTab, const Size& rSize )
5098 {
5099 	if ( ValidTab(nTab)  && pTab[nTab] )
5100 		pTab[nTab]->SetPageSize( rSize );
5101 }
5102 
5103 Size ScDocument::GetPageSize( SCTAB nTab ) const
5104 {
5105 	if ( ValidTab(nTab)  && pTab[nTab] )
5106 		return pTab[nTab]->GetPageSize();
5107 
5108 	DBG_ERROR("falsche Tab");
5109 	return Size();
5110 }
5111 
5112 
5113 void ScDocument::SetRepeatArea( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow )
5114 {
5115 	if ( ValidTab(nTab)  && pTab[nTab] )
5116 		pTab[nTab]->SetRepeatArea( nStartCol, nEndCol, nStartRow, nEndRow );
5117 }
5118 
5119 void ScDocument::InvalidatePageBreaks(SCTAB nTab)
5120 {
5121     if (ValidTab(nTab) && pTab[nTab])
5122         pTab[nTab]->InvalidatePageBreaks();
5123 }
5124 
5125 void ScDocument::UpdatePageBreaks( SCTAB nTab, const ScRange* pUserArea )
5126 {
5127 	if ( ValidTab(nTab)  && pTab[nTab] )
5128 		pTab[nTab]->UpdatePageBreaks( pUserArea );
5129 }
5130 
5131 void ScDocument::RemoveManualBreaks( SCTAB nTab )
5132 {
5133 	if ( ValidTab(nTab)  && pTab[nTab] )
5134 		pTab[nTab]->RemoveManualBreaks();
5135 }
5136 
5137 sal_Bool ScDocument::HasManualBreaks( SCTAB nTab ) const
5138 {
5139 	if ( ValidTab(nTab)  && pTab[nTab] )
5140 		return pTab[nTab]->HasManualBreaks();
5141 
5142 	DBG_ERROR("falsche Tab");
5143 	return sal_False;
5144 }
5145 
5146 
5147 void ScDocument::GetDocStat( ScDocStat& rDocStat )
5148 {
5149 	rDocStat.nTableCount = GetTableCount();
5150 	rDocStat.aDocName	 = aDocName;
5151 	rDocStat.nCellCount	 = GetCellCount();
5152 }
5153 
5154 
5155 sal_Bool ScDocument::HasPrintRange()
5156 {
5157 	sal_Bool bResult = sal_False;
5158 
5159 	for ( SCTAB i=0; !bResult && i<nMaxTableNumber; i++ )
5160 		if ( pTab[i] )
5161             bResult = pTab[i]->IsPrintEntireSheet() || (pTab[i]->GetPrintRangeCount() > 0);
5162 
5163 	return bResult;
5164 }
5165 
5166 
5167 sal_Bool ScDocument::IsPrintEntireSheet( SCTAB nTab ) const
5168 {
5169     return (ValidTab(nTab) ) && pTab[nTab] && pTab[nTab]->IsPrintEntireSheet();
5170 }
5171 
5172 
5173 sal_uInt16 ScDocument::GetPrintRangeCount( SCTAB nTab )
5174 {
5175 	if (ValidTab(nTab) && pTab[nTab])
5176 		return pTab[nTab]->GetPrintRangeCount();
5177 
5178 	return 0;
5179 }
5180 
5181 
5182 const ScRange* ScDocument::GetPrintRange( SCTAB nTab, sal_uInt16 nPos )
5183 {
5184 	if (ValidTab(nTab) && pTab[nTab])
5185 		return pTab[nTab]->GetPrintRange(nPos);
5186 
5187 	return NULL;
5188 }
5189 
5190 
5191 const ScRange* ScDocument::GetRepeatColRange( SCTAB nTab )
5192 {
5193 	if (ValidTab(nTab) && pTab[nTab])
5194 		return pTab[nTab]->GetRepeatColRange();
5195 
5196 	return NULL;
5197 }
5198 
5199 
5200 const ScRange* ScDocument::GetRepeatRowRange( SCTAB nTab )
5201 {
5202 	if (ValidTab(nTab) && pTab[nTab])
5203 		return pTab[nTab]->GetRepeatRowRange();
5204 
5205 	return NULL;
5206 }
5207 
5208 
5209 void ScDocument::ClearPrintRanges( SCTAB nTab )
5210 {
5211     if (ValidTab(nTab) && pTab[nTab])
5212         pTab[nTab]->ClearPrintRanges();
5213 }
5214 
5215 
5216 void ScDocument::AddPrintRange( SCTAB nTab, const ScRange& rNew )
5217 {
5218 	if (ValidTab(nTab) && pTab[nTab])
5219         pTab[nTab]->AddPrintRange( rNew );
5220 }
5221 
5222 
5223 //UNUSED2009-05 void ScDocument::SetPrintRange( SCTAB nTab, const ScRange& rNew )
5224 //UNUSED2009-05 {
5225 //UNUSED2009-05     if (ValidTab(nTab) && pTab[nTab])
5226 //UNUSED2009-05         pTab[nTab]->SetPrintRange( rNew );
5227 //UNUSED2009-05 }
5228 
5229 
5230 void ScDocument::SetPrintEntireSheet( SCTAB nTab )
5231 {
5232     if (ValidTab(nTab) && pTab[nTab])
5233         pTab[nTab]->SetPrintEntireSheet();
5234 }
5235 
5236 
5237 void ScDocument::SetRepeatColRange( SCTAB nTab, const ScRange* pNew )
5238 {
5239 	if (ValidTab(nTab) && pTab[nTab])
5240 		pTab[nTab]->SetRepeatColRange( pNew );
5241 }
5242 
5243 
5244 void ScDocument::SetRepeatRowRange( SCTAB nTab, const ScRange* pNew )
5245 {
5246 	if (ValidTab(nTab) && pTab[nTab])
5247 		pTab[nTab]->SetRepeatRowRange( pNew );
5248 }
5249 
5250 
5251 ScPrintRangeSaver* ScDocument::CreatePrintRangeSaver() const
5252 {
5253 	SCTAB nCount = GetTableCount();
5254 	ScPrintRangeSaver* pNew = new ScPrintRangeSaver( nCount );
5255 	for (SCTAB i=0; i<nCount; i++)
5256 		if (pTab[i])
5257 			pTab[i]->FillPrintSaver( pNew->GetTabData(i) );
5258 	return pNew;
5259 }
5260 
5261 
5262 void ScDocument::RestorePrintRanges( const ScPrintRangeSaver& rSaver )
5263 {
5264 	SCTAB nCount = rSaver.GetTabCount();
5265 	for (SCTAB i=0; i<nCount; i++)
5266 		if (pTab[i])
5267 			pTab[i]->RestorePrintRanges( rSaver.GetTabData(i) );
5268 }
5269 
5270 
5271 sal_Bool ScDocument::NeedPageResetAfterTab( SCTAB nTab ) const
5272 {
5273     //  Die Seitennummern-Zaehlung faengt bei einer Tabelle neu an, wenn eine
5274 	//	andere Vorlage als bei der vorherigen gesetzt ist (nur Namen vergleichen)
5275 	//	und eine Seitennummer angegeben ist (nicht 0)
5276 
5277 	if ( nTab < MAXTAB && pTab[nTab] && pTab[nTab+1] )
5278 	{
5279 		String aNew = pTab[nTab+1]->GetPageStyle();
5280 		if ( aNew != pTab[nTab]->GetPageStyle() )
5281 		{
5282 			SfxStyleSheetBase* pStyle = xPoolHelper->GetStylePool()->Find( aNew, SFX_STYLE_FAMILY_PAGE );
5283 			if ( pStyle )
5284 			{
5285 				const SfxItemSet& rSet = pStyle->GetItemSet();
5286 				sal_uInt16 nFirst = ((const SfxUInt16Item&)rSet.Get(ATTR_PAGE_FIRSTPAGENO)).GetValue();
5287 				if ( nFirst != 0 )
5288 					return sal_True;		// Seitennummer in neuer Vorlage angegeben
5289 			}
5290 		}
5291 	}
5292 
5293 	return sal_False;		// sonst nicht
5294 }
5295 
5296 SfxUndoManager* ScDocument::GetUndoManager()
5297 {
5298 	if (!mpUndoManager)
5299     {
5300         // to support enhanced text edit for draw objects, use an SdrUndoManager
5301 		mpUndoManager = new SdrUndoManager;
5302     }
5303 
5304 	return mpUndoManager;
5305 }
5306 
5307 ScRowBreakIterator* ScDocument::GetRowBreakIterator(SCTAB nTab) const
5308 {
5309     if (ValidTab(nTab) && pTab[nTab])
5310         return new ScRowBreakIterator(pTab[nTab]->maRowPageBreaks);
5311     return NULL;
5312 }
5313 
5314 void ScDocument::EnableUndo( bool bVal )
5315 {
5316 	GetUndoManager()->EnableUndo(bVal);
5317 	if( pDrawLayer ) pDrawLayer->EnableUndo(bVal);
5318 	mbUndoEnabled = bVal;
5319 }
5320 
5321 bool ScDocument::IsInVBAMode() const
5322 {
5323     bool bResult = false;
5324     if ( pShell )
5325     {
5326         com::sun::star::uno::Reference< com::sun::star::script::vba::XVBACompatibility > xVBA( pShell->GetBasicContainer(), com::sun::star::uno::UNO_QUERY );
5327         bResult = xVBA.is() && xVBA->getVBACompatibilityMode();
5328     }
5329     return bResult;
5330 }
5331