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