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