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