xref: /aoo41x/main/sc/source/core/data/documen3.cxx (revision b3f79822)
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 #include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
30 #include "scitems.hxx"
31 #include <editeng/langitem.hxx>
32 #include <svl/srchitem.hxx>
33 #include <sfx2/linkmgr.hxx>
34 #include <sfx2/bindings.hxx>
35 #include <sfx2/objsh.hxx>
36 #include <svl/zforlist.hxx>
37 #include <svl/PasswordHelper.hxx>
38 #include <vcl/svapp.hxx>
39 #include "document.hxx"
40 #include "attrib.hxx"
41 #include "cell.hxx"
42 #include "table.hxx"
43 #include "rangenam.hxx"
44 #include "dbcolect.hxx"
45 #include "pivot.hxx"
46 #include "docpool.hxx"
47 #include "poolhelp.hxx"
48 #include "autoform.hxx"
49 #include "rangelst.hxx"
50 #include "chartarr.hxx"
51 #include "chartlock.hxx"
52 #include "refupdat.hxx"
53 #include "docoptio.hxx"
54 #include "viewopti.hxx"
55 #include "scextopt.hxx"
56 #include "brdcst.hxx"
57 #include "bcaslot.hxx"
58 #include "tablink.hxx"
59 #include "externalrefmgr.hxx"
60 #include "markdata.hxx"
61 #include "validat.hxx"
62 #include "dociter.hxx"
63 #include "detdata.hxx"
64 #include "detfunc.hxx"
65 #include "scmod.hxx"   		// SC_MOD
66 #include "inputopt.hxx" 	// GetExpandRefs
67 #include "chartlis.hxx"
68 #include "sc.hrc"			// SID_LINK
69 #include "hints.hxx"
70 #include "dpobject.hxx"
71 #include "unoguard.hxx"
72 #include "drwlayer.hxx"
73 #include "unoreflist.hxx"
74 #include "listenercalls.hxx"
75 // Wang Xu Ming -- 2009-8-17
76 // DataPilot Migration - Cache&&Performance
77 #include "dpshttab.hxx"
78 #include "dptablecache.hxx"
79 // End Comments
80 #include "tabprotection.hxx"
81 #include "formulaparserpool.hxx"
82 #include "clipparam.hxx"
83 #include "sheetevents.hxx"
84 
85 #include <memory>
86 
87 using namespace com::sun::star;
88 
89 //------------------------------------------------------------------------
90 
91 ScRangeName* ScDocument::GetRangeName()
92 {
93 	return pRangeName;
94 }
95 
96 void ScDocument::SetRangeName( ScRangeName* pNewRangeName )
97 {
98 	if (pRangeName)
99 		delete pRangeName;
100 	pRangeName = pNewRangeName;
101 }
102 
103 //UNUSED2008-05  ScRangeData* ScDocument::GetRangeAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab,
104 //UNUSED2008-05                                              sal_Bool bStartOnly) const
105 //UNUSED2008-05  {
106 //UNUSED2008-05      if ( pRangeName )
107 //UNUSED2008-05          return pRangeName->GetRangeAtCursor( ScAddress( nCol, nRow, nTab ), bStartOnly );
108 //UNUSED2008-05      else
109 //UNUSED2008-05          return NULL;
110 //UNUSED2008-05  }
111 
112 ScRangeData* ScDocument::GetRangeAtBlock( const ScRange& rBlock, String* pName ) const
113 {
114 	ScRangeData* pData = NULL;
115 	if ( pRangeName )
116 	{
117 		pData = pRangeName->GetRangeAtBlock( rBlock );
118 		if (pData && pName)
119 			*pName = pData->GetName();
120 	}
121 	return pData;
122 }
123 
124 ScDBCollection* ScDocument::GetDBCollection() const
125 {
126 	return pDBCollection;
127 }
128 
129 void ScDocument::SetDBCollection( ScDBCollection* pNewDBCollection, sal_Bool bRemoveAutoFilter )
130 {
131 	if ( bRemoveAutoFilter )
132 	{
133 		//	remove auto filter attribute if new db data don't contain auto filter flag
134 		//	start position is also compared, so bRemoveAutoFilter must not be set from ref-undo!
135 
136 		if ( pDBCollection )
137 		{
138 			sal_uInt16 nOldCount = pDBCollection->GetCount();
139 			for (sal_uInt16 nOld=0; nOld<nOldCount; nOld++)
140 			{
141 				ScDBData* pOldData = (*pDBCollection)[nOld];
142 				if ( pOldData->HasAutoFilter() )
143 				{
144 					ScRange aOldRange;
145 					pOldData->GetArea( aOldRange );
146 
147 					sal_Bool bFound = sal_False;
148 					sal_uInt16 nNewIndex = 0;
149 					if ( pNewDBCollection &&
150 						pNewDBCollection->SearchName( pOldData->GetName(), nNewIndex ) )
151 					{
152 						ScDBData* pNewData = (*pNewDBCollection)[nNewIndex];
153 						if ( pNewData->HasAutoFilter() )
154 						{
155 							ScRange aNewRange;
156 							pNewData->GetArea( aNewRange );
157 							if ( aOldRange.aStart == aNewRange.aStart )
158 								bFound = sal_True;
159 						}
160 					}
161 
162 					if ( !bFound )
163 					{
164 						aOldRange.aEnd.SetRow( aOldRange.aStart.Row() );
165 						RemoveFlagsTab( aOldRange.aStart.Col(), aOldRange.aStart.Row(),
166 										aOldRange.aEnd.Col(),   aOldRange.aEnd.Row(),
167 										aOldRange.aStart.Tab(), SC_MF_AUTO );
168                         RepaintRange( aOldRange );
169 					}
170 				}
171 			}
172 		}
173 	}
174 
175 	if (pDBCollection)
176 		delete pDBCollection;
177 	pDBCollection = pNewDBCollection;
178 }
179 
180 ScDBData* ScDocument::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_Bool bStartOnly) const
181 {
182 	if (pDBCollection)
183 		return pDBCollection->GetDBAtCursor(nCol, nRow, nTab, bStartOnly);
184 	else
185 		return NULL;
186 }
187 
188 ScDBData* ScDocument::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
189 {
190 	if (pDBCollection)
191 		return pDBCollection->GetDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2);
192 	else
193 		return NULL;
194 }
195 
196 ScDBData* ScDocument::GetFilterDBAtTable(SCTAB nTab) const
197 {
198 	if (pDBCollection)
199 		return pDBCollection->GetFilterDBAtTable(nTab);
200 	else
201 		return NULL;
202 }
203 
204 ScDPCollection* ScDocument::GetDPCollection()
205 {
206 	if (!pDPCollection)
207 		pDPCollection = new ScDPCollection(this);
208 	return pDPCollection;
209 }
210 
211 ScDPObject* ScDocument::GetDPAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab) const
212 {
213 	if (!pDPCollection)
214 		return NULL;
215 
216 	sal_uInt16 nCount = pDPCollection->GetCount();
217 	ScAddress aPos( nCol, nRow, nTab );
218 	for (sal_uInt16 i=0; i<nCount; i++)
219 		if ( (*pDPCollection)[i]->GetOutRange().In( aPos ) )
220 			return (*pDPCollection)[i];
221 
222 	return NULL;
223 }
224 
225 ScDPObject* ScDocument::GetDPAtBlock( const ScRange & rBlock ) const
226 {
227     if (!pDPCollection)
228         return NULL;
229 
230     /* Walk the collection in reverse order to get something of an
231      * approximation of MS Excels 'most recent' effect. */
232     sal_uInt16 i = pDPCollection->GetCount();
233     while ( i-- > 0 )
234         if ( (*pDPCollection)[i]->GetOutRange().In( rBlock ) )
235             return (*pDPCollection)[i];
236 
237     return NULL;
238 }
239 
240 ScChartCollection* ScDocument::GetChartCollection() const
241 {
242 	return pChartCollection;
243 }
244 
245 void ScDocument::StopTemporaryChartLock()
246 {
247     if( apTemporaryChartLock.get() )
248         apTemporaryChartLock->StopLocking();
249 }
250 
251 void ScDocument::SetChartListenerCollection(
252 			ScChartListenerCollection* pNewChartListenerCollection,
253 			sal_Bool bSetChartRangeLists )
254 {
255 	ScChartListenerCollection* pOld = pChartListenerCollection;
256 	pChartListenerCollection = pNewChartListenerCollection;
257 	if ( pChartListenerCollection )
258 	{
259 		if ( pOld )
260 			pChartListenerCollection->SetDiffDirty( *pOld, bSetChartRangeLists );
261 		pChartListenerCollection->StartAllListeners();
262 	}
263 	delete pOld;
264 }
265 
266 void ScDocument::SetScenario( SCTAB nTab, sal_Bool bFlag )
267 {
268 	if (ValidTab(nTab) && pTab[nTab])
269 		pTab[nTab]->SetScenario(bFlag);
270 }
271 
272 sal_Bool ScDocument::IsScenario( SCTAB nTab ) const
273 {
274     return ValidTab(nTab) && pTab[nTab] &&pTab[nTab]->IsScenario();
275 	//if (ValidTab(nTab) && pTab[nTab])
276 	//	return pTab[nTab]->IsScenario();
277 
278 	//return sal_False;
279 }
280 
281 void ScDocument::SetScenarioData( SCTAB nTab, const String& rComment,
282 										const Color& rColor, sal_uInt16 nFlags )
283 {
284 	if (ValidTab(nTab) && pTab[nTab] && pTab[nTab]->IsScenario())
285 	{
286 		pTab[nTab]->SetScenarioComment( rComment );
287 		pTab[nTab]->SetScenarioColor( rColor );
288 		pTab[nTab]->SetScenarioFlags( nFlags );
289 	}
290 }
291 
292 Color ScDocument::GetTabBgColor( SCTAB nTab ) const
293 {
294     if (ValidTab(nTab) && pTab[nTab])
295         return pTab[nTab]->GetTabBgColor();
296     return Color(COL_AUTO);
297 }
298 
299 void ScDocument::SetTabBgColor( SCTAB nTab, const Color& rColor )
300 {
301     if (ValidTab(nTab) && pTab[nTab])
302         pTab[nTab]->SetTabBgColor(rColor);
303 }
304 
305 bool ScDocument::IsDefaultTabBgColor( SCTAB nTab ) const
306 {
307     if (ValidTab(nTab) && pTab[nTab])
308         return pTab[nTab]->GetTabBgColor() == COL_AUTO;
309     return true;
310 }
311 
312 void ScDocument::GetScenarioData( SCTAB nTab, String& rComment,
313 										Color& rColor, sal_uInt16& rFlags ) const
314 {
315 	if (ValidTab(nTab) && pTab[nTab] && pTab[nTab]->IsScenario())
316 	{
317 		pTab[nTab]->GetScenarioComment( rComment );
318 		rColor = pTab[nTab]->GetScenarioColor();
319 		rFlags = pTab[nTab]->GetScenarioFlags();
320 	}
321 }
322 
323 void ScDocument::GetScenarioFlags( SCTAB nTab, sal_uInt16& rFlags ) const
324 {
325     if (VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->IsScenario())
326         rFlags = pTab[nTab]->GetScenarioFlags();
327 }
328 
329 sal_Bool ScDocument::IsLinked( SCTAB nTab ) const
330 {
331     return ValidTab(nTab) && pTab[nTab] && pTab[nTab]->IsLinked();
332     // euqivalent to
333 	//if (ValidTab(nTab) && pTab[nTab])
334 	//	return pTab[nTab]->IsLinked();
335 	//return sal_False;
336 }
337 
338 formula::FormulaGrammar::AddressConvention ScDocument::GetAddressConvention() const
339 {
340     return formula::FormulaGrammar::extractRefConvention(eGrammar);
341 }
342 
343 formula::FormulaGrammar::Grammar ScDocument::GetGrammar() const
344 {
345     return eGrammar;
346 }
347 
348 void ScDocument::SetGrammar( formula::FormulaGrammar::Grammar eGram )
349 {
350     eGrammar = eGram;
351 }
352 
353 sal_Bool ScDocument::GetLinkMode( SCTAB nTab ) const
354 {
355 	if (ValidTab(nTab) && pTab[nTab])
356 		return pTab[nTab]->GetLinkMode();
357 	return SC_LINK_NONE;
358 }
359 
360 const String& ScDocument::GetLinkDoc( SCTAB nTab ) const
361 {
362 	if (ValidTab(nTab) && pTab[nTab])
363 		return pTab[nTab]->GetLinkDoc();
364 	return EMPTY_STRING;
365 }
366 
367 const String& ScDocument::GetLinkFlt( SCTAB nTab ) const
368 {
369 	if (ValidTab(nTab) && pTab[nTab])
370 		return pTab[nTab]->GetLinkFlt();
371 	return EMPTY_STRING;
372 }
373 
374 const String& ScDocument::GetLinkOpt( SCTAB nTab ) const
375 {
376 	if (ValidTab(nTab) && pTab[nTab])
377 		return pTab[nTab]->GetLinkOpt();
378 	return EMPTY_STRING;
379 }
380 
381 const String& ScDocument::GetLinkTab( SCTAB nTab ) const
382 {
383 	if (ValidTab(nTab) && pTab[nTab])
384 		return pTab[nTab]->GetLinkTab();
385 	return EMPTY_STRING;
386 }
387 
388 sal_uLong ScDocument::GetLinkRefreshDelay( SCTAB nTab ) const
389 {
390 	if (ValidTab(nTab) && pTab[nTab])
391 		return pTab[nTab]->GetLinkRefreshDelay();
392 	return 0;
393 }
394 
395 void ScDocument::SetLink( SCTAB nTab, sal_uInt8 nMode, const String& rDoc,
396 							const String& rFilter, const String& rOptions,
397 							const String& rTabName, sal_uLong nRefreshDelay )
398 {
399 	if (ValidTab(nTab) && pTab[nTab])
400 		pTab[nTab]->SetLink( nMode, rDoc, rFilter, rOptions, rTabName, nRefreshDelay );
401 }
402 
403 sal_Bool ScDocument::HasLink( const String& rDoc,
404 							const String& rFilter, const String& rOptions ) const
405 {
406 	SCTAB nCount = GetTableCount();
407 	for (SCTAB i=0; i<nCount; i++)
408 		if (pTab[i]->IsLinked()
409 				&& pTab[i]->GetLinkDoc() == rDoc
410 				&& pTab[i]->GetLinkFlt() == rFilter
411 				&& pTab[i]->GetLinkOpt() == rOptions)
412 			return sal_True;
413 
414 	return sal_False;
415 }
416 
417 sal_Bool ScDocument::LinkExternalTab( SCTAB& rTab, const String& aDocTab,
418 		const String& aFileName, const String& aTabName )
419 {
420 	if ( IsClipboard() )
421 	{
422 		DBG_ERRORFILE( "LinkExternalTab in Clipboard" );
423 		return sal_False;
424 	}
425 	rTab = 0;
426 	String	aFilterName;		// wird vom Loader gefuellt
427 	String	aOptions;		// Filter-Optionen
428     sal_uInt32 nLinkCnt = pExtDocOptions ? pExtDocOptions->GetDocSettings().mnLinkCnt : 0;
429     ScDocumentLoader aLoader( aFileName, aFilterName, aOptions, nLinkCnt + 1 );
430 	if ( aLoader.IsError() )
431 		return sal_False;
432 	ScDocument* pSrcDoc = aLoader.GetDocument();
433 
434 	//	Tabelle kopieren
435 	SCTAB nSrcTab;
436 	if ( pSrcDoc->GetTable( aTabName, nSrcTab ) )
437 	{
438 		if ( !InsertTab( SC_TAB_APPEND, aDocTab, sal_True ) )
439 		{
440 			DBG_ERRORFILE("can't insert external document table");
441 			return sal_False;
442 		}
443 		rTab = GetTableCount() - 1;
444 		// nicht neu einfuegen, nur Ergebnisse
445 		TransferTab( pSrcDoc, nSrcTab, rTab, sal_False, sal_True );
446 	}
447 	else
448 		return sal_False;
449 
450 	sal_uLong nRefreshDelay = 0;
451 
452 	sal_Bool bWasThere = HasLink( aFileName, aFilterName, aOptions );
453 	SetLink( rTab, SC_LINK_VALUE, aFileName, aFilterName, aOptions, aTabName, nRefreshDelay );
454 	if ( !bWasThere )		// Link pro Quelldokument nur einmal eintragen
455 	{
456 		ScTableLink* pLink = new ScTableLink( pShell, aFileName, aFilterName, aOptions, nRefreshDelay );
457 		pLink->SetInCreate( sal_True );
458 		GetLinkManager()->InsertFileLink( *pLink, OBJECT_CLIENT_FILE, aFileName,
459 										&aFilterName );
460 		pLink->Update();
461 		pLink->SetInCreate( sal_False );
462 		SfxBindings* pBindings = GetViewBindings();
463 		if (pBindings)
464 			pBindings->Invalidate( SID_LINKS );
465 	}
466 	return sal_True;
467 }
468 
469 ScExternalRefManager* ScDocument::GetExternalRefManager() const
470 {
471     ScDocument* pThis = const_cast<ScDocument*>(this);
472     if (!pExternalRefMgr.get())
473         pThis->pExternalRefMgr.reset( new ScExternalRefManager( pThis));
474 
475     return pExternalRefMgr.get();
476 }
477 
478 bool ScDocument::IsInExternalReferenceMarking() const
479 {
480     return pExternalRefMgr.get() && pExternalRefMgr->isInReferenceMarking();
481 }
482 
483 void ScDocument::MarkUsedExternalReferences()
484 {
485     if (!pExternalRefMgr.get())
486         return;
487     if (!pExternalRefMgr->hasExternalData())
488         return;
489     // Charts.
490     bool bAllMarked = pExternalRefMgr->markUsedByLinkListeners();
491     // Formula cells.
492 	bAllMarked = pExternalRefMgr->markUsedExternalRefCells();
493 
494     /* NOTE: Conditional formats and validation objects are marked when
495      * collecting them during export. */
496 }
497 
498 ScFormulaParserPool& ScDocument::GetFormulaParserPool() const
499 {
500     if( !mxFormulaParserPool.get() )
501         mxFormulaParserPool.reset( new ScFormulaParserPool( *this ) );
502     return *mxFormulaParserPool;
503 }
504 
505 const ScSheetEvents* ScDocument::GetSheetEvents( SCTAB nTab ) const
506 {
507     if (VALIDTAB(nTab) && pTab[nTab])
508         return pTab[nTab]->GetSheetEvents();
509     return NULL;
510 }
511 
512 void ScDocument::SetSheetEvents( SCTAB nTab, const ScSheetEvents* pNew )
513 {
514     if (VALIDTAB(nTab) && pTab[nTab])
515         pTab[nTab]->SetSheetEvents( pNew );
516 }
517 
518 bool ScDocument::HasSheetEventScript( SCTAB nTab, sal_Int32 nEvent, bool bWithVbaEvents ) const
519 {
520     if (pTab[nTab])
521     {
522         // check if any event handler script has been configured
523         const ScSheetEvents* pEvents = pTab[nTab]->GetSheetEvents();
524         if ( pEvents && pEvents->GetScript( nEvent ) )
525             return true;
526         // check if VBA event handlers exist
527         if (bWithVbaEvents && mxVbaEvents.is()) try
528         {
529             uno::Sequence< uno::Any > aArgs( 1 );
530             aArgs[ 0 ] <<= nTab;
531             if (mxVbaEvents->hasVbaEventHandler( ScSheetEvents::GetVbaSheetEventId( nEvent ), aArgs ) ||
532                 mxVbaEvents->hasVbaEventHandler( ScSheetEvents::GetVbaDocumentEventId( nEvent ), uno::Sequence< uno::Any >() ))
533                 return true;
534         }
535         catch( uno::Exception& )
536         {
537         }
538     }
539     return false;
540 }
541 
542 bool ScDocument::HasAnySheetEventScript( sal_Int32 nEvent, bool bWithVbaEvents ) const
543 {
544     for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
545         if (HasSheetEventScript( nTab, nEvent, bWithVbaEvents ))
546             return true;
547     return false;
548 }
549 
550 bool ScDocument::HasAnyCalcNotification() const
551 {
552     for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
553         if (pTab[nTab] && pTab[nTab]->GetCalcNotification())
554             return true;
555     return false;
556 }
557 
558 sal_Bool ScDocument::HasCalcNotification( SCTAB nTab ) const
559 {
560     if (VALIDTAB(nTab) && pTab[nTab])
561         return pTab[nTab]->GetCalcNotification();
562     return sal_False;
563 }
564 
565 void ScDocument::SetCalcNotification( SCTAB nTab )
566 {
567     // set only if not set before
568     if (VALIDTAB(nTab) && pTab[nTab] && !pTab[nTab]->GetCalcNotification())
569         pTab[nTab]->SetCalcNotification(sal_True);
570 }
571 
572 void ScDocument::ResetCalcNotifications()
573 {
574     for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
575         if (pTab[nTab] && pTab[nTab]->GetCalcNotification())
576             pTab[nTab]->SetCalcNotification(sal_False);
577 }
578 
579 ScOutlineTable* ScDocument::GetOutlineTable( SCTAB nTab, sal_Bool bCreate )
580 {
581 	ScOutlineTable* pVal = NULL;
582 
583 	if (VALIDTAB(nTab))
584 		if (pTab[nTab])
585 		{
586 			pVal = pTab[nTab]->GetOutlineTable();
587 			if (!pVal)
588 				if (bCreate)
589 				{
590 					pTab[nTab]->StartOutlineTable();
591 					pVal = pTab[nTab]->GetOutlineTable();
592 				}
593 		}
594 
595 	return pVal;
596 }
597 
598 sal_Bool ScDocument::SetOutlineTable( SCTAB nTab, const ScOutlineTable* pNewOutline )
599 {
600     return VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->SetOutlineTable(pNewOutline);
601 	//if (VALIDTAB(nTab))
602 	//	if (pTab[nTab])
603 	//		return pTab[nTab]->SetOutlineTable(pNewOutline);
604 
605 	//return sal_False;
606 }
607 
608 void ScDocument::DoAutoOutline( SCCOL nStartCol, SCROW nStartRow,
609 								SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
610 {
611 	if (VALIDTAB(nTab) && pTab[nTab])
612 	    pTab[nTab]->DoAutoOutline( nStartCol, nStartRow, nEndCol, nEndRow );
613 }
614 
615 sal_Bool ScDocument::TestRemoveSubTotals( SCTAB nTab, const ScSubTotalParam& rParam )
616 {
617     return VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->TestRemoveSubTotals( rParam );
618 	//if (VALIDTAB(nTab) && pTab[nTab] )
619 	//	return pTab[nTab]->TestRemoveSubTotals( rParam );
620 
621 	//return sal_False;
622 }
623 
624 void ScDocument::RemoveSubTotals( SCTAB nTab, ScSubTotalParam& rParam )
625 {
626 	if ( VALIDTAB(nTab) && pTab[nTab] )
627 		pTab[nTab]->RemoveSubTotals( rParam );
628 }
629 
630 sal_Bool ScDocument::DoSubTotals( SCTAB nTab, ScSubTotalParam& rParam )
631 {
632     return VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->DoSubTotals( rParam );
633 	//if (VALIDTAB(nTab))
634 	//	if (pTab[nTab])
635 	//		return pTab[nTab]->DoSubTotals( rParam );
636 
637 	//return sal_False;
638 }
639 
640 sal_Bool ScDocument::HasSubTotalCells( const ScRange& rRange )
641 {
642 	ScCellIterator aIter( this, rRange );
643 	ScBaseCell* pCell = aIter.GetFirst();
644 	while (pCell)
645 	{
646 		if ( pCell->GetCellType() == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell)->IsSubTotal() )
647 			return sal_True;
648 
649 		pCell = aIter.GetNext();
650 	}
651 	return sal_False;	// none found
652 }
653 
654 //	kopiert aus diesem Dokument die Zellen von Positionen, an denen in pPosDoc
655 //	auch Zellen stehen, nach pDestDoc
656 
657 void ScDocument::CopyUpdated( ScDocument* pPosDoc, ScDocument* pDestDoc )
658 {
659 	SCTAB nCount = GetTableCount();
660 	for (SCTAB nTab=0; nTab<nCount; nTab++)
661 		if (pTab[nTab] && pPosDoc->pTab[nTab] && pDestDoc->pTab[nTab])
662 			pTab[nTab]->CopyUpdated( pPosDoc->pTab[nTab], pDestDoc->pTab[nTab] );
663 }
664 
665 void ScDocument::CopyScenario( SCTAB nSrcTab, SCTAB nDestTab, sal_Bool bNewScenario )
666 {
667 	if (ValidTab(nSrcTab) && ValidTab(nDestTab) && pTab[nSrcTab] && pTab[nDestTab])
668 	{
669 		//	Flags fuer aktive Szenarios richtig setzen
670 		//	und aktuelle Werte in bisher aktive Szenarios zurueckschreiben
671 
672 		ScRangeList aRanges = *pTab[nSrcTab]->GetScenarioRanges();
673 		const sal_uLong nRangeCount = aRanges.Count();
674 
675 		//	nDestTab ist die Zieltabelle
676 		for ( SCTAB nTab = nDestTab+1;
677 				nTab<=MAXTAB && pTab[nTab] && pTab[nTab]->IsScenario();
678 				nTab++ )
679 		{
680 			if ( pTab[nTab]->IsActiveScenario() )		// auch wenn's dasselbe Szenario ist
681 			{
682 				sal_Bool bTouched = sal_False;
683 				for ( sal_uLong nR=0; nR<nRangeCount && !bTouched; nR++)
684 				{
685 					const ScRange* pRange = aRanges.GetObject(nR);
686 					if ( pTab[nTab]->HasScenarioRange( *pRange ) )
687 						bTouched = sal_True;
688 				}
689 				if (bTouched)
690 				{
691 					pTab[nTab]->SetActiveScenario(sal_False);
692 					if ( pTab[nTab]->GetScenarioFlags() & SC_SCENARIO_TWOWAY )
693 						pTab[nTab]->CopyScenarioFrom( pTab[nDestTab] );
694 				}
695 			}
696 		}
697 
698 		pTab[nSrcTab]->SetActiveScenario(sal_True);		// da kommt's her...
699 		if (!bNewScenario)							// Daten aus dem ausgewaehlten Szenario kopieren
700 		{
701 			sal_Bool bOldAutoCalc = GetAutoCalc();
702 			SetAutoCalc( sal_False );	// Mehrfachberechnungen vermeiden
703 			pTab[nSrcTab]->CopyScenarioTo( pTab[nDestTab] );
704 			SetDirty();
705 			SetAutoCalc( bOldAutoCalc );
706 		}
707 	}
708 }
709 
710 void ScDocument::MarkScenario( SCTAB nSrcTab, SCTAB nDestTab, ScMarkData& rDestMark,
711 								sal_Bool bResetMark, sal_uInt16 nNeededBits ) const
712 {
713 	if (bResetMark)
714 		rDestMark.ResetMark();
715 
716 	if (ValidTab(nSrcTab) && pTab[nSrcTab])
717 		pTab[nSrcTab]->MarkScenarioIn( rDestMark, nNeededBits );
718 
719 	rDestMark.SetAreaTab( nDestTab );
720 }
721 
722 sal_Bool ScDocument::HasScenarioRange( SCTAB nTab, const ScRange& rRange ) const
723 {
724     return ValidTab(nTab) && pTab[nTab] && pTab[nTab]->HasScenarioRange( rRange );
725 	//if (ValidTab(nTab) && pTab[nTab])
726 	//	return pTab[nTab]->HasScenarioRange( rRange );
727 
728 	//return sal_False;
729 }
730 
731 const ScRangeList* ScDocument::GetScenarioRanges( SCTAB nTab ) const
732 {
733 	if (ValidTab(nTab) && pTab[nTab])
734 		return pTab[nTab]->GetScenarioRanges();
735 
736 	return NULL;
737 }
738 
739 sal_Bool ScDocument::IsActiveScenario( SCTAB nTab ) const
740 {
741     return ValidTab(nTab) && pTab[nTab] && pTab[nTab]->IsActiveScenario(  );
742 	//if (ValidTab(nTab) && pTab[nTab])
743 	//	return pTab[nTab]->IsActiveScenario();
744 
745 	//return sal_False;
746 }
747 
748 void ScDocument::SetActiveScenario( SCTAB nTab, sal_Bool bActive )
749 {
750 	if (ValidTab(nTab) && pTab[nTab])
751 		pTab[nTab]->SetActiveScenario( bActive );
752 }
753 
754 sal_Bool ScDocument::TestCopyScenario( SCTAB nSrcTab, SCTAB nDestTab ) const
755 {
756 	if (ValidTab(nSrcTab) && ValidTab(nDestTab))
757 		return pTab[nSrcTab]->TestCopyScenarioTo( pTab[nDestTab] );
758 
759 	DBG_ERROR("falsche Tabelle bei TestCopyScenario");
760 	return sal_False;
761 }
762 
763 void ScDocument::AddUnoObject( SfxListener& rObject )
764 {
765 	if (!pUnoBroadcaster)
766 		pUnoBroadcaster = new SfxBroadcaster;
767 
768 	rObject.StartListening( *pUnoBroadcaster );
769 }
770 
771 void ScDocument::RemoveUnoObject( SfxListener& rObject )
772 {
773 	if (pUnoBroadcaster)
774 	{
775 		rObject.EndListening( *pUnoBroadcaster );
776 
777 		if ( bInUnoBroadcast )
778 		{
779 			//	#107294# Broadcasts from ScDocument::BroadcastUno are the only way that
780 			//	uno object methods are called without holding a reference.
781 			//
782 			//	If RemoveUnoObject is called from an object dtor in the finalizer thread
783 			//	while the main thread is calling BroadcastUno, the dtor thread must wait
784 			//	(or the object's Notify might try to access a deleted object).
785 			//	The SolarMutex can't be locked here because if a component is called from
786 			//	a VCL event, the main thread has the SolarMutex locked all the time.
787 			//
788 			//	This check is done after calling EndListening, so a later BroadcastUno call
789 			//	won't touch this object.
790 
791 			vos::IMutex& rSolarMutex = Application::GetSolarMutex();
792 			if ( rSolarMutex.tryToAcquire() )
793 			{
794 				//	BroadcastUno is always called with the SolarMutex locked, so if it
795 				//	can be acquired, this is within the same thread (should not happen)
796 				DBG_ERRORFILE( "RemoveUnoObject called from BroadcastUno" );
797 				rSolarMutex.release();
798 			}
799 			else
800 			{
801 				//	let the thread that called BroadcastUno continue
802 				while ( bInUnoBroadcast )
803 				{
804 					vos::OThread::yield();
805 				}
806 			}
807 		}
808 	}
809 	else
810 	{
811 		DBG_ERROR("No Uno broadcaster");
812 	}
813 }
814 
815 void ScDocument::BroadcastUno( const SfxHint &rHint )
816 {
817 	if (pUnoBroadcaster)
818 	{
819 		bInUnoBroadcast = sal_True;
820 		pUnoBroadcaster->Broadcast( rHint );
821 		bInUnoBroadcast = sal_False;
822 
823 		// During Broadcast notification, Uno objects can add to pUnoListenerCalls.
824 		// The listener calls must be processed after completing the broadcast,
825 		// because they can add or remove objects from pUnoBroadcaster.
826 
827 		if ( pUnoListenerCalls && rHint.ISA( SfxSimpleHint ) &&
828 				((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DATACHANGED &&
829 				!bInUnoListenerCall )
830 		{
831 			// Listener calls may lead to BroadcastUno calls again. The listener calls
832 			// are not nested, instead the calls are collected in the list, and the
833 			// outermost call executes them all.
834 
835             ScChartLockGuard aChartLockGuard(this);
836 			bInUnoListenerCall = sal_True;
837 			pUnoListenerCalls->ExecuteAndClear();
838 			bInUnoListenerCall = sal_False;
839 		}
840 	}
841 }
842 
843 void ScDocument::AddUnoListenerCall( const uno::Reference<util::XModifyListener>& rListener,
844 										const lang::EventObject& rEvent )
845 {
846 	DBG_ASSERT( bInUnoBroadcast, "AddUnoListenerCall is supposed to be called from BroadcastUno only" );
847 
848 	if ( !pUnoListenerCalls )
849 		pUnoListenerCalls = new ScUnoListenerCalls;
850 	pUnoListenerCalls->Add( rListener, rEvent );
851 }
852 
853 void ScDocument::BeginUnoRefUndo()
854 {
855     DBG_ASSERT( !pUnoRefUndoList, "BeginUnoRefUndo twice" );
856     delete pUnoRefUndoList;
857 
858     pUnoRefUndoList = new ScUnoRefList;
859 }
860 
861 ScUnoRefList* ScDocument::EndUnoRefUndo()
862 {
863     ScUnoRefList* pRet = pUnoRefUndoList;
864     pUnoRefUndoList = NULL;
865     return pRet;                // must be deleted by caller!
866 }
867 
868 void ScDocument::AddUnoRefChange( sal_Int64 nId, const ScRangeList& rOldRanges )
869 {
870     if ( pUnoRefUndoList )
871         pUnoRefUndoList->Add( nId, rOldRanges );
872 }
873 
874 sal_Int64 ScDocument::GetNewUnoId()
875 {
876     return ++nUnoObjectId;
877 }
878 
879 void ScDocument::UpdateReference( UpdateRefMode eUpdateRefMode,
880 									SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
881 									SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
882 									SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
883 									ScDocument* pUndoDoc, sal_Bool bIncludeDraw,
884                                     bool bUpdateNoteCaptionPos )
885 {
886 	PutInOrder( nCol1, nCol2 );
887 	PutInOrder( nRow1, nRow2 );
888 	PutInOrder( nTab1, nTab2 );
889 	if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
890 	{
891 		sal_Bool bExpandRefsOld = IsExpandRefs();
892 		if ( eUpdateRefMode == URM_INSDEL && (nDx > 0 || nDy > 0 || nDz > 0) )
893 			SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() );
894 		SCTAB i;
895 		SCTAB iMax;
896 		if ( eUpdateRefMode == URM_COPY )
897 		{
898 			i = nTab1;
899 			iMax = nTab2;
900 		}
901 		else
902 		{
903 			ScRange aRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
904 			xColNameRanges->UpdateReference( eUpdateRefMode, this, aRange, nDx, nDy, nDz );
905 			xRowNameRanges->UpdateReference( eUpdateRefMode, this, aRange, nDx, nDy, nDz );
906 			pDBCollection->UpdateReference( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz );
907 			pRangeName->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
908 			if ( pDPCollection )
909 				pDPCollection->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
910 			UpdateChartRef( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz );
911 			UpdateRefAreaLinks( eUpdateRefMode, aRange, nDx, nDy, nDz );
912 			if ( pCondFormList )
913 				pCondFormList->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
914 			if ( pValidationList )
915 				pValidationList->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
916 			if ( pDetOpList )
917 				pDetOpList->UpdateReference( this, eUpdateRefMode, aRange, nDx, nDy, nDz );
918 			if ( pUnoBroadcaster )
919 				pUnoBroadcaster->Broadcast( ScUpdateRefHint(
920 									eUpdateRefMode, aRange, nDx, nDy, nDz ) );
921 			i = 0;
922 			iMax = MAXTAB;
923 		}
924 		for ( ; i<=iMax; i++)
925 			if (pTab[i])
926 				pTab[i]->UpdateReference(
927 					eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2,
928 					nDx, nDy, nDz, pUndoDoc, bIncludeDraw, bUpdateNoteCaptionPos );
929 
930 		if ( bIsEmbedded )
931 		{
932             SCCOL theCol1;
933             SCROW theRow1;
934             SCTAB theTab1;
935             SCCOL theCol2;
936             SCROW theRow2;
937             SCTAB theTab2;
938 			theCol1 = aEmbedRange.aStart.Col();
939 			theRow1 = aEmbedRange.aStart.Row();
940 			theTab1 = aEmbedRange.aStart.Tab();
941 			theCol2 = aEmbedRange.aEnd.Col();
942 			theRow2 = aEmbedRange.aEnd.Row();
943 			theTab2 = aEmbedRange.aEnd.Tab();
944 			if ( ScRefUpdate::Update( this, eUpdateRefMode, nCol1,nRow1,nTab1, nCol2,nRow2,nTab2,
945 										nDx,nDy,nDz, theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) )
946 			{
947 				aEmbedRange = ScRange( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
948 			}
949 		}
950 		SetExpandRefs( bExpandRefsOld );
951 
952 		// #30428# after moving, no clipboard move ref-updates are possible
953 		if ( eUpdateRefMode != URM_COPY && IsClipboardSource() )
954 		{
955 			ScDocument* pClipDoc = SC_MOD()->GetClipDoc();
956 			if (pClipDoc)
957 				pClipDoc->GetClipParam().mbCutMode = false;
958 		}
959 	}
960 }
961 
962 void ScDocument::UpdateTranspose( const ScAddress& rDestPos, ScDocument* pClipDoc,
963 										const ScMarkData& rMark, ScDocument* pUndoDoc )
964 {
965 	DBG_ASSERT(pClipDoc->bIsClip, "UpdateTranspose: kein Clip");
966 
967     ScRange aSource;
968     ScClipParam& rClipParam = GetClipParam();
969     if (rClipParam.maRanges.Count())
970         aSource = *rClipParam.maRanges.First();
971 	ScAddress aDest = rDestPos;
972 
973 	SCTAB nClipTab = 0;
974 	for (SCTAB nDestTab=0; nDestTab<=MAXTAB && pTab[nDestTab]; nDestTab++)
975 		if (rMark.GetTableSelect(nDestTab))
976 		{
977 			while (!pClipDoc->pTab[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
978 			aSource.aStart.SetTab( nClipTab );
979 			aSource.aEnd.SetTab( nClipTab );
980 			aDest.SetTab( nDestTab );
981 
982 			//	wie UpdateReference
983 
984 			pRangeName->UpdateTranspose( aSource, aDest );		// vor den Zellen!
985 			for (SCTAB i=0; i<=MAXTAB; i++)
986 				if (pTab[i])
987 					pTab[i]->UpdateTranspose( aSource, aDest, pUndoDoc );
988 
989 			nClipTab = (nClipTab+1) % (MAXTAB+1);
990 		}
991 }
992 
993 void ScDocument::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
994 {
995 	//!	pDBCollection
996 	//!	pPivotCollection
997 	//!	UpdateChartRef
998 
999 	pRangeName->UpdateGrow( rArea, nGrowX, nGrowY );
1000 
1001 	for (SCTAB i=0; i<=MAXTAB && pTab[i]; i++)
1002 		pTab[i]->UpdateGrow( rArea, nGrowX, nGrowY );
1003 }
1004 
1005 void ScDocument::Fill(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const ScMarkData& rMark,
1006 						sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
1007 						double nStepValue, double nMaxValue)
1008 {
1009 	PutInOrder( nCol1, nCol2 );
1010 	PutInOrder( nRow1, nRow2 );
1011 	for (SCTAB i=0; i <= MAXTAB; i++)
1012 		if (pTab[i])
1013 			if (rMark.GetTableSelect(i))
1014 				pTab[i]->Fill(nCol1, nRow1, nCol2, nRow2,
1015 								nFillCount, eFillDir, eFillCmd, eFillDateCmd,
1016 								nStepValue, nMaxValue);
1017 }
1018 
1019 String ScDocument::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW nEndY )
1020 {
1021 	SCTAB nTab = rSource.aStart.Tab();
1022 	if (pTab[nTab])
1023 		return pTab[nTab]->GetAutoFillPreview( rSource, nEndX, nEndY );
1024 
1025 	return EMPTY_STRING;
1026 }
1027 
1028 void ScDocument::AutoFormat( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1029 									sal_uInt16 nFormatNo, const ScMarkData& rMark )
1030 {
1031 	PutInOrder( nStartCol, nEndCol );
1032 	PutInOrder( nStartRow, nEndRow );
1033 	for (SCTAB i=0; i <= MAXTAB; i++)
1034 		if (pTab[i])
1035 			if (rMark.GetTableSelect(i))
1036 				pTab[i]->AutoFormat( nStartCol, nStartRow, nEndCol, nEndRow, nFormatNo );
1037 }
1038 
1039 void ScDocument::GetAutoFormatData(SCTAB nTab, SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1040 									ScAutoFormatData& rData)
1041 {
1042 	if (VALIDTAB(nTab))
1043 	{
1044 		if (pTab[nTab])
1045 		{
1046 			PutInOrder(nStartCol, nEndCol);
1047 			PutInOrder(nStartRow, nEndRow);
1048 			pTab[nTab]->GetAutoFormatData(nStartCol, nStartRow, nEndCol, nEndRow, rData);
1049 		}
1050 	}
1051 }
1052 
1053 // static
1054 void ScDocument::GetSearchAndReplaceStart( const SvxSearchItem& rSearchItem,
1055 		SCCOL& rCol, SCROW& rRow )
1056 {
1057 	sal_uInt16 nCommand = rSearchItem.GetCommand();
1058 	sal_Bool bReplace = ( nCommand == SVX_SEARCHCMD_REPLACE ||
1059 		nCommand == SVX_SEARCHCMD_REPLACE_ALL );
1060 	if ( rSearchItem.GetBackward() )
1061 	{
1062 		if ( rSearchItem.GetRowDirection() )
1063 		{
1064 			if ( rSearchItem.GetPattern() )
1065 			{
1066 				rCol = MAXCOL;
1067 				rRow = MAXROW+1;
1068 			}
1069 			else if ( bReplace )
1070 			{
1071 				rCol = MAXCOL;
1072 				rRow = MAXROW;
1073 			}
1074 			else
1075 			{
1076 				rCol = MAXCOL+1;
1077 				rRow = MAXROW;
1078 			}
1079 		}
1080 		else
1081 		{
1082 			if ( rSearchItem.GetPattern() )
1083 			{
1084 				rCol = MAXCOL+1;
1085 				rRow = MAXROW;
1086 			}
1087 			else if ( bReplace )
1088 			{
1089 				rCol = MAXCOL;
1090 				rRow = MAXROW;
1091 			}
1092 			else
1093 			{
1094 				rCol = MAXCOL;
1095 				rRow = MAXROW+1;
1096 			}
1097 		}
1098 	}
1099 	else
1100 	{
1101 		if ( rSearchItem.GetRowDirection() )
1102 		{
1103 			if ( rSearchItem.GetPattern() )
1104 			{
1105 				rCol = 0;
1106 				rRow = (SCROW) -1;
1107 			}
1108 			else if ( bReplace )
1109 			{
1110 				rCol = 0;
1111 				rRow = 0;
1112 			}
1113 			else
1114 			{
1115 				rCol = (SCCOL) -1;
1116 				rRow = 0;
1117 			}
1118 		}
1119 		else
1120 		{
1121 			if ( rSearchItem.GetPattern() )
1122 			{
1123 				rCol = (SCCOL) -1;
1124 				rRow = 0;
1125 			}
1126 			else if ( bReplace )
1127 			{
1128 				rCol = 0;
1129 				rRow = 0;
1130 			}
1131 			else
1132 			{
1133 				rCol = 0;
1134 				rRow = (SCROW) -1;
1135 			}
1136 		}
1137 	}
1138 }
1139 
1140 sal_Bool ScDocument::SearchAndReplace(const SvxSearchItem& rSearchItem,
1141 								SCCOL& rCol, SCROW& rRow, SCTAB& rTab,
1142 								ScMarkData& rMark,
1143 								String& rUndoStr, ScDocument* pUndoDoc)
1144 {
1145 	//!		getrennte Markierungen pro Tabelle verwalten !!!!!!!!!!!!!
1146 
1147 	rMark.MarkToMulti();
1148 
1149 	sal_Bool bFound = sal_False;
1150 	if (VALIDTAB(rTab))
1151 	{
1152 		SCCOL nCol;
1153 		SCROW nRow;
1154 		SCTAB nTab;
1155 		sal_uInt16 nCommand = rSearchItem.GetCommand();
1156 		if ( nCommand == SVX_SEARCHCMD_FIND_ALL ||
1157 			 nCommand == SVX_SEARCHCMD_REPLACE_ALL )
1158 		{
1159 			for (nTab = 0; nTab <= MAXTAB; nTab++)
1160 				if (pTab[nTab])
1161 				{
1162 					if (rMark.GetTableSelect(nTab))
1163 					{
1164 						nCol = 0;
1165 						nRow = 0;
1166 						bFound |= pTab[nTab]->SearchAndReplace(
1167 									rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc );
1168 					}
1169 				}
1170 
1171 			//	Markierung wird innen schon komplett gesetzt
1172 		}
1173 		else
1174 		{
1175 			nCol = rCol;
1176 			nRow = rRow;
1177 			if (rSearchItem.GetBackward())
1178 			{
1179 				for (nTab = rTab; ((SCsTAB)nTab >= 0) && !bFound; nTab--)
1180 					if (pTab[nTab])
1181 					{
1182 						if (rMark.GetTableSelect(nTab))
1183 						{
1184 							bFound = pTab[nTab]->SearchAndReplace(
1185 										rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc );
1186 							if (bFound)
1187 							{
1188 								rCol = nCol;
1189 								rRow = nRow;
1190 								rTab = nTab;
1191 							}
1192 							else
1193 								ScDocument::GetSearchAndReplaceStart(
1194 									rSearchItem, nCol, nRow );
1195 						}
1196 					}
1197 			}
1198 			else
1199 			{
1200 				for (nTab = rTab; (nTab <= MAXTAB) && !bFound; nTab++)
1201 					if (pTab[nTab])
1202 					{
1203 						if (rMark.GetTableSelect(nTab))
1204 						{
1205 							bFound = pTab[nTab]->SearchAndReplace(
1206 										rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc );
1207 							if (bFound)
1208 							{
1209 								rCol = nCol;
1210 								rRow = nRow;
1211 								rTab = nTab;
1212 							}
1213 							else
1214 								ScDocument::GetSearchAndReplaceStart(
1215 									rSearchItem, nCol, nRow );
1216 						}
1217 					}
1218 			}
1219 		}
1220 	}
1221 	return bFound;
1222 }
1223 
1224 //	Outline anpassen
1225 
1226 sal_Bool ScDocument::UpdateOutlineCol( SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, sal_Bool bShow )
1227 {
1228 	if ( ValidTab(nTab) && pTab[nTab] )
1229 		return pTab[nTab]->UpdateOutlineCol( nStartCol, nEndCol, bShow );
1230 
1231 	DBG_ERROR("missing tab");
1232 	return sal_False;
1233 }
1234 
1235 sal_Bool ScDocument::UpdateOutlineRow( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_Bool bShow )
1236 {
1237 	if ( ValidTab(nTab) && pTab[nTab] )
1238 		return pTab[nTab]->UpdateOutlineRow( nStartRow, nEndRow, bShow );
1239 
1240 	DBG_ERROR("missing tab");
1241 	return sal_False;
1242 }
1243 
1244 void ScDocument::Sort(SCTAB nTab, const ScSortParam& rSortParam, sal_Bool bKeepQuery)
1245 {
1246 	if ( ValidTab(nTab) && pTab[nTab] )
1247 	{
1248 		sal_Bool bOldDisableIdle = IsIdleDisabled();
1249 		DisableIdle( sal_True );
1250 		pTab[nTab]->Sort(rSortParam, bKeepQuery);
1251 		DisableIdle( bOldDisableIdle );
1252 	}
1253 }
1254 
1255 SCSIZE ScDocument::Query(SCTAB nTab, const ScQueryParam& rQueryParam, sal_Bool bKeepSub)
1256 {
1257 	if ( ValidTab(nTab) && pTab[nTab] )
1258 		return pTab[nTab]->Query((ScQueryParam&)rQueryParam, bKeepSub);
1259 
1260 	DBG_ERROR("missing tab");
1261 	return 0;
1262 }
1263 
1264 
1265 sal_Bool ScDocument::ValidQuery( SCROW nRow, SCTAB nTab, const ScQueryParam& rQueryParam, sal_Bool* pSpecial )
1266 {
1267 	if ( ValidTab(nTab) && pTab[nTab] )
1268 		return pTab[nTab]->ValidQuery( nRow, rQueryParam, pSpecial );
1269 
1270 	DBG_ERROR("missing tab");
1271 	return sal_False;
1272 }
1273 
1274 
1275 void ScDocument::GetUpperCellString(SCCOL nCol, SCROW nRow, SCTAB nTab, String& rStr)
1276 {
1277 	if ( ValidTab(nTab) && pTab[nTab] )
1278 		pTab[nTab]->GetUpperCellString( nCol, nRow, rStr );
1279 	else
1280 		rStr.Erase();
1281 }
1282 
1283 sal_Bool ScDocument::CreateQueryParam(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCTAB nTab, ScQueryParam& rQueryParam)
1284 {
1285 	if ( ValidTab(nTab) && pTab[nTab] )
1286 		return pTab[nTab]->CreateQueryParam(nCol1, nRow1, nCol2, nRow2, rQueryParam);
1287 
1288 	DBG_ERROR("missing tab");
1289 	return sal_False;
1290 }
1291 
1292 sal_Bool ScDocument::HasAutoFilter( SCCOL nCurCol, SCROW nCurRow, SCTAB nCurTab )
1293 {
1294 	ScDBData*		pDBData			= GetDBAtCursor( nCurCol, nCurRow, nCurTab );
1295 	sal_Bool			bHasAutoFilter	= ( pDBData != NULL );
1296 
1297 	if ( pDBData )
1298 	{
1299 		if ( pDBData->HasHeader() )
1300 		{
1301 			SCCOL nCol;
1302 			SCROW nRow;
1303 			sal_Int16  nFlag;
1304 
1305 			ScQueryParam aParam;
1306 			pDBData->GetQueryParam( aParam );
1307 			nRow = aParam.nRow1;
1308 
1309 			for ( nCol=aParam.nCol1; nCol<=aParam.nCol2 && bHasAutoFilter; nCol++ )
1310 			{
1311 				nFlag = ((ScMergeFlagAttr*)
1312 							GetAttr( nCol, nRow, nCurTab, ATTR_MERGE_FLAG ))->
1313 								GetValue();
1314 
1315 				if ( (nFlag & SC_MF_AUTO) == 0 )
1316 					bHasAutoFilter = sal_False;
1317 			}
1318 		}
1319 		else
1320 			bHasAutoFilter = sal_False;
1321 	}
1322 
1323 	return bHasAutoFilter;
1324 }
1325 
1326 sal_Bool ScDocument::HasColHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1327 									SCTAB nTab )
1328 {
1329     return VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->HasColHeader( nStartCol, nStartRow, nEndCol, nEndRow );
1330 	//if (VALIDTAB(nTab))
1331 	//	if (pTab[nTab])
1332 	//		return pTab[nTab]->HasColHeader( nStartCol, nStartRow, nEndCol, nEndRow );
1333 
1334 	//return sal_False;
1335 }
1336 
1337 sal_Bool ScDocument::HasRowHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1338 									SCTAB nTab )
1339 {
1340     return VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->HasRowHeader( nStartCol, nStartRow, nEndCol, nEndRow );
1341 	//if (VALIDTAB(nTab))
1342 	//	if (pTab[nTab])
1343 	//		return pTab[nTab]->HasRowHeader( nStartCol, nStartRow, nEndCol, nEndRow );
1344 
1345 	//return sal_False;
1346 }
1347 
1348 //
1349 //	GetFilterEntries - Eintraege fuer AutoFilter-Listbox
1350 //
1351 
1352 sal_Bool ScDocument::GetFilterEntries(
1353     SCCOL nCol, SCROW nRow, SCTAB nTab, bool bFilter, TypedScStrCollection& rStrings, bool& rHasDates)
1354 {
1355 	if ( ValidTab(nTab) && pTab[nTab] && pDBCollection )
1356 	{
1357 		ScDBData* pDBData = pDBCollection->GetDBAtCursor(nCol, nRow, nTab, sal_False);	//!??
1358 		if (pDBData)
1359 		{
1360 			SCTAB nAreaTab;
1361 			SCCOL nStartCol;
1362 			SCROW nStartRow;
1363 			SCCOL nEndCol;
1364 			SCROW nEndRow;
1365 			pDBData->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow );
1366 
1367 		//Add for i85305
1368 			SCCOL nTmpStartCol = nCol;
1369             SCROW nTmpStartRow = nRow;
1370 			SCCOL nTmpEndCol = nCol;
1371             SCROW nTmpEndRow = nRow;
1372 			GetDataArea( nTab, nTmpStartCol, nTmpStartRow, nTmpEndCol, nTmpEndRow, sal_False, false);
1373 			if (nTmpEndRow > nEndRow)
1374 			{
1375 				nEndRow = nTmpEndRow;
1376 				pDBData->SetArea(nAreaTab, nStartCol,nStartRow, nEndCol,nEndRow);
1377 			}
1378 		//End of i85305
1379 
1380 			if (pDBData->HasHeader())
1381 				++nStartRow;
1382 
1383 			ScQueryParam aParam;
1384 			pDBData->GetQueryParam( aParam );
1385 			rStrings.SetCaseSensitive( aParam.bCaseSens );
1386 
1387             // return all filter entries, if a filter condition is connected with a boolean OR
1388             if ( bFilter )
1389             {
1390                 SCSIZE nEntryCount = aParam.GetEntryCount();
1391                 for ( SCSIZE i = 0; i < nEntryCount && aParam.GetEntry(i).bDoQuery; ++i )
1392                 {
1393                     ScQueryEntry& rEntry = aParam.GetEntry(i);
1394                     if ( rEntry.eConnect != SC_AND )
1395                     {
1396                         bFilter = false;
1397                         break;
1398                     }
1399                 }
1400             }
1401 
1402             if ( bFilter )
1403             {
1404                 pTab[nTab]->GetFilteredFilterEntries( nCol, nStartRow, nEndRow, aParam, rStrings, rHasDates );
1405             }
1406             else
1407             {
1408                 pTab[nTab]->GetFilterEntries( nCol, nStartRow, nEndRow, rStrings, rHasDates );
1409             }
1410 
1411 			return sal_True;
1412 		}
1413 	}
1414 
1415 	return sal_False;
1416 }
1417 
1418 //
1419 //	GetFilterEntriesArea - Eintraege fuer Filter-Dialog
1420 //
1421 
1422 sal_Bool ScDocument::GetFilterEntriesArea( SCCOL nCol, SCROW nStartRow, SCROW nEndRow,
1423                                         SCTAB nTab, TypedScStrCollection& rStrings, bool& rHasDates )
1424 {
1425 	if ( ValidTab(nTab) && pTab[nTab] )
1426 	{
1427         pTab[nTab]->GetFilterEntries( nCol, nStartRow, nEndRow, rStrings, rHasDates );
1428 		return sal_True;
1429 	}
1430 
1431 	return sal_False;
1432 }
1433 
1434 //
1435 //	GetDataEntries - Eintraege fuer Auswahlliste-Listbox (keine Zahlen / Formeln)
1436 //
1437 
1438 sal_Bool ScDocument::GetDataEntries( SCCOL nCol, SCROW nRow, SCTAB nTab,
1439 									TypedScStrCollection& rStrings, sal_Bool bLimit )
1440 {
1441     if( !bLimit )
1442     {
1443         /*  Try to generate the list from list validation. This part is skipped,
1444             if bLimit==sal_True, because in that case this function is called to get
1445             cell values for auto completion on input. */
1446         sal_uInt32 nValidation = static_cast< const SfxUInt32Item* >( GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA ) )->GetValue();
1447         if( nValidation )
1448         {
1449             const ScValidationData* pData = GetValidationEntry( nValidation );
1450             if( pData && pData->FillSelectionList( rStrings, ScAddress( nCol, nRow, nTab ) ) )
1451                 return sal_True;
1452         }
1453     }
1454 
1455     return ValidTab(nTab) && pTab[nTab] && pTab[nTab]->GetDataEntries( nCol, nRow, rStrings, bLimit );
1456 	//if (ValidTab(nTab) && pTab[nTab])
1457 	//	return pTab[nTab]->GetDataEntries( nCol, nRow, rStrings, bLimit );
1458 
1459 	//return sal_False;
1460 }
1461 
1462 //
1463 //	GetFormulaEntries - Eintraege fuer Formel-AutoEingabe
1464 //
1465 
1466 //	Funktionen werden als 1 schon vom InputHandler eingefuegt
1467 #define SC_STRTYPE_NAMES		2
1468 #define SC_STRTYPE_DBNAMES		3
1469 #define SC_STRTYPE_HEADERS		4
1470 
1471 sal_Bool ScDocument::GetFormulaEntries( TypedScStrCollection& rStrings )
1472 {
1473 	sal_uInt16 i;
1474 
1475 	//
1476 	//	Bereichsnamen
1477 	//
1478 
1479 	if ( pRangeName )
1480 	{
1481 		sal_uInt16 nRangeCount = pRangeName->GetCount();
1482 		for ( i=0; i<nRangeCount; i++ )
1483 		{
1484 			ScRangeData* pData = (*pRangeName)[i];
1485 			if (pData)
1486 			{
1487 				TypedStrData* pNew = new TypedStrData( pData->GetName(), 0.0, SC_STRTYPE_NAMES );
1488 				if ( !rStrings.Insert(pNew) )
1489 					delete pNew;
1490 			}
1491 		}
1492 	}
1493 
1494 	//
1495 	//	Datenbank-Bereiche
1496 	//
1497 
1498 	if ( pDBCollection )
1499 	{
1500 		sal_uInt16 nDBCount = pDBCollection->GetCount();
1501 		for ( i=0; i<nDBCount; i++ )
1502 		{
1503 			ScDBData* pData = (*pDBCollection)[i];
1504 			if (pData)
1505 			{
1506 				TypedStrData* pNew = new TypedStrData( pData->GetName(), 0.0, SC_STRTYPE_DBNAMES );
1507 				if ( !rStrings.Insert(pNew) )
1508 					delete pNew;
1509 			}
1510 		}
1511 	}
1512 
1513 	//
1514 	//	Inhalte von Beschriftungsbereichen
1515 	//
1516 
1517 	ScRangePairList* pLists[2];
1518 	pLists[0] = GetColNameRanges();
1519 	pLists[1] = GetRowNameRanges();
1520 	for (sal_uInt16 nListNo=0; nListNo<2; nListNo++)
1521 	{
1522 		ScRangePairList* pList = pLists[nListNo];
1523 		if (pList)
1524 			for ( ScRangePair* pPair = pList->First(); pPair; pPair = pList->Next() )
1525 			{
1526 				ScRange aRange = pPair->GetRange(0);
1527 				ScCellIterator aIter( this, aRange );
1528 				for ( ScBaseCell* pCell = aIter.GetFirst(); pCell; pCell = aIter.GetNext() )
1529 					if ( pCell->HasStringData() )
1530 					{
1531 						String aStr = pCell->GetStringData();
1532 						TypedStrData* pNew = new TypedStrData( aStr, 0.0, SC_STRTYPE_HEADERS );
1533 						if ( !rStrings.Insert(pNew) )
1534 							delete pNew;
1535 					}
1536 			}
1537 	}
1538 
1539 	return sal_True;
1540 }
1541 
1542 
1543 sal_Bool ScDocument::IsEmbedded() const
1544 {
1545 	return bIsEmbedded;
1546 }
1547 
1548 void ScDocument::GetEmbedded( ScRange& rRange ) const
1549 {
1550     rRange = aEmbedRange;
1551 }
1552 
1553 Rectangle ScDocument::GetEmbeddedRect() const						// 1/100 mm
1554 {
1555 	Rectangle aRect;
1556 	ScTable* pTable = pTab[aEmbedRange.aStart.Tab()];
1557 	if (!pTable)
1558 	{
1559 		DBG_ERROR("GetEmbeddedRect ohne Tabelle");
1560 	}
1561 	else
1562 	{
1563 		SCCOL i;
1564 
1565 		for (i=0; i<aEmbedRange.aStart.Col(); i++)
1566 			aRect.Left() += pTable->GetColWidth(i);
1567         aRect.Top() += pTable->GetRowHeight( 0, aEmbedRange.aStart.Row() - 1);
1568 		aRect.Right() = aRect.Left();
1569 		for (i=aEmbedRange.aStart.Col(); i<=aEmbedRange.aEnd.Col(); i++)
1570 			aRect.Right() += pTable->GetColWidth(i);
1571 		aRect.Bottom() = aRect.Top();
1572         aRect.Bottom() += pTable->GetRowHeight( aEmbedRange.aStart.Row(), aEmbedRange.aEnd.Row());
1573 
1574 		aRect.Left()   = (long) ( aRect.Left()   * HMM_PER_TWIPS );
1575 		aRect.Right()  = (long) ( aRect.Right()  * HMM_PER_TWIPS );
1576 		aRect.Top()    = (long) ( aRect.Top()    * HMM_PER_TWIPS );
1577 		aRect.Bottom() = (long) ( aRect.Bottom() * HMM_PER_TWIPS );
1578 	}
1579 	return aRect;
1580 }
1581 
1582 void ScDocument::SetEmbedded( const ScRange& rRange )
1583 {
1584 	bIsEmbedded = sal_True;
1585 	aEmbedRange = rRange;
1586 }
1587 
1588 void ScDocument::ResetEmbedded()
1589 {
1590 	bIsEmbedded = sal_False;
1591 	aEmbedRange = ScRange();
1592 }
1593 
1594 
1595 /** Similar to ScViewData::AddPixelsWhile(), but add height twips and only
1596     while result is less than nStopTwips.
1597     @return sal_True if advanced at least one row.
1598  */
1599 bool lcl_AddTwipsWhile( long & rTwips, long nStopTwips, SCROW & rPosY, SCROW nEndRow, const ScTable * pTable )
1600 {
1601     SCROW nRow = rPosY;
1602     bool bAdded = false;
1603     bool bStop = false;
1604     while (rTwips < nStopTwips && nRow <= nEndRow && !bStop)
1605     {
1606         SCROW nHeightEndRow;
1607         sal_uInt16 nHeight = pTable->GetRowHeight( nRow, NULL, &nHeightEndRow);
1608         if (nHeightEndRow > nEndRow)
1609             nHeightEndRow = nEndRow;
1610         if (!nHeight)
1611             nRow = nHeightEndRow + 1;
1612         else
1613         {
1614             SCROW nRows = nHeightEndRow - nRow + 1;
1615             sal_Int64 nAdd = static_cast<sal_Int64>(nHeight) * nRows;
1616             if (nAdd + rTwips >= nStopTwips)
1617             {
1618                 sal_Int64 nDiff = nAdd + rTwips - nStopTwips;
1619                 nRows -= static_cast<SCROW>(nDiff / nHeight);
1620                 nAdd = nHeight * nRows;
1621                 // We're looking for a value that satisfies loop condition.
1622                 if (nAdd + rTwips >= nStopTwips)
1623                 {
1624                     --nRows;
1625                     nAdd -= nHeight;
1626                 }
1627                 bStop = true;
1628             }
1629             rTwips += static_cast<long>(nAdd);
1630             nRow += nRows;
1631         }
1632     }
1633     if (nRow > rPosY)
1634     {
1635         --nRow;
1636         bAdded = true;
1637     }
1638     rPosY = nRow;
1639     return bAdded;
1640 }
1641 
1642 ScRange ScDocument::GetRange( SCTAB nTab, const Rectangle& rMMRect )
1643 {
1644 	ScTable* pTable = pTab[nTab];
1645 	if (!pTable)
1646 	{
1647 		DBG_ERROR("GetRange ohne Tabelle");
1648 		return ScRange();
1649 	}
1650 
1651 	Rectangle aPosRect = rMMRect;
1652 	if ( IsNegativePage( nTab ) )
1653 		ScDrawLayer::MirrorRectRTL( aPosRect );			// always with positive (LTR) values
1654 
1655 	long nSize;
1656 	long nTwips;
1657 	long nAdd;
1658 	sal_Bool bEnd;
1659 
1660 	nSize = 0;
1661 	nTwips = (long) (aPosRect.Left() / HMM_PER_TWIPS);
1662 
1663 	SCCOL nX1 = 0;
1664 	bEnd = sal_False;
1665 	while (!bEnd)
1666 	{
1667 		nAdd = (long) pTable->GetColWidth(nX1);
1668 		if (nSize+nAdd <= nTwips+1 && nX1<MAXCOL)
1669 		{
1670 			nSize += nAdd;
1671 			++nX1;
1672 		}
1673 		else
1674 			bEnd = sal_True;
1675 	}
1676 
1677 	nTwips = (long) (aPosRect.Right() / HMM_PER_TWIPS);
1678 
1679 	SCCOL nX2 = nX1;
1680 	bEnd = sal_False;
1681 	while (!bEnd)
1682 	{
1683 		nAdd = (long) pTable->GetColWidth(nX2);
1684 		if (nSize+nAdd < nTwips && nX2<MAXCOL)
1685 		{
1686 			nSize += nAdd;
1687 			++nX2;
1688 		}
1689 		else
1690 			bEnd = sal_True;
1691 	}
1692 
1693 
1694 	nSize = 0;
1695 	nTwips = (long) (aPosRect.Top() / HMM_PER_TWIPS);
1696 
1697 	SCROW nY1 = 0;
1698     // Was if(nSize+nAdd<=nTwips+1) inside loop => if(nSize+nAdd<nTwips+2)
1699     if (lcl_AddTwipsWhile( nSize, nTwips+2, nY1, MAXROW, pTable) && nY1 < MAXROW)
1700         ++nY1;  // original loop ended on last matched +1 unless that was MAXROW
1701 
1702 	nTwips = (long) (aPosRect.Bottom() / HMM_PER_TWIPS);
1703 
1704 	SCROW nY2 = nY1;
1705     // Was if(nSize+nAdd<nTwips) inside loop => if(nSize+nAdd<nTwips)
1706     if (lcl_AddTwipsWhile( nSize, nTwips, nY2, MAXROW, pTable) && nY2 < MAXROW)
1707         ++nY2;  // original loop ended on last matched +1 unless that was MAXROW
1708 
1709 	return ScRange( nX1,nY1,nTab, nX2,nY2,nTab );
1710 }
1711 
1712 void ScDocument::SetEmbedded( const Rectangle& rRect )			// aus VisArea (1/100 mm)
1713 {
1714 	bIsEmbedded = sal_True;
1715 	aEmbedRange = GetRange( nVisibleTab, rRect );
1716 }
1717 
1718 //	VisArea auf Zellgrenzen anpassen
1719 
1720 void lcl_SnapHor( ScTable* pTable, long& rVal, SCCOL& rStartCol )
1721 {
1722 	SCCOL nCol = 0;
1723 	long nTwips = (long) (rVal / HMM_PER_TWIPS);
1724 	long nSnap = 0;
1725 	while ( nCol<MAXCOL )
1726 	{
1727 		long nAdd = pTable->GetColWidth(nCol);
1728 		if ( nSnap + nAdd/2 < nTwips || nCol < rStartCol )
1729 		{
1730 			nSnap += nAdd;
1731 			++nCol;
1732 		}
1733 		else
1734 			break;
1735 	}
1736 	rVal = (long) ( nSnap * HMM_PER_TWIPS );
1737 	rStartCol = nCol;
1738 }
1739 
1740 void lcl_SnapVer( ScTable* pTable, long& rVal, SCROW& rStartRow )
1741 {
1742 	SCROW nRow = 0;
1743 	long nTwips = (long) (rVal / HMM_PER_TWIPS);
1744 	long nSnap = 0;
1745 
1746     bool bFound = false;
1747     for (SCROW i = nRow; i <= MAXROW; ++i)
1748 	{
1749         SCROW nLastRow;
1750         if (pTable->RowHidden(i, NULL, &nLastRow))
1751         {
1752             i = nLastRow;
1753             continue;
1754         }
1755 
1756         nRow = i;
1757 		long nAdd = pTable->GetRowHeight(i);
1758 		if ( nSnap + nAdd/2 < nTwips || nRow < rStartRow )
1759 		{
1760 			nSnap += nAdd;
1761 			++nRow;
1762 		}
1763 		else
1764         {
1765             bFound = true;
1766 			break;
1767         }
1768 	}
1769     if (!bFound)
1770         nRow = MAXROW;  // all hidden down to the bottom
1771 
1772 	rVal = (long) ( nSnap * HMM_PER_TWIPS );
1773 	rStartRow = nRow;
1774 }
1775 
1776 void ScDocument::SnapVisArea( Rectangle& rRect ) const
1777 {
1778 	ScTable* pTable = pTab[nVisibleTab];
1779 	if (!pTable)
1780 	{
1781 		DBG_ERROR("SetEmbedded ohne Tabelle");
1782 		return;
1783 	}
1784 
1785     sal_Bool bNegativePage = IsNegativePage( nVisibleTab );
1786     if ( bNegativePage )
1787         ScDrawLayer::MirrorRectRTL( rRect );        // calculate with positive (LTR) values
1788 
1789 	SCCOL nCol = 0;
1790 	lcl_SnapHor( pTable, rRect.Left(), nCol );
1791 	++nCol;											// mindestens eine Spalte
1792 	lcl_SnapHor( pTable, rRect.Right(), nCol );
1793 
1794 	SCROW nRow = 0;
1795 	lcl_SnapVer( pTable, rRect.Top(), nRow );
1796 	++nRow;											// mindestens eine Zeile
1797 	lcl_SnapVer( pTable, rRect.Bottom(), nRow );
1798 
1799     if ( bNegativePage )
1800         ScDrawLayer::MirrorRectRTL( rRect );        // back to real rectangle
1801 }
1802 
1803 ScDocProtection* ScDocument::GetDocProtection() const
1804 {
1805     return pDocProtection.get();
1806 }
1807 
1808 void ScDocument::SetDocProtection(const ScDocProtection* pProtect)
1809 {
1810     if (pProtect)
1811         pDocProtection.reset(new ScDocProtection(*pProtect));
1812     else
1813         pDocProtection.reset(NULL);
1814 }
1815 
1816 sal_Bool ScDocument::IsDocProtected() const
1817 {
1818     return pDocProtection.get() && pDocProtection->isProtected();
1819 }
1820 
1821 sal_Bool ScDocument::IsDocEditable() const
1822 {
1823     // import into read-only document is possible
1824     return !IsDocProtected() && ( bImportingXML || mbChangeReadOnlyEnabled || !pShell || !pShell->IsReadOnly() );
1825 }
1826 
1827 sal_Bool ScDocument::IsTabProtected( SCTAB nTab ) const
1828 {
1829 	if (VALIDTAB(nTab) && pTab[nTab])
1830 		return pTab[nTab]->IsProtected();
1831 
1832 	DBG_ERROR("Falsche Tabellennummer");
1833 	return sal_False;
1834 }
1835 
1836 ScTableProtection* ScDocument::GetTabProtection( SCTAB nTab ) const
1837 {
1838     if (VALIDTAB(nTab) && pTab[nTab])
1839         return pTab[nTab]->GetProtection();
1840 
1841     return NULL;
1842 }
1843 
1844 void ScDocument::SetTabProtection(SCTAB nTab, const ScTableProtection* pProtect)
1845 {
1846     if (!ValidTab(nTab))
1847         return;
1848 
1849     pTab[nTab]->SetProtection(pProtect);
1850 }
1851 
1852 void ScDocument::CopyTabProtection(SCTAB nTabSrc, SCTAB nTabDest)
1853 {
1854     if (!ValidTab(nTabSrc) || !ValidTab(nTabDest))
1855         return;
1856 
1857     pTab[nTabDest]->SetProtection( pTab[nTabSrc]->GetProtection() );
1858 }
1859 
1860 const ScDocOptions& ScDocument::GetDocOptions() const
1861 {
1862 	DBG_ASSERT( pDocOptions, "No DocOptions! :-(" );
1863 	return *pDocOptions;
1864 }
1865 
1866 void ScDocument::SetDocOptions( const ScDocOptions& rOpt )
1867 {
1868 	DBG_ASSERT( pDocOptions, "No DocOptions! :-(" );
1869 	*pDocOptions = rOpt;
1870 
1871 	xPoolHelper->SetFormTableOpt(rOpt);
1872 }
1873 
1874 const ScViewOptions& ScDocument::GetViewOptions() const
1875 {
1876 	DBG_ASSERT( pViewOptions, "No ViewOptions! :-(" );
1877 	return *pViewOptions;
1878 }
1879 
1880 void ScDocument::SetViewOptions( const ScViewOptions& rOpt )
1881 {
1882 	DBG_ASSERT( pViewOptions, "No ViewOptions! :-(" );
1883 	*pViewOptions = rOpt;
1884 }
1885 
1886 void ScDocument::GetLanguage( LanguageType& rLatin, LanguageType& rCjk, LanguageType& rCtl ) const
1887 {
1888 	rLatin = eLanguage;
1889 	rCjk = eCjkLanguage;
1890 	rCtl = eCtlLanguage;
1891 }
1892 
1893 void ScDocument::SetLanguage( LanguageType eLatin, LanguageType eCjk, LanguageType eCtl )
1894 {
1895 	eLanguage = eLatin;
1896 	eCjkLanguage = eCjk;
1897 	eCtlLanguage = eCtl;
1898 	if ( xPoolHelper.isValid() )
1899 	{
1900 		ScDocumentPool* pPool = xPoolHelper->GetDocPool();
1901 		pPool->SetPoolDefaultItem( SvxLanguageItem( eLanguage, ATTR_FONT_LANGUAGE ) );
1902 		pPool->SetPoolDefaultItem( SvxLanguageItem( eCjkLanguage, ATTR_CJK_FONT_LANGUAGE ) );
1903 		pPool->SetPoolDefaultItem( SvxLanguageItem( eCtlLanguage, ATTR_CTL_FONT_LANGUAGE ) );
1904 	}
1905 
1906 	UpdateDrawLanguages();		// set edit engine defaults in drawing layer pool
1907 }
1908 
1909 void ScDocument::SetDrawDefaults()
1910 {
1911     bSetDrawDefaults = sal_True;
1912     UpdateDrawDefaults();
1913 }
1914 
1915 Rectangle ScDocument::GetMMRect( SCCOL nStartCol, SCROW nStartRow,
1916 								SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
1917 {
1918 	if (!ValidTab(nTab) || !pTab[nTab])
1919 	{
1920 		DBG_ERROR("GetMMRect: falsche Tabelle");
1921 		return Rectangle(0,0,0,0);
1922 	}
1923 
1924 	SCCOL i;
1925 	Rectangle aRect;
1926 
1927 	for (i=0; i<nStartCol; i++)
1928 		aRect.Left() += GetColWidth(i,nTab);
1929     aRect.Top() += GetRowHeight( 0, nStartRow-1, nTab);
1930 
1931 	aRect.Right()  = aRect.Left();
1932 	aRect.Bottom() = aRect.Top();
1933 
1934 	for (i=nStartCol; i<=nEndCol; i++)
1935 		aRect.Right() += GetColWidth(i,nTab);
1936     aRect.Bottom() += GetRowHeight( nStartRow, nEndRow, nTab);
1937 
1938 	aRect.Left()	= (long)(aRect.Left()	* HMM_PER_TWIPS);
1939 	aRect.Right()	= (long)(aRect.Right()	* HMM_PER_TWIPS);
1940 	aRect.Top()		= (long)(aRect.Top()	* HMM_PER_TWIPS);
1941 	aRect.Bottom()	= (long)(aRect.Bottom()	* HMM_PER_TWIPS);
1942 
1943 	if ( IsNegativePage( nTab ) )
1944 		ScDrawLayer::MirrorRectRTL( aRect );
1945 
1946 	return aRect;
1947 }
1948 
1949 void ScDocument::SetExtDocOptions( ScExtDocOptions* pNewOptions )
1950 {
1951 	delete pExtDocOptions;
1952 	pExtDocOptions = pNewOptions;
1953 }
1954 
1955 void ScDocument::DoMergeContents( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
1956 									SCCOL nEndCol, SCROW nEndRow )
1957 {
1958 	String aEmpty;
1959 	String aTotal;
1960 	String aCellStr;
1961 	SCCOL nCol;
1962 	SCROW nRow;
1963 	for (nRow=nStartRow; nRow<=nEndRow; nRow++)
1964 		for (nCol=nStartCol; nCol<=nEndCol; nCol++)
1965 		{
1966 			GetString(nCol,nRow,nTab,aCellStr);
1967 			if (aCellStr.Len())
1968 			{
1969 				if (aTotal.Len())
1970 					aTotal += ' ';
1971 				aTotal += aCellStr;
1972 			}
1973 			if (nCol != nStartCol || nRow != nStartRow)
1974 				SetString(nCol,nRow,nTab,aEmpty);
1975 		}
1976 
1977 	SetString(nStartCol,nStartRow,nTab,aTotal);
1978 }
1979 
1980 void ScDocument::DoMerge( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
1981                                     SCCOL nEndCol, SCROW nEndRow, bool bDeleteCaptions )
1982 {
1983 	ScMergeAttr aAttr( nEndCol-nStartCol+1, nEndRow-nStartRow+1 );
1984 	ApplyAttr( nStartCol, nStartRow, nTab, aAttr );
1985 
1986 	if ( nEndCol > nStartCol )
1987 		ApplyFlagsTab( nStartCol+1, nStartRow, nEndCol, nStartRow, nTab, SC_MF_HOR );
1988 	if ( nEndRow > nStartRow )
1989 		ApplyFlagsTab( nStartCol, nStartRow+1, nStartCol, nEndRow, nTab, SC_MF_VER );
1990 	if ( nEndCol > nStartCol && nEndRow > nStartRow )
1991 		ApplyFlagsTab( nStartCol+1, nStartRow+1, nEndCol, nEndRow, nTab, SC_MF_HOR | SC_MF_VER );
1992 
1993     // remove all covered notes (removed captions are collected by drawing undo if active)
1994     sal_uInt16 nDelFlag = IDF_NOTE | (bDeleteCaptions ? 0 : IDF_NOCAPTIONS);
1995     if( nStartCol < nEndCol )
1996         DeleteAreaTab( nStartCol + 1, nStartRow, nEndCol, nStartRow, nTab, nDelFlag );
1997     if( nStartRow < nEndRow )
1998         DeleteAreaTab( nStartCol, nStartRow + 1, nEndCol, nEndRow, nTab, nDelFlag );
1999 }
2000 
2001 void ScDocument::RemoveMerge( SCCOL nCol, SCROW nRow, SCTAB nTab )
2002 {
2003 	const ScMergeAttr* pAttr = (const ScMergeAttr*)
2004 									GetAttr( nCol, nRow, nTab, ATTR_MERGE );
2005 
2006 	if ( pAttr->GetColMerge() <= 1 && pAttr->GetRowMerge() <= 1 )
2007 		return;
2008 
2009 	SCCOL nEndCol = nCol + pAttr->GetColMerge() - 1;
2010 	SCROW nEndRow = nRow + pAttr->GetRowMerge() - 1;
2011 
2012 	RemoveFlagsTab( nCol, nRow, nEndCol, nEndRow, nTab, SC_MF_HOR | SC_MF_VER );
2013 
2014 	const ScMergeAttr* pDefAttr = (const ScMergeAttr*)
2015 										&xPoolHelper->GetDocPool()->GetDefaultItem( ATTR_MERGE );
2016 	ApplyAttr( nCol, nRow, nTab, *pDefAttr );
2017 }
2018 
2019 void ScDocument::ExtendPrintArea( OutputDevice* pDev, SCTAB nTab,
2020 					SCCOL nStartCol, SCROW nStartRow, SCCOL& rEndCol, SCROW nEndRow )
2021 {
2022 	if ( ValidTab(nTab)  && pTab[nTab] )
2023 		pTab[nTab]->ExtendPrintArea( pDev, nStartCol, nStartRow, rEndCol, nEndRow );
2024 }
2025 
2026 void ScDocument::IncSizeRecalcLevel( SCTAB nTab )
2027 {
2028 	if ( ValidTab(nTab)  && pTab[nTab] )
2029 		pTab[nTab]->IncRecalcLevel();
2030 }
2031 
2032 void ScDocument::DecSizeRecalcLevel( SCTAB nTab, bool bUpdateNoteCaptionPos )
2033 {
2034 	if ( ValidTab(nTab)  && pTab[nTab] )
2035 		pTab[nTab]->DecRecalcLevel( bUpdateNoteCaptionPos );
2036 }
2037 
2038 // Wang Xu Ming -- 2009-8-17
2039 // DataPilot Migration - Cache&&Performance
2040 ScDPTableDataCache* ScDocument::GetDPObjectCache( long nID )
2041 {
2042     for ( std::list<ScDPTableDataCache*>::iterator iter = m_listDPObjectsCaches.begin(); iter!=m_listDPObjectsCaches.end(); iter++ )
2043     { //
2044         if ( nID == (*iter)->GetId() )
2045             return *iter;
2046     }
2047     return NULL;
2048 }
2049 
2050 ScDPTableDataCache* ScDocument::GetUsedDPObjectCache ( ScRange rRange )
2051 {
2052     ScDPTableDataCache* pCache = NULL;
2053     sal_uInt16 nCount = GetDPCollection()->GetCount();
2054     for ( short i=nCount-1; i>=0 ; i--)
2055     {
2056         if ( const ScSheetSourceDesc* pUsedSheetDesc = (*pDPCollection)[i]->GetSheetDesc() )
2057             if ( rRange == pUsedSheetDesc->aSourceRange )
2058             {
2059                 long nID = (*pDPCollection)[i]->GetCacheId();
2060                 if ( nID >= 0  )
2061                     pCache= GetDPObjectCache( nID );
2062                 if ( pCache )
2063                     return pCache;
2064             }
2065     }
2066     return pCache;
2067 }
2068 
2069 long ScDocument::AddDPObjectCache( ScDPTableDataCache* pData )
2070 {
2071     if ( pData->GetId() < 0 )
2072     { //create a id for it
2073         pData->SetId( GetNewDPObjectCacheId() );
2074     }
2075     m_listDPObjectsCaches.push_back( pData );
2076     return pData->GetId();
2077 }
2078 
2079 long ScDocument::GetNewDPObjectCacheId()
2080 {
2081     long nID = 0;
2082 
2083     bool bFound = false;
2084     std::list<ScDPTableDataCache*>::iterator iter;
2085     do {
2086         for ( iter = m_listDPObjectsCaches.begin(); iter!=m_listDPObjectsCaches.end(); iter++ )
2087         { //Get a new Id
2088             if ( nID == (*iter)->GetId() )
2089             {
2090                 nID++;
2091                 bFound = true;
2092                 break;
2093             }
2094         }
2095         if ( iter == m_listDPObjectsCaches.end() )
2096             bFound = false;
2097     } while ( bFound );
2098 
2099     return nID;
2100 }
2101 
2102 void ScDocument::RemoveDPObjectCache( long nID )
2103 {
2104     for ( std::list<ScDPTableDataCache*>::iterator iter = m_listDPObjectsCaches.begin(); iter!=m_listDPObjectsCaches.end(); iter++ )
2105     {
2106         if ( nID == (*iter)->GetId() )
2107         {
2108             ScDPTableDataCache* pCache = *iter;
2109             m_listDPObjectsCaches.erase( iter );
2110             delete pCache;
2111             break;
2112         }
2113     }
2114 
2115 }
2116 
2117 void ScDocument::RemoveUnusedDPObjectCaches()
2118 {
2119     for ( std::list<ScDPTableDataCache*>::iterator iter = m_listDPObjectsCaches.begin(); iter!=m_listDPObjectsCaches.end(); )
2120     {
2121         long  nID = (*iter)->GetId();
2122         sal_uInt16 nCount = GetDPCollection()->GetCount();
2123         sal_uInt16 i ;
2124         for ( i=0; i<nCount; i++)
2125         {
2126             if ( nID ==  (*pDPCollection)[i]->GetCacheId() )
2127                 break;
2128         }
2129         if ( i == nCount )
2130         {
2131             ScDPTableDataCache* pCache = *iter;
2132             iter = m_listDPObjectsCaches.erase( iter );
2133             delete pCache;
2134             continue;
2135         }
2136         ++iter;
2137     }
2138 }
2139 
2140 void ScDocument::GetUsedDPObjectCache( std::list<ScDPTableDataCache*>& usedlist )
2141 {
2142     for ( std::list<ScDPTableDataCache*>::iterator iter = m_listDPObjectsCaches.begin(); iter!=m_listDPObjectsCaches.end(); iter++ )
2143     {
2144         long  nID = (*iter)->GetId();
2145         sal_uInt16 nCount = GetDPCollection()->GetCount();
2146         sal_uInt16 i=0;
2147         for ( i=0; i<nCount; i++)
2148             if ( nID ==  (*pDPCollection)[i]->GetCacheId() )
2149                 break;
2150         if ( i != nCount )
2151             usedlist.push_back( *iter );
2152     }
2153 }
2154 // End Comments
2155