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