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