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