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