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