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