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