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