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