xref: /AOO41X/main/sc/source/core/data/document.cxx (revision 7b6b9ddb4b63a97ea0214b9472b5270bbf674949)
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 #define _ZFORLIST_DECLARE_TABLE
30 #include "scitems.hxx"
31 #include <editeng/eeitem.hxx>
32 
33 #include <editeng/boxitem.hxx>
34 #include <editeng/frmdiritem.hxx>
35 #include <svx/pageitem.hxx>
36 #include <editeng/editeng.hxx>
37 #include <svx/svditer.hxx>
38 #include <svx/svdpage.hxx>
39 #include <svx/svdocapt.hxx>
40 #include <sfx2/app.hxx>
41 #include <sfx2/objsh.hxx>
42 #include <svl/poolcach.hxx>
43 #include <unotools/saveopt.hxx>
44 #include <svl/zforlist.hxx>
45 #include <unotools/charclass.hxx>
46 #include <unotools/transliterationwrapper.hxx>
47 #include <tools/tenccvt.hxx>
48 #include <svx/sdrundomanager.hxx>
49 
50 #include <com/sun/star/text/WritingMode2.hpp>
51 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
52 #include <com/sun/star/sheet/TablePageBreakData.hpp>
53 
54 #include "document.hxx"
55 #include "table.hxx"
56 #include "attrib.hxx"
57 #include "attarray.hxx"
58 #include "markarr.hxx"
59 #include "patattr.hxx"
60 #include "rangenam.hxx"
61 #include "poolhelp.hxx"
62 #include "docpool.hxx"
63 #include "stlpool.hxx"
64 #include "stlsheet.hxx"
65 #include "globstr.hrc"
66 #include "rechead.hxx"
67 #include "dbcolect.hxx"
68 #include "pivot.hxx"
69 #include "chartlis.hxx"
70 #include "rangelst.hxx"
71 #include "markdata.hxx"
72 #include "drwlayer.hxx"
73 #include "conditio.hxx"
74 #include "validat.hxx"
75 #include "prnsave.hxx"
76 #include "chgtrack.hxx"
77 #include "sc.hrc"
78 #include "scresid.hxx"
79 #include "hints.hxx"
80 #include "detdata.hxx"
81 #include "cell.hxx"
82 #include "dpobject.hxx"
83 #include "detfunc.hxx"      // for UpdateAllComments
84 #include "scmod.hxx"
85 #include "dociter.hxx"
86 #include "progress.hxx"
87 #include "autonamecache.hxx"
88 #include "bcaslot.hxx"
89 #include "postit.hxx"
90 #include "externalrefmgr.hxx"
91 #include "tabprotection.hxx"
92 #include "clipparam.hxx"
93 
94 #include <map>
95 #include <limits>
96 
97 namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
98 using ::com::sun::star::uno::Sequence;
99 using ::com::sun::star::sheet::TablePageBreakData;
100 using ::std::set;
101 
102 struct ScDefaultAttr
103 {
104     const ScPatternAttr*    pAttr;
105     SCROW                   nFirst;
106     SCSIZE                  nCount;
107     ScDefaultAttr(const ScPatternAttr* pPatAttr) : pAttr(pPatAttr), nFirst(0), nCount(0) {}
108 };
109 
110 struct ScLessDefaultAttr
111 {
112     sal_Bool operator() (const ScDefaultAttr& rValue1, const ScDefaultAttr& rValue2) const
113     {
114         return rValue1.pAttr < rValue2.pAttr;
115     }
116 };
117 
118 typedef std::set<ScDefaultAttr, ScLessDefaultAttr>  ScDefaultAttrSet;
119 
120 void ScDocument::MakeTable( SCTAB nTab,bool _bNeedsNameCheck )
121 {
122     if ( ValidTab(nTab) && !pTab[nTab] )
123     {
124         String aString = ScGlobal::GetRscString(STR_TABLE_DEF); //"Tabelle"
125         aString += String::CreateFromInt32(nTab+1);
126         if ( _bNeedsNameCheck )
127             CreateValidTabName( aString );  // keine doppelten
128 
129         pTab[nTab] = new ScTable(this, nTab, aString);
130         pTab[nTab]->SetLoadingMedium(bLoadingMedium);
131         ++nMaxTableNumber;
132     }
133 }
134 
135 
136 sal_Bool ScDocument::HasTable( SCTAB nTab ) const
137 {
138     if (VALIDTAB(nTab))
139         if (pTab[nTab])
140             return sal_True;
141 
142     return sal_False;
143 }
144 
145 
146 sal_Bool ScDocument::GetName( SCTAB nTab, String& rName ) const
147 {
148     if (VALIDTAB(nTab))
149         if (pTab[nTab])
150         {
151             pTab[nTab]->GetName( rName );
152             return sal_True;
153         }
154     rName.Erase();
155     return sal_False;
156 }
157 
158 sal_Bool ScDocument::SetCodeName( SCTAB nTab, const String& rName )
159 {
160     if (VALIDTAB(nTab))
161     {
162         if (pTab[nTab])
163         {
164             pTab[nTab]->SetCodeName( rName );
165             return sal_True;
166         }
167     }
168     OSL_TRACE( "**** can't set code name %s", rtl::OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr() );
169     return sal_False;
170 }
171 
172 sal_Bool ScDocument::GetCodeName( SCTAB nTab, String& rName ) const
173 {
174     if (VALIDTAB(nTab))
175         if (pTab[nTab])
176         {
177             pTab[nTab]->GetCodeName( rName );
178             return sal_True;
179         }
180     rName.Erase();
181     return sal_False;
182 }
183 
184 
185 sal_Bool ScDocument::GetTable( const String& rName, SCTAB& rTab ) const
186 {
187     String aUpperName = rName;
188     ScGlobal::pCharClass->toUpper(aUpperName);
189 
190     for (SCTAB i=0; i<=MAXTAB; i++)
191         if (pTab[i])
192         {
193             if ( pTab[i]->GetUpperName() == aUpperName )
194             {
195                 rTab = i;
196                 return sal_True;
197             }
198         }
199     rTab = 0;
200     return sal_False;
201 }
202 
203 
204 sal_Bool ScDocument::ValidTabName( const String& rName ) const
205 {
206     xub_StrLen nLen = rName.Len();
207     if (!nLen)
208         return false;
209 
210 #if 1
211     // Restrict sheet names to what Excel accepts.
212     /* TODO: We may want to remove this restriction for full ODFF compliance.
213      * Merely loading and calculating ODF documents using these characters in
214      * sheet names is not affected by this, but all sheet name editing and
215      * copying functionality is, maybe falling back to "Sheet4" or similar. */
216     for (xub_StrLen i = 0; i < nLen; ++i)
217     {
218         const sal_Unicode c = rName.GetChar(i);
219         switch (c)
220         {
221             case ':':
222             case '\\':
223             case '/':
224             case '?':
225             case '*':
226             case '[':
227             case ']':
228                 // these characters are not allowed to match XL's convention.
229                 return false;
230             case '\'':
231                 if (i == 0 || i == nLen - 1)
232                     // single quote is not allowed at the first or last
233                     // character position.
234                     return false;
235             break;
236         }
237     }
238 #endif
239 
240     return true;
241 }
242 
243 
244 sal_Bool ScDocument::ValidNewTabName( const String& rName ) const
245 {
246     sal_Bool bValid = ValidTabName(rName);
247     for (SCTAB i=0; (i<=MAXTAB) && bValid; i++)
248         if (pTab[i])
249         {
250             String aOldName;
251             pTab[i]->GetName(aOldName);
252             bValid = !ScGlobal::GetpTransliteration()->isEqual( rName, aOldName );
253         }
254     return bValid;
255 }
256 
257 
258 void ScDocument::CreateValidTabName(String& rName) const
259 {
260     if ( !ValidTabName(rName) )
261     {
262         // neu erzeugen
263 
264         const String aStrTable( ScResId(SCSTR_TABLE) );
265         sal_Bool         bOk   = sal_False;
266 
267         //  vorneweg testen, ob der Prefix als gueltig erkannt wird
268         //  wenn nicht, nur doppelte vermeiden
269         sal_Bool bPrefix = ValidTabName( aStrTable );
270         DBG_ASSERT(bPrefix, "ungueltiger Tabellenname");
271         SCTAB nDummy;
272 
273         SCTAB nLoops = 0;       // "zur Sicherheit"
274         for ( SCTAB i = nMaxTableNumber+1; !bOk && nLoops <= MAXTAB; i++ )
275         {
276             rName  = aStrTable;
277             rName += String::CreateFromInt32(i);
278             if (bPrefix)
279                 bOk = ValidNewTabName( rName );
280             else
281                 bOk = !GetTable( rName, nDummy );
282             ++nLoops;
283         }
284 
285         DBG_ASSERT(bOk, "kein gueltiger Tabellenname gefunden");
286         if ( !bOk )
287             rName = aStrTable;
288     }
289     else
290     {
291         // uebergebenen Namen ueberpruefen
292 
293         if ( !ValidNewTabName(rName) )
294         {
295             SCTAB i = 1;
296             String aName;
297             do
298             {
299                 i++;
300                 aName = rName;
301                 aName += '_';
302                 aName += String::CreateFromInt32(static_cast<sal_Int32>(i));
303             }
304             while (!ValidNewTabName(aName) && (i < MAXTAB+1));
305             rName = aName;
306         }
307     }
308 }
309 
310 
311 sal_Bool ScDocument::InsertTab( SCTAB nPos, const String& rName,
312             sal_Bool bExternalDocument )
313 {
314     SCTAB   nTabCount = GetTableCount();
315     sal_Bool    bValid = ValidTab(nTabCount);
316     if ( !bExternalDocument )   // sonst rName == "'Doc'!Tab", vorher pruefen
317         bValid = (bValid && ValidNewTabName(rName));
318     if (bValid)
319     {
320         if (nPos == SC_TAB_APPEND || nPos == nTabCount)
321         {
322             pTab[nTabCount] = new ScTable(this, nTabCount, rName);
323             pTab[nTabCount]->SetCodeName( rName );
324             ++nMaxTableNumber;
325             if ( bExternalDocument )
326                 pTab[nTabCount]->SetVisible( sal_False );
327         }
328         else
329         {
330             if (VALIDTAB(nPos) && (nPos < nTabCount))
331             {
332                 ScRange aRange( 0,0,nPos, MAXCOL,MAXROW,MAXTAB );
333                 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
334                 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
335                 pRangeName->UpdateTabRef( nPos, 1 );
336                 pDBCollection->UpdateReference(
337                                     URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
338                 if (pDPCollection)
339                     pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
340                 if (pDetOpList)
341                     pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,1 );
342                 UpdateChartRef( URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
343                 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,1 );
344                 if ( pUnoBroadcaster )
345                     pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,1 ) );
346 
347                 SCTAB i;
348                 for (i = 0; i <= MAXTAB; i++)
349                     if (pTab[i])
350                         pTab[i]->UpdateInsertTab(nPos);
351 
352                 for (i = nTabCount; i > nPos; i--)
353                 {
354                     pTab[i] = pTab[i - 1];
355                 }
356 
357                 pTab[nPos] = new ScTable(this, nPos, rName);
358                 pTab[nPos]->SetCodeName( rName );
359                 ++nMaxTableNumber;
360 
361                 // UpdateBroadcastAreas must be called between UpdateInsertTab,
362                 // which ends listening, and StartAllListeners, to not modify
363                 // areas that are to be inserted by starting listeners.
364                 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,1);
365                 for (i = 0; i <= MAXTAB; i++)
366                     if (pTab[i])
367                         pTab[i]->UpdateCompile();
368                 for (i = 0; i <= MAXTAB; i++)
369                     if (pTab[i])
370                         pTab[i]->StartAllListeners();
371 
372                 //  update conditional formats after table is inserted
373                 if ( pCondFormList )
374                     pCondFormList->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
375                 if ( pValidationList )
376                     pValidationList->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
377                 // #81844# sheet names of references are not valid until sheet is inserted
378                 if ( pChartListenerCollection )
379                     pChartListenerCollection->UpdateScheduledSeriesRanges();
380 
381                 SetDirty();
382                 bValid = sal_True;
383             }
384             else
385                 bValid = sal_False;
386         }
387     }
388     return bValid;
389 }
390 
391 
392 sal_Bool ScDocument::DeleteTab( SCTAB nTab, ScDocument* pRefUndoDoc )
393 {
394     sal_Bool bValid = sal_False;
395     if (VALIDTAB(nTab))
396     {
397         if (pTab[nTab])
398         {
399             SCTAB nTabCount = GetTableCount();
400             if (nTabCount > 1)
401             {
402                 sal_Bool bOldAutoCalc = GetAutoCalc();
403                 SetAutoCalc( sal_False );   // Mehrfachberechnungen vermeiden
404                 ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTab );
405                 DelBroadcastAreasInRange( aRange );
406 
407                 // #i8180# remove database ranges etc. that are on the deleted tab
408                 // (restored in undo with ScRefUndoData)
409 
410                 xColNameRanges->DeleteOnTab( nTab );
411                 xRowNameRanges->DeleteOnTab( nTab );
412                 pDBCollection->DeleteOnTab( nTab );
413                 if (pDPCollection)
414                     pDPCollection->DeleteOnTab( nTab );
415                 if (pDetOpList)
416                     pDetOpList->DeleteOnTab( nTab );
417                 DeleteAreaLinksOnTab( nTab );
418 
419                 // normal reference update
420 
421                 aRange.aEnd.SetTab( MAXTAB );
422                 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
423                 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
424                 pRangeName->UpdateTabRef( nTab, 2 );
425                 pDBCollection->UpdateReference(
426                                     URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1 );
427                 if (pDPCollection)
428                     pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
429                 if (pDetOpList)
430                     pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1 );
431                 UpdateChartRef( URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1 );
432                 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1 );
433                 if ( pCondFormList )
434                     pCondFormList->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
435                 if ( pValidationList )
436                     pValidationList->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
437                 if ( pUnoBroadcaster )
438                     pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1 ) );
439 
440                 SCTAB i;
441                 for (i=0; i<=MAXTAB; i++)
442                     if (pTab[i])
443                         pTab[i]->UpdateDeleteTab(nTab,sal_False,
444                                     pRefUndoDoc ? pRefUndoDoc->pTab[i] : 0);
445                 delete pTab[nTab];
446                 for (i=nTab + 1; i < nTabCount; i++)
447                     pTab[i - 1] = pTab[i];
448                 pTab[nTabCount - 1] = NULL;
449                 --nMaxTableNumber;
450                 // UpdateBroadcastAreas must be called between UpdateDeleteTab,
451                 // which ends listening, and StartAllListeners, to not modify
452                 // areas that are to be inserted by starting listeners.
453                 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1);
454                 for (i = 0; i <= MAXTAB; i++)
455                     if (pTab[i])
456                         pTab[i]->UpdateCompile();
457                 // Excel-Filter loescht einige Tables waehrend des Ladens,
458                 // Listener werden erst nach dem Laden aufgesetzt
459                 if ( !bInsertingFromOtherDoc )
460                 {
461                     for (i = 0; i <= MAXTAB; i++)
462                         if (pTab[i])
463                             pTab[i]->StartAllListeners();
464                     SetDirty();
465                 }
466                 // #81844# sheet names of references are not valid until sheet is deleted
467                 pChartListenerCollection->UpdateScheduledSeriesRanges();
468 
469                 SetAutoCalc( bOldAutoCalc );
470                 bValid = sal_True;
471             }
472         }
473     }
474     return bValid;
475 }
476 
477 
478 sal_Bool ScDocument::RenameTab( SCTAB nTab, const String& rName, sal_Bool /* bUpdateRef */,
479         sal_Bool bExternalDocument )
480 {
481     sal_Bool    bValid = sal_False;
482     SCTAB   i;
483     if VALIDTAB(nTab)
484         if (pTab[nTab])
485         {
486             if ( bExternalDocument )
487                 bValid = sal_True;      // zusammengesetzter Name
488             else
489                 bValid = ValidTabName(rName);
490             for (i=0; (i<=MAXTAB) && bValid; i++)
491                 if (pTab[i] && (i != nTab))
492                 {
493                     String aOldName;
494                     pTab[i]->GetName(aOldName);
495                     bValid = !ScGlobal::GetpTransliteration()->isEqual( rName, aOldName );
496                 }
497             if (bValid)
498             {
499                 // #i75258# update charts before renaming, so they can get their live data objects.
500                 // Once the charts are live, the sheet can be renamed without problems.
501                 if ( pChartListenerCollection )
502                     pChartListenerCollection->UpdateChartsContainingTab( nTab );
503                 pTab[nTab]->SetName(rName);
504 
505                 // If formulas refer to the renamed sheet, the TokenArray remains valid,
506                 // but the XML stream must be re-generated.
507                 for (i=0; i<=MAXTAB; ++i)
508                     if (pTab[i] && pTab[i]->IsStreamValid())
509                         pTab[i]->SetStreamValid( sal_False );
510             }
511         }
512     return bValid;
513 }
514 
515 
516 void ScDocument::SetVisible( SCTAB nTab, sal_Bool bVisible )
517 {
518     if (VALIDTAB(nTab))
519         if (pTab[nTab])
520             pTab[nTab]->SetVisible(bVisible);
521 }
522 
523 
524 sal_Bool ScDocument::IsVisible( SCTAB nTab ) const
525 {
526     if (VALIDTAB(nTab))
527         if (pTab[nTab])
528             return pTab[nTab]->IsVisible();
529 
530     return sal_False;
531 }
532 
533 
534 sal_Bool ScDocument::IsStreamValid( SCTAB nTab ) const
535 {
536     if ( ValidTab(nTab) && pTab[nTab] )
537         return pTab[nTab]->IsStreamValid();
538 
539     return sal_False;
540 }
541 
542 
543 void ScDocument::SetStreamValid( SCTAB nTab, sal_Bool bSet, sal_Bool bIgnoreLock )
544 {
545     if ( ValidTab(nTab) && pTab[nTab] )
546         pTab[nTab]->SetStreamValid( bSet, bIgnoreLock );
547 }
548 
549 
550 void ScDocument::LockStreamValid( bool bLock )
551 {
552     mbStreamValidLocked = bLock;
553 }
554 
555 
556 sal_Bool ScDocument::IsPendingRowHeights( SCTAB nTab ) const
557 {
558     if ( ValidTab(nTab) && pTab[nTab] )
559         return pTab[nTab]->IsPendingRowHeights();
560 
561     return sal_False;
562 }
563 
564 
565 void ScDocument::SetPendingRowHeights( SCTAB nTab, sal_Bool bSet )
566 {
567     if ( ValidTab(nTab) && pTab[nTab] )
568         pTab[nTab]->SetPendingRowHeights( bSet );
569 }
570 
571 
572 void ScDocument::SetLayoutRTL( SCTAB nTab, sal_Bool bRTL )
573 {
574     if ( ValidTab(nTab)  && pTab[nTab] )
575     {
576         if ( bImportingXML )
577         {
578             // #i57869# only set the LoadingRTL flag, the real setting (including mirroring)
579             // is applied in SetImportingXML(sal_False). This is so the shapes can be loaded in
580             // normal LTR mode.
581 
582             pTab[nTab]->SetLoadingRTL( bRTL );
583             return;
584         }
585 
586         pTab[nTab]->SetLayoutRTL( bRTL );       // only sets the flag
587         pTab[nTab]->SetDrawPageSize();
588 
589         //  mirror existing objects:
590 
591         if (pDrawLayer)
592         {
593             SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
594             DBG_ASSERT(pPage,"Page ?");
595             if (pPage)
596             {
597                 SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
598                 SdrObject* pObject = aIter.Next();
599                 while (pObject)
600                 {
601                     //  objects with ScDrawObjData are re-positioned in SetPageSize,
602                     //  don't mirror again
603                     ScDrawObjData* pData = ScDrawLayer::GetObjData( pObject );
604                     if ( !pData )
605                         pDrawLayer->MirrorRTL( pObject );
606 
607                     pObject->SetContextWritingMode( bRTL ? WritingMode2::RL_TB : WritingMode2::LR_TB );
608 
609                     pObject = aIter.Next();
610                 }
611             }
612         }
613     }
614 }
615 
616 
617 sal_Bool ScDocument::IsLayoutRTL( SCTAB nTab ) const
618 {
619     if ( ValidTab(nTab)  && pTab[nTab] )
620         return pTab[nTab]->IsLayoutRTL();
621 
622     return sal_False;
623 }
624 
625 
626 sal_Bool ScDocument::IsNegativePage( SCTAB nTab ) const
627 {
628     //  Negative page area is always used for RTL layout.
629     //  The separate method is used to find all RTL handling of drawing objects.
630     return IsLayoutRTL( nTab );
631 }
632 
633 
634 /* ----------------------------------------------------------------------------
635     benutzten Bereich suchen:
636 
637     GetCellArea  - nur Daten
638     GetTableArea - Daten / Attribute
639     GetPrintArea - beruecksichtigt auch Zeichenobjekte,
640                     streicht Attribute bis ganz rechts / unten
641 ---------------------------------------------------------------------------- */
642 
643 
644 sal_Bool ScDocument::GetCellArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
645 {
646     if (VALIDTAB(nTab))
647         if (pTab[nTab])
648             return pTab[nTab]->GetCellArea( rEndCol, rEndRow );
649 
650     rEndCol = 0;
651     rEndRow = 0;
652     return sal_False;
653 }
654 
655 
656 sal_Bool ScDocument::GetTableArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
657 {
658     if (VALIDTAB(nTab))
659         if (pTab[nTab])
660             return pTab[nTab]->GetTableArea( rEndCol, rEndRow );
661 
662     rEndCol = 0;
663     rEndRow = 0;
664     return sal_False;
665 }
666 
667 bool ScDocument::ShrinkToDataArea(SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow) const
668 {
669     if (!ValidTab(nTab) || !pTab[nTab])
670         return false;
671 
672     SCCOL nCol1, nCol2;
673     SCROW nRow1, nRow2;
674     pTab[nTab]->GetFirstDataPos(nCol1, nRow1);
675     pTab[nTab]->GetLastDataPos(nCol2, nRow2);
676 
677     if (nCol1 > nCol2 || nRow1 > nRow2)
678         // invalid range.
679         return false;
680 
681     // Make sure the area only shrinks, and doesn't grow.
682     if (rStartCol < nCol1)
683         rStartCol = nCol1;
684     if (nCol2 < rEndCol)
685         rEndCol = nCol2;
686     if (rStartRow < nRow1)
687         rStartRow = nRow1;
688     if (nRow2 < rEndRow)
689         rEndRow = nRow2;
690 
691     if (rStartCol > rEndCol || rStartRow > rEndRow)
692         // invalid range.
693         return false;
694 
695     return true;  // success!
696 }
697 
698 bool ScDocument::ShrinkToUsedDataArea( bool& o_bShrunk, SCTAB nTab, SCCOL& rStartCol,
699         SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const
700 {
701     if (!ValidTab(nTab) || !pTab[nTab])
702     {
703         o_bShrunk = false;
704         return false;
705     }
706     return pTab[nTab]->ShrinkToUsedDataArea( o_bShrunk, rStartCol, rStartRow, rEndCol, rEndRow, bColumnsOnly);
707 }
708 
709 //  zusammenhaengender Bereich
710 
711 void ScDocument::GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
712                               SCCOL& rEndCol, SCROW& rEndRow, sal_Bool bIncludeOld, bool bOnlyDown ) const
713 {
714     if (ValidTab(nTab) && pTab[nTab])
715         pTab[nTab]->GetDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bIncludeOld, bOnlyDown );
716 }
717 
718 
719 void ScDocument::LimitChartArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
720                                     SCCOL& rEndCol, SCROW& rEndRow )
721 {
722     if (VALIDTAB(nTab))
723         if (pTab[nTab])
724             pTab[nTab]->LimitChartArea( rStartCol, rStartRow, rEndCol, rEndRow );
725 }
726 
727 
728 void ScDocument::LimitChartIfAll( ScRangeListRef& rRangeList )
729 {
730     ScRangeListRef aNew = new ScRangeList;
731     if (rRangeList.Is())
732     {
733         sal_uLong nCount = rRangeList->Count();
734         for (sal_uLong i=0; i<nCount; i++)
735         {
736             ScRange aRange(*rRangeList->GetObject( i ));
737             if ( ( aRange.aStart.Col() == 0 && aRange.aEnd.Col() == MAXCOL ) ||
738                  ( aRange.aStart.Row() == 0 && aRange.aEnd.Row() == MAXROW ) )
739             {
740                 SCCOL nStartCol = aRange.aStart.Col();
741                 SCROW nStartRow = aRange.aStart.Row();
742                 SCCOL nEndCol = aRange.aEnd.Col();
743                 SCROW nEndRow = aRange.aEnd.Row();
744                 SCTAB nTab = aRange.aStart.Tab();
745                 if (pTab[nTab])
746                     pTab[nTab]->LimitChartArea(nStartCol, nStartRow, nEndCol, nEndRow);
747                 aRange.aStart.SetCol( nStartCol );
748                 aRange.aStart.SetRow( nStartRow );
749                 aRange.aEnd.SetCol( nEndCol );
750                 aRange.aEnd.SetRow( nEndRow );
751             }
752             aNew->Append(aRange);
753         }
754     }
755     else
756     {
757         DBG_ERROR("LimitChartIfAll: Ref==0");
758     }
759     rRangeList = aNew;
760 }
761 
762 
763 void lcl_GetFirstTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark )
764 {
765     // without ScMarkData, leave start/end unchanged
766     if ( pTabMark )
767     {
768         for (SCTAB nTab=0; nTab<=MAXTAB; ++nTab)
769             if (pTabMark->GetTableSelect(nTab))
770             {
771                 // find first range of consecutive selected sheets
772                 rTabRangeStart = nTab;
773                 while ( nTab+1 <= MAXTAB && pTabMark->GetTableSelect(nTab+1) )
774                     ++nTab;
775                 rTabRangeEnd = nTab;
776                 return;
777             }
778     }
779 }
780 
781 bool lcl_GetNextTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark )
782 {
783     if ( pTabMark )
784     {
785         // find next range of consecutive selected sheets after rTabRangeEnd
786         for (SCTAB nTab=rTabRangeEnd+1; nTab<=MAXTAB; ++nTab)
787             if (pTabMark->GetTableSelect(nTab))
788             {
789                 rTabRangeStart = nTab;
790                 while ( nTab+1 <= MAXTAB && pTabMark->GetTableSelect(nTab+1) )
791                     ++nTab;
792                 rTabRangeEnd = nTab;
793                 return true;
794             }
795     }
796     return false;
797 }
798 
799 
800 sal_Bool ScDocument::CanInsertRow( const ScRange& rRange ) const
801 {
802     SCCOL nStartCol = rRange.aStart.Col();
803     SCROW nStartRow = rRange.aStart.Row();
804     SCTAB nStartTab = rRange.aStart.Tab();
805     SCCOL nEndCol = rRange.aEnd.Col();
806     SCROW nEndRow = rRange.aEnd.Row();
807     SCTAB nEndTab = rRange.aEnd.Tab();
808     PutInOrder( nStartCol, nEndCol );
809     PutInOrder( nStartRow, nEndRow );
810     PutInOrder( nStartTab, nEndTab );
811     SCSIZE nSize = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
812 
813     sal_Bool bTest = sal_True;
814     for (SCTAB i=nStartTab; i<=nEndTab && bTest; i++)
815         if (pTab[i])
816             bTest &= pTab[i]->TestInsertRow( nStartCol, nEndCol, nSize );
817 
818     return bTest;
819 }
820 
821 
822 sal_Bool ScDocument::InsertRow( SCCOL nStartCol, SCTAB nStartTab,
823                             SCCOL nEndCol,   SCTAB nEndTab,
824                             SCROW nStartRow, SCSIZE nSize, ScDocument* pRefUndoDoc,
825                             const ScMarkData* pTabMark )
826 {
827     SCTAB i;
828 
829     PutInOrder( nStartCol, nEndCol );
830     PutInOrder( nStartTab, nEndTab );
831     if ( pTabMark )
832     {
833         nStartTab = 0;
834         nEndTab = MAXTAB;
835     }
836 
837     sal_Bool bTest = sal_True;
838     sal_Bool bRet = sal_False;
839     sal_Bool bOldAutoCalc = GetAutoCalc();
840     SetAutoCalc( sal_False );   // Mehrfachberechnungen vermeiden
841     for ( i = nStartTab; i <= nEndTab && bTest; i++)
842         if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
843             bTest &= pTab[i]->TestInsertRow( nStartCol, nEndCol, nSize );
844     if (bTest)
845     {
846         // UpdateBroadcastAreas muss vor UpdateReference gerufen werden, damit nicht
847         // Eintraege verschoben werden, die erst bei UpdateReference neu erzeugt werden
848 
849         // handle chunks of consecutive selected sheets together
850         SCTAB nTabRangeStart = nStartTab;
851         SCTAB nTabRangeEnd = nEndTab;
852         lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
853         do
854         {
855             UpdateBroadcastAreas( URM_INSDEL, ScRange(
856                 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
857                 ScAddress( nEndCol, MAXROW, nTabRangeEnd )), 0, static_cast<SCsROW>(nSize), 0 );
858         }
859         while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
860 
861         lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
862         do
863         {
864             UpdateReference( URM_INSDEL, nStartCol, nStartRow, nTabRangeStart,
865                              nEndCol, MAXROW, nTabRangeEnd,
866                              0, static_cast<SCsROW>(nSize), 0, pRefUndoDoc, sal_False );        // without drawing objects
867         }
868         while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
869 
870         for (i=nStartTab; i<=nEndTab; i++)
871             if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
872                 pTab[i]->InsertRow( nStartCol, nEndCol, nStartRow, nSize );
873 
874         //  #82991# UpdateRef for drawing layer must be after inserting,
875         //  when the new row heights are known.
876         for (i=nStartTab; i<=nEndTab; i++)
877             if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
878                 pTab[i]->UpdateDrawRef( URM_INSDEL,
879                             nStartCol, nStartRow, nStartTab, nEndCol, MAXROW, nEndTab,
880                             0, static_cast<SCsROW>(nSize), 0 );
881 
882         if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
883         {   // durch Restaurierung von Referenzen auf geloeschte Bereiche ist
884             // ein neues Listening faellig, bisherige Listener wurden in
885             // FormulaCell UpdateReference abgehaengt
886             StartAllListeners();
887         }
888         else
889         {   // Listeners have been removed in UpdateReference
890             for (i=0; i<=MAXTAB; i++)
891                 if (pTab[i])
892                     pTab[i]->StartNeededListeners();
893             // #69592# at least all cells using range names pointing relative
894             // to the moved range must recalculate
895             for (i=0; i<=MAXTAB; i++)
896                 if (pTab[i])
897                     pTab[i]->SetRelNameDirty();
898         }
899         bRet = sal_True;
900     }
901     SetAutoCalc( bOldAutoCalc );
902     if ( bRet )
903         pChartListenerCollection->UpdateDirtyCharts();
904     return bRet;
905 }
906 
907 
908 sal_Bool ScDocument::InsertRow( const ScRange& rRange, ScDocument* pRefUndoDoc )
909 {
910     return InsertRow( rRange.aStart.Col(), rRange.aStart.Tab(),
911                       rRange.aEnd.Col(),   rRange.aEnd.Tab(),
912                       rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
913                       pRefUndoDoc );
914 }
915 
916 
917 void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
918                             SCCOL nEndCol,   SCTAB nEndTab,
919                             SCROW nStartRow, SCSIZE nSize,
920                             ScDocument* pRefUndoDoc, sal_Bool* pUndoOutline,
921                             const ScMarkData* pTabMark )
922 {
923     SCTAB i;
924 
925     PutInOrder( nStartCol, nEndCol );
926     PutInOrder( nStartTab, nEndTab );
927     if ( pTabMark )
928     {
929         nStartTab = 0;
930         nEndTab = MAXTAB;
931     }
932 
933     sal_Bool bOldAutoCalc = GetAutoCalc();
934     SetAutoCalc( sal_False );   // Mehrfachberechnungen vermeiden
935 
936     // handle chunks of consecutive selected sheets together
937     SCTAB nTabRangeStart = nStartTab;
938     SCTAB nTabRangeEnd = nEndTab;
939     lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
940     do
941     {
942         if ( ValidRow(nStartRow+nSize) )
943         {
944             DelBroadcastAreasInRange( ScRange(
945                 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
946                 ScAddress( nEndCol, nStartRow+nSize-1, nTabRangeEnd ) ) );
947             UpdateBroadcastAreas( URM_INSDEL, ScRange(
948                 ScAddress( nStartCol, nStartRow+nSize, nTabRangeStart ),
949                 ScAddress( nEndCol, MAXROW, nTabRangeEnd )), 0, -(static_cast<SCsROW>(nSize)), 0 );
950         }
951         else
952             DelBroadcastAreasInRange( ScRange(
953                 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
954                 ScAddress( nEndCol, MAXROW, nTabRangeEnd ) ) );
955     }
956     while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
957 
958     if ( ValidRow(nStartRow+nSize) )
959     {
960         lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
961         do
962         {
963             UpdateReference( URM_INSDEL, nStartCol, nStartRow+nSize, nTabRangeStart,
964                              nEndCol, MAXROW, nTabRangeEnd,
965                              0, -(static_cast<SCsROW>(nSize)), 0, pRefUndoDoc, sal_True, false );
966         }
967         while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
968     }
969 
970     if (pUndoOutline)
971         *pUndoOutline = sal_False;
972 
973     for ( i = nStartTab; i <= nEndTab; i++)
974         if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
975             pTab[i]->DeleteRow( nStartCol, nEndCol, nStartRow, nSize, pUndoOutline );
976 
977     if ( ValidRow(nStartRow+nSize) )
978     {   // Listeners have been removed in UpdateReference
979         for (i=0; i<=MAXTAB; i++)
980             if (pTab[i])
981                 pTab[i]->StartNeededListeners();
982         // #69592# at least all cells using range names pointing relative to
983         // the moved range must recalculate
984         for (i=0; i<=MAXTAB; i++)
985             if (pTab[i])
986                 pTab[i]->SetRelNameDirty();
987     }
988 
989     SetAutoCalc( bOldAutoCalc );
990     pChartListenerCollection->UpdateDirtyCharts();
991 }
992 
993 
994 void ScDocument::DeleteRow( const ScRange& rRange, ScDocument* pRefUndoDoc, sal_Bool* pUndoOutline )
995 {
996     DeleteRow( rRange.aStart.Col(), rRange.aStart.Tab(),
997                rRange.aEnd.Col(),   rRange.aEnd.Tab(),
998                rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
999                pRefUndoDoc, pUndoOutline );
1000 }
1001 
1002 
1003 sal_Bool ScDocument::CanInsertCol( const ScRange& rRange ) const
1004 {
1005     SCCOL nStartCol = rRange.aStart.Col();
1006     SCROW nStartRow = rRange.aStart.Row();
1007     SCTAB nStartTab = rRange.aStart.Tab();
1008     SCCOL nEndCol = rRange.aEnd.Col();
1009     SCROW nEndRow = rRange.aEnd.Row();
1010     SCTAB nEndTab = rRange.aEnd.Tab();
1011     PutInOrder( nStartCol, nEndCol );
1012     PutInOrder( nStartRow, nEndRow );
1013     PutInOrder( nStartTab, nEndTab );
1014     SCSIZE nSize = static_cast<SCSIZE>(nEndCol - nStartCol + 1);
1015 
1016     sal_Bool bTest = sal_True;
1017     for (SCTAB i=nStartTab; i<=nEndTab && bTest; i++)
1018         if (pTab[i])
1019             bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
1020 
1021     return bTest;
1022 }
1023 
1024 
1025 sal_Bool ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
1026                             SCROW nEndRow,   SCTAB nEndTab,
1027                             SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
1028                             const ScMarkData* pTabMark )
1029 {
1030     SCTAB i;
1031 
1032     PutInOrder( nStartRow, nEndRow );
1033     PutInOrder( nStartTab, nEndTab );
1034     if ( pTabMark )
1035     {
1036         nStartTab = 0;
1037         nEndTab = MAXTAB;
1038     }
1039 
1040     sal_Bool bTest = sal_True;
1041     sal_Bool bRet = sal_False;
1042     sal_Bool bOldAutoCalc = GetAutoCalc();
1043     SetAutoCalc( sal_False );   // Mehrfachberechnungen vermeiden
1044     for ( i = nStartTab; i <= nEndTab && bTest; i++)
1045         if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1046             bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
1047     if (bTest)
1048     {
1049         // handle chunks of consecutive selected sheets together
1050         SCTAB nTabRangeStart = nStartTab;
1051         SCTAB nTabRangeEnd = nEndTab;
1052         lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
1053         do
1054         {
1055             UpdateBroadcastAreas( URM_INSDEL, ScRange(
1056                 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1057                 ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), static_cast<SCsCOL>(nSize), 0, 0 );
1058         }
1059         while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
1060 
1061         lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
1062         do
1063         {
1064             UpdateReference( URM_INSDEL, nStartCol, nStartRow, nTabRangeStart,
1065                              MAXCOL, nEndRow, nTabRangeEnd,
1066                              static_cast<SCsCOL>(nSize), 0, 0, pRefUndoDoc, sal_True, false );
1067         }
1068         while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
1069 
1070         for (i=nStartTab; i<=nEndTab; i++)
1071             if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1072                 pTab[i]->InsertCol( nStartCol, nStartRow, nEndRow, nSize );
1073 
1074         if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
1075         {   // durch Restaurierung von Referenzen auf geloeschte Bereiche ist
1076             // ein neues Listening faellig, bisherige Listener wurden in
1077             // FormulaCell UpdateReference abgehaengt
1078             StartAllListeners();
1079         }
1080         else
1081         {   // Listeners have been removed in UpdateReference
1082             for (i=0; i<=MAXTAB; i++)
1083                 if (pTab[i])
1084                     pTab[i]->StartNeededListeners();
1085             // #69592# at least all cells using range names pointing relative
1086             // to the moved range must recalculate
1087             for (i=0; i<=MAXTAB; i++)
1088                 if (pTab[i])
1089                     pTab[i]->SetRelNameDirty();
1090         }
1091         bRet = sal_True;
1092     }
1093     SetAutoCalc( bOldAutoCalc );
1094     if ( bRet )
1095         pChartListenerCollection->UpdateDirtyCharts();
1096     return bRet;
1097 }
1098 
1099 
1100 sal_Bool ScDocument::InsertCol( const ScRange& rRange, ScDocument* pRefUndoDoc )
1101 {
1102     return InsertCol( rRange.aStart.Row(), rRange.aStart.Tab(),
1103                       rRange.aEnd.Row(),   rRange.aEnd.Tab(),
1104                       rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
1105                       pRefUndoDoc );
1106 }
1107 
1108 
1109 void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTAB nEndTab,
1110                                 SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
1111                                 sal_Bool* pUndoOutline, const ScMarkData* pTabMark )
1112 {
1113     SCTAB i;
1114 
1115     PutInOrder( nStartRow, nEndRow );
1116     PutInOrder( nStartTab, nEndTab );
1117     if ( pTabMark )
1118     {
1119         nStartTab = 0;
1120         nEndTab = MAXTAB;
1121     }
1122 
1123     sal_Bool bOldAutoCalc = GetAutoCalc();
1124     SetAutoCalc( sal_False );   // Mehrfachberechnungen vermeiden
1125 
1126     // handle chunks of consecutive selected sheets together
1127     SCTAB nTabRangeStart = nStartTab;
1128     SCTAB nTabRangeEnd = nEndTab;
1129     lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
1130     do
1131     {
1132         if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1133         {
1134             DelBroadcastAreasInRange( ScRange(
1135                 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1136                 ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize-1), nEndRow, nTabRangeEnd ) ) );
1137             UpdateBroadcastAreas( URM_INSDEL, ScRange(
1138                 ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart ),
1139                 ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), -static_cast<SCsCOL>(nSize), 0, 0 );
1140         }
1141         else
1142             DelBroadcastAreasInRange( ScRange(
1143                 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1144                 ScAddress( MAXCOL, nEndRow, nTabRangeEnd ) ) );
1145     }
1146     while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
1147 
1148     if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1149     {
1150         lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
1151         do
1152         {
1153             UpdateReference( URM_INSDEL, sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart,
1154                              MAXCOL, nEndRow, nTabRangeEnd,
1155                              -static_cast<SCsCOL>(nSize), 0, 0, pRefUndoDoc, sal_True, false );
1156         }
1157         while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
1158     }
1159 
1160     if (pUndoOutline)
1161         *pUndoOutline = sal_False;
1162 
1163     for ( i = nStartTab; i <= nEndTab; i++)
1164         if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1165             pTab[i]->DeleteCol( nStartCol, nStartRow, nEndRow, nSize, pUndoOutline );
1166 
1167     if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1168     {   // Listeners have been removed in UpdateReference
1169         for (i=0; i<=MAXTAB; i++)
1170             if (pTab[i])
1171                 pTab[i]->StartNeededListeners();
1172         // #69592# at least all cells using range names pointing relative to
1173         // the moved range must recalculate
1174         for (i=0; i<=MAXTAB; i++)
1175             if (pTab[i])
1176                 pTab[i]->SetRelNameDirty();
1177     }
1178 
1179     SetAutoCalc( bOldAutoCalc );
1180     pChartListenerCollection->UpdateDirtyCharts();
1181 }
1182 
1183 
1184 void ScDocument::DeleteCol( const ScRange& rRange, ScDocument* pRefUndoDoc, sal_Bool* pUndoOutline )
1185 {
1186     DeleteCol( rRange.aStart.Row(), rRange.aStart.Tab(),
1187                rRange.aEnd.Row(),   rRange.aEnd.Tab(),
1188                rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
1189                pRefUndoDoc, pUndoOutline );
1190 }
1191 
1192 
1193 //  fuer Area-Links: Zellen einuegen/loeschen, wenn sich der Bereich veraendert
1194 //  (ohne Paint)
1195 
1196 
1197 void lcl_GetInsDelRanges( const ScRange& rOld, const ScRange& rNew,
1198                             ScRange& rColRange, sal_Bool& rInsCol, sal_Bool& rDelCol,
1199                             ScRange& rRowRange, sal_Bool& rInsRow, sal_Bool& rDelRow )
1200 {
1201     DBG_ASSERT( rOld.aStart == rNew.aStart, "FitBlock: Anfang unterschiedlich" );
1202 
1203     rInsCol = rDelCol = rInsRow = rDelRow = sal_False;
1204 
1205     SCCOL nStartX = rOld.aStart.Col();
1206     SCROW nStartY = rOld.aStart.Row();
1207     SCCOL nOldEndX = rOld.aEnd.Col();
1208     SCROW nOldEndY = rOld.aEnd.Row();
1209     SCCOL nNewEndX = rNew.aEnd.Col();
1210     SCROW nNewEndY = rNew.aEnd.Row();
1211     SCTAB nTab = rOld.aStart.Tab();
1212 
1213     //  wenn es mehr Zeilen werden, werden Spalten auf der alten Hoehe eingefuegt/geloescht
1214     sal_Bool bGrowY = ( nNewEndY > nOldEndY );
1215     SCROW nColEndY = bGrowY ? nOldEndY : nNewEndY;
1216     SCCOL nRowEndX = bGrowY ? nNewEndX : nOldEndX;
1217 
1218     //  Spalten
1219 
1220     if ( nNewEndX > nOldEndX )          // Spalten einfuegen
1221     {
1222         rColRange = ScRange( nOldEndX+1, nStartY, nTab, nNewEndX, nColEndY, nTab );
1223         rInsCol = sal_True;
1224     }
1225     else if ( nNewEndX < nOldEndX )     // Spalten loeschen
1226     {
1227         rColRange = ScRange( nNewEndX+1, nStartY, nTab, nOldEndX, nColEndY, nTab );
1228         rDelCol = sal_True;
1229     }
1230 
1231     //  Zeilen
1232 
1233     if ( nNewEndY > nOldEndY )          // Zeilen einfuegen
1234     {
1235         rRowRange = ScRange( nStartX, nOldEndY+1, nTab, nRowEndX, nNewEndY, nTab );
1236         rInsRow = sal_True;
1237     }
1238     else if ( nNewEndY < nOldEndY )     // Zeilen loeschen
1239     {
1240         rRowRange = ScRange( nStartX, nNewEndY+1, nTab, nRowEndX, nOldEndY, nTab );
1241         rDelRow = sal_True;
1242     }
1243 }
1244 
1245 
1246 sal_Bool ScDocument::HasPartOfMerged( const ScRange& rRange )
1247 {
1248     sal_Bool bPart = sal_False;
1249     SCTAB nTab = rRange.aStart.Tab();
1250 
1251     SCCOL nStartX = rRange.aStart.Col();
1252     SCROW nStartY = rRange.aStart.Row();
1253     SCCOL nEndX = rRange.aEnd.Col();
1254     SCROW nEndY = rRange.aEnd.Row();
1255 
1256     if (HasAttrib( nStartX, nStartY, nTab, nEndX, nEndY, nTab,
1257                         HASATTR_MERGED | HASATTR_OVERLAPPED ))
1258     {
1259         ExtendMerge( nStartX, nStartY, nEndX, nEndY, nTab );
1260         ExtendOverlapped( nStartX, nStartY, nEndX, nEndY, nTab );
1261 
1262         bPart = ( nStartX != rRange.aStart.Col() || nEndX != rRange.aEnd.Col() ||
1263                   nStartY != rRange.aStart.Row() || nEndY != rRange.aEnd.Row() );
1264     }
1265     return bPart;
1266 }
1267 
1268 
1269 sal_Bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
1270 {
1271     if ( rOld == rNew )
1272         return sal_True;
1273 
1274     sal_Bool bOk = sal_True;
1275     sal_Bool bInsCol,bDelCol,bInsRow,bDelRow;
1276     ScRange aColRange,aRowRange;
1277     lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
1278 
1279     if ( bInsCol && !CanInsertCol( aColRange ) )            // Zellen am Rand ?
1280         bOk = sal_False;
1281     if ( bInsRow && !CanInsertRow( aRowRange ) )            // Zellen am Rand ?
1282         bOk = sal_False;
1283 
1284     if ( bInsCol || bDelCol )
1285     {
1286         aColRange.aEnd.SetCol(MAXCOL);
1287         if ( HasPartOfMerged(aColRange) )
1288             bOk = sal_False;
1289     }
1290     if ( bInsRow || bDelRow )
1291     {
1292         aRowRange.aEnd.SetRow(MAXROW);
1293         if ( HasPartOfMerged(aRowRange) )
1294             bOk = sal_False;
1295     }
1296 
1297     return bOk;
1298 }
1299 
1300 
1301 void ScDocument::FitBlock( const ScRange& rOld, const ScRange& rNew, sal_Bool bClear )
1302 {
1303     if (bClear)
1304         DeleteAreaTab( rOld, IDF_ALL );
1305 
1306     sal_Bool bInsCol,bDelCol,bInsRow,bDelRow;
1307     ScRange aColRange,aRowRange;
1308     lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
1309 
1310     if ( bInsCol )
1311         InsertCol( aColRange );         // Spalten zuerst einfuegen
1312     if ( bInsRow )
1313         InsertRow( aRowRange );
1314 
1315     if ( bDelRow )
1316         DeleteRow( aRowRange );         // Zeilen zuerst loeschen
1317     if ( bDelCol )
1318         DeleteCol( aColRange );
1319 
1320     //  Referenzen um eingefuegte Zeilen erweitern
1321 
1322     if ( bInsCol || bInsRow )
1323     {
1324         ScRange aGrowSource = rOld;
1325         aGrowSource.aEnd.SetCol(Min( rOld.aEnd.Col(), rNew.aEnd.Col() ));
1326         aGrowSource.aEnd.SetRow(Min( rOld.aEnd.Row(), rNew.aEnd.Row() ));
1327         SCCOL nGrowX = bInsCol ? ( rNew.aEnd.Col() - rOld.aEnd.Col() ) : 0;
1328         SCROW nGrowY = bInsRow ? ( rNew.aEnd.Row() - rOld.aEnd.Row() ) : 0;
1329         UpdateGrow( aGrowSource, nGrowX, nGrowY );
1330     }
1331 }
1332 
1333 
1334 void ScDocument::DeleteArea(SCCOL nCol1, SCROW nRow1,
1335                             SCCOL nCol2, SCROW nRow2,
1336                             const ScMarkData& rMark, sal_uInt16 nDelFlag)
1337 {
1338     PutInOrder( nCol1, nCol2 );
1339     PutInOrder( nRow1, nRow2 );
1340     sal_Bool bOldAutoCalc = GetAutoCalc();
1341     SetAutoCalc( sal_False );   // Mehrfachberechnungen vermeiden
1342     for (SCTAB i = 0; i <= MAXTAB; i++)
1343         if (pTab[i])
1344             if ( rMark.GetTableSelect(i) || bIsUndo )
1345                 pTab[i]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
1346     SetAutoCalc( bOldAutoCalc );
1347 }
1348 
1349 
1350 void ScDocument::DeleteAreaTab(SCCOL nCol1, SCROW nRow1,
1351                                 SCCOL nCol2, SCROW nRow2,
1352                                 SCTAB nTab, sal_uInt16 nDelFlag)
1353 {
1354     PutInOrder( nCol1, nCol2 );
1355     PutInOrder( nRow1, nRow2 );
1356     if ( VALIDTAB(nTab) && pTab[nTab] )
1357     {
1358         sal_Bool bOldAutoCalc = GetAutoCalc();
1359         SetAutoCalc( sal_False );   // Mehrfachberechnungen vermeiden
1360         pTab[nTab]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
1361         SetAutoCalc( bOldAutoCalc );
1362     }
1363 }
1364 
1365 
1366 void ScDocument::DeleteAreaTab( const ScRange& rRange, sal_uInt16 nDelFlag )
1367 {
1368     for ( SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); nTab++ )
1369         DeleteAreaTab( rRange.aStart.Col(), rRange.aStart.Row(),
1370                        rRange.aEnd.Col(),   rRange.aEnd.Row(),
1371                        nTab, nDelFlag );
1372 }
1373 
1374 
1375 void ScDocument::InitUndoSelected( ScDocument* pSrcDoc, const ScMarkData& rTabSelection,
1376                                 sal_Bool bColInfo, sal_Bool bRowInfo )
1377 {
1378     if (bIsUndo)
1379     {
1380         Clear();
1381 
1382         xPoolHelper = pSrcDoc->xPoolHelper;
1383 
1384         String aString;
1385         for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
1386             if ( rTabSelection.GetTableSelect( nTab ) )
1387             {
1388                 pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1389                 nMaxTableNumber = nTab + 1;
1390             }
1391     }
1392     else
1393         {
1394         DBG_ERROR("InitUndo");
1395         }
1396 }
1397 
1398 
1399 void ScDocument::InitUndo( ScDocument* pSrcDoc, SCTAB nTab1, SCTAB nTab2,
1400                                 sal_Bool bColInfo, sal_Bool bRowInfo )
1401 {
1402     if (bIsUndo)
1403     {
1404         Clear();
1405 
1406         xPoolHelper = pSrcDoc->xPoolHelper;
1407 
1408         String aString;
1409         for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
1410             pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1411 
1412         nMaxTableNumber = nTab2 + 1;
1413     }
1414     else
1415     {
1416         DBG_ERROR("InitUndo");
1417     }
1418 }
1419 
1420 
1421 void ScDocument::AddUndoTab( SCTAB nTab1, SCTAB nTab2, sal_Bool bColInfo, sal_Bool bRowInfo )
1422 {
1423     if (bIsUndo)
1424     {
1425         String aString;
1426         for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
1427             if (!pTab[nTab])
1428                 pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1429 
1430         if ( nMaxTableNumber <= nTab2 )
1431             nMaxTableNumber = nTab2 + 1;
1432     }
1433     else
1434     {
1435         DBG_ERROR("InitUndo");
1436     }
1437 }
1438 
1439 
1440 void ScDocument::SetCutMode( sal_Bool bVal )
1441 {
1442     if (bIsClip)
1443         GetClipParam().mbCutMode = bVal;
1444     else
1445     {
1446         DBG_ERROR("SetCutMode without bIsClip");
1447     }
1448 }
1449 
1450 
1451 sal_Bool ScDocument::IsCutMode()
1452 {
1453     if (bIsClip)
1454         return GetClipParam().mbCutMode;
1455     else
1456     {
1457         DBG_ERROR("IsCutMode ohne bIsClip");
1458         return sal_False;
1459     }
1460 }
1461 
1462 
1463 void ScDocument::CopyToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1464                             SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1465                             sal_uInt16 nFlags, sal_Bool bOnlyMarked, ScDocument* pDestDoc,
1466                             const ScMarkData* pMarks, sal_Bool bColRowFlags )
1467 {
1468     PutInOrder( nCol1, nCol2 );
1469     PutInOrder( nRow1, nRow2 );
1470     PutInOrder( nTab1, nTab2 );
1471     if( !pDestDoc->aDocName.Len() )
1472         pDestDoc->aDocName = aDocName;
1473     if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
1474     {
1475         sal_Bool bOldAutoCalc = pDestDoc->GetAutoCalc();
1476         pDestDoc->SetAutoCalc( sal_False );     // Mehrfachberechnungen vermeiden
1477         for (SCTAB i = nTab1; i <= nTab2; i++)
1478         {
1479             if (pTab[i] && pDestDoc->pTab[i])
1480                 pTab[i]->CopyToTable( nCol1, nRow1, nCol2, nRow2, nFlags,
1481                                       bOnlyMarked, pDestDoc->pTab[i], pMarks,
1482                                       sal_False, bColRowFlags );
1483         }
1484         pDestDoc->SetAutoCalc( bOldAutoCalc );
1485     }
1486 }
1487 
1488 
1489 void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1490                             SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1491                             sal_uInt16 nFlags, sal_Bool bOnlyMarked, ScDocument* pDestDoc,
1492                             const ScMarkData* pMarks)
1493 {
1494     PutInOrder( nCol1, nCol2 );
1495     PutInOrder( nRow1, nRow2 );
1496     PutInOrder( nTab1, nTab2 );
1497     if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
1498     {
1499         sal_Bool bOldAutoCalc = pDestDoc->GetAutoCalc();
1500         pDestDoc->SetAutoCalc( sal_False );     // Mehrfachberechnungen vermeiden
1501         if (nTab1 > 0)
1502             CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, sal_False, pDestDoc, pMarks );
1503 
1504         for (SCTAB i = nTab1; i <= nTab2; i++)
1505         {
1506             if (pTab[i] && pDestDoc->pTab[i])
1507                 pTab[i]->UndoToTable(nCol1, nRow1, nCol2, nRow2, nFlags,
1508                                     bOnlyMarked, pDestDoc->pTab[i], pMarks);
1509         }
1510 
1511         if (nTab2 < MAXTAB)
1512             CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA, sal_False, pDestDoc, pMarks );
1513         pDestDoc->SetAutoCalc( bOldAutoCalc );
1514     }
1515 }
1516 
1517 
1518 void ScDocument::CopyToDocument(const ScRange& rRange,
1519                             sal_uInt16 nFlags, sal_Bool bOnlyMarked, ScDocument* pDestDoc,
1520                             const ScMarkData* pMarks, sal_Bool bColRowFlags)
1521 {
1522     ScRange aNewRange = rRange;
1523     aNewRange.Justify();
1524 
1525     if( !pDestDoc->aDocName.Len() )
1526         pDestDoc->aDocName = aDocName;
1527     sal_Bool bOldAutoCalc = pDestDoc->GetAutoCalc();
1528     pDestDoc->SetAutoCalc( sal_False );     // Mehrfachberechnungen vermeiden
1529     for (SCTAB i = aNewRange.aStart.Tab(); i <= aNewRange.aEnd.Tab(); i++)
1530         if (pTab[i] && pDestDoc->pTab[i])
1531             pTab[i]->CopyToTable(aNewRange.aStart.Col(), aNewRange.aStart.Row(),
1532                                  aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
1533                                  nFlags, bOnlyMarked, pDestDoc->pTab[i],
1534                                  pMarks, sal_False, bColRowFlags);
1535     pDestDoc->SetAutoCalc( bOldAutoCalc );
1536 }
1537 
1538 
1539 void ScDocument::UndoToDocument(const ScRange& rRange,
1540                             sal_uInt16 nFlags, sal_Bool bOnlyMarked, ScDocument* pDestDoc,
1541                             const ScMarkData* pMarks)
1542 {
1543     ScRange aNewRange = rRange;
1544     aNewRange.Justify();
1545     SCTAB nTab1 = aNewRange.aStart.Tab();
1546     SCTAB nTab2 = aNewRange.aEnd.Tab();
1547 
1548     sal_Bool bOldAutoCalc = pDestDoc->GetAutoCalc();
1549     pDestDoc->SetAutoCalc( sal_False );     // Mehrfachberechnungen vermeiden
1550     if (nTab1 > 0)
1551         CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, sal_False, pDestDoc, pMarks );
1552 
1553     for (SCTAB i = nTab1; i <= nTab2; i++)
1554     {
1555         if (pTab[i] && pDestDoc->pTab[i])
1556             pTab[i]->UndoToTable(aNewRange.aStart.Col(), aNewRange.aStart.Row(),
1557                                     aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
1558                                     nFlags, bOnlyMarked, pDestDoc->pTab[i], pMarks);
1559     }
1560 
1561     if (nTab2 < MAXTAB)
1562         CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA, sal_False, pDestDoc, pMarks );
1563     pDestDoc->SetAutoCalc( bOldAutoCalc );
1564 }
1565 
1566 void ScDocument::CopyToClip(const ScClipParam& rClipParam,
1567                             ScDocument* pClipDoc, const ScMarkData* pMarks,
1568                             bool bAllTabs, bool bKeepScenarioFlags, bool bIncludeObjects, bool bCloneNoteCaptions)
1569 {
1570     DBG_ASSERT( bAllTabs || pMarks, "CopyToClip: ScMarkData fehlt" );
1571 
1572     if (bIsClip)
1573         return;
1574 
1575     if (!pClipDoc)
1576     {
1577         DBG_ERROR("CopyToClip: no ClipDoc");
1578         pClipDoc = SC_MOD()->GetClipDoc();
1579     }
1580 
1581     pClipDoc->aDocName = aDocName;
1582     pClipDoc->SetClipParam(rClipParam);
1583     pClipDoc->ResetClip(this, pMarks);
1584 
1585     ScRange aClipRange = rClipParam.getWholeRange();
1586     CopyRangeNamesToClip(pClipDoc, aClipRange, pMarks, bAllTabs);
1587 
1588     for (SCTAB i = 0; i <= MAXTAB; ++i)
1589     {
1590         if (!pTab[i] || !pClipDoc->pTab[i])
1591             continue;
1592 
1593         if (pMarks && !pMarks->GetTableSelect(i))
1594             continue;
1595 
1596         pTab[i]->CopyToClip(rClipParam.maRanges, pClipDoc->pTab[i], bKeepScenarioFlags, bCloneNoteCaptions);
1597 
1598         if (pDrawLayer && bIncludeObjects)
1599         {
1600             //  also copy drawing objects
1601             Rectangle aObjRect = GetMMRect(
1602                 aClipRange.aStart.Col(), aClipRange.aStart.Row(), aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i);
1603             pDrawLayer->CopyToClip(pClipDoc, i, aObjRect);
1604         }
1605     }
1606 
1607     // Make sure to mark overlapped cells.
1608     pClipDoc->ExtendMerge(aClipRange, true);
1609 }
1610 
1611 void ScDocument::CopyTabToClip(SCCOL nCol1, SCROW nRow1,
1612                                 SCCOL nCol2, SCROW nRow2,
1613                                 SCTAB nTab, ScDocument* pClipDoc)
1614 {
1615     if (!bIsClip)
1616     {
1617         PutInOrder( nCol1, nCol2 );
1618         PutInOrder( nRow1, nRow2 );
1619         if (!pClipDoc)
1620         {
1621             DBG_ERROR("CopyTabToClip: no ClipDoc");
1622             pClipDoc = SC_MOD()->GetClipDoc();
1623         }
1624 
1625         ScClipParam& rClipParam = pClipDoc->GetClipParam();
1626         pClipDoc->aDocName = aDocName;
1627         rClipParam.maRanges.RemoveAll();
1628         rClipParam.maRanges.Append(ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0));
1629         pClipDoc->ResetClip( this, nTab );
1630 
1631         if (pTab[nTab] && pClipDoc->pTab[nTab])
1632             pTab[nTab]->CopyToClip(nCol1, nRow1, nCol2, nRow2, pClipDoc->pTab[nTab], sal_False, sal_True);
1633 
1634         pClipDoc->GetClipParam().mbCutMode = false;
1635     }
1636 }
1637 
1638 
1639 void ScDocument::TransposeClip( ScDocument* pTransClip, sal_uInt16 nFlags, sal_Bool bAsLink )
1640 {
1641     DBG_ASSERT( bIsClip && pTransClip && pTransClip->bIsClip,
1642                     "TransposeClip mit falschem Dokument" );
1643 
1644         //  initialisieren
1645         //  -> pTransClip muss vor dem Original-Dokument geloescht werden!
1646 
1647     pTransClip->ResetClip(this, (ScMarkData*)NULL);     // alle
1648 
1649         //  Bereiche uebernehmen
1650 
1651     pTransClip->pRangeName->FreeAll();
1652     for (sal_uInt16 i = 0; i < pRangeName->GetCount(); i++)     //! DB-Bereiche Pivot-Bereiche auch !!!
1653     {
1654         sal_uInt16 nIndex = ((ScRangeData*)((*pRangeName)[i]))->GetIndex();
1655         ScRangeData* pData = new ScRangeData(*((*pRangeName)[i]));
1656         if (!pTransClip->pRangeName->Insert(pData))
1657             delete pData;
1658         else
1659             pData->SetIndex(nIndex);
1660     }
1661 
1662         //  Daten
1663 
1664     ScRange aClipRange = GetClipParam().getWholeRange();
1665     if ( ValidRow(aClipRange.aEnd.Row()-aClipRange.aStart.Row()) )
1666     {
1667         for (SCTAB i=0; i<=MAXTAB; i++)
1668             if (pTab[i])
1669             {
1670                 DBG_ASSERT( pTransClip->pTab[i], "TransposeClip: Tabelle nicht da" );
1671                 pTab[i]->TransposeClip( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
1672                                             aClipRange.aEnd.Col(), aClipRange.aEnd.Row(),
1673                                             pTransClip->pTab[i], nFlags, bAsLink );
1674 
1675                 if ( pDrawLayer && ( nFlags & IDF_OBJECTS ) )
1676                 {
1677                     //  Drawing objects are copied to the new area without transposing.
1678                     //  CopyFromClip is used to adjust the objects to the transposed block's
1679                     //  cell range area.
1680                     //  (pDrawLayer in the original clipboard document is set only if there
1681                     //  are drawing objects to copy)
1682 
1683                     pTransClip->InitDrawLayer();
1684                     Rectangle aSourceRect = GetMMRect( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
1685                                                         aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i );
1686                     Rectangle aDestRect = pTransClip->GetMMRect( 0, 0,
1687                             static_cast<SCCOL>(aClipRange.aEnd.Row() - aClipRange.aStart.Row()),
1688                             static_cast<SCROW>(aClipRange.aEnd.Col() - aClipRange.aStart.Col()), i );
1689                     pTransClip->pDrawLayer->CopyFromClip( pDrawLayer, i, aSourceRect, ScAddress(0,0,i), aDestRect );
1690                 }
1691             }
1692 
1693         pTransClip->SetClipParam(GetClipParam());
1694         pTransClip->GetClipParam().transpose();
1695     }
1696     else
1697     {
1698         DBG_ERROR("TransposeClip: zu gross");
1699     }
1700 
1701         //  Dies passiert erst beim Einfuegen...
1702 
1703     GetClipParam().mbCutMode = false;
1704 }
1705 
1706 void ScDocument::CopyRangeNamesToClip(ScDocument* pClipDoc, const ScRange& rClipRange, const ScMarkData* pMarks, bool bAllTabs)
1707 {
1708     std::set<sal_uInt16> aUsedNames;        // indexes of named ranges that are used in the copied cells
1709     for (SCTAB i = 0; i <= MAXTAB; ++i)
1710         if (pTab[i] && pClipDoc->pTab[i])
1711             if ( bAllTabs || !pMarks || pMarks->GetTableSelect(i) )
1712                 pTab[i]->FindRangeNamesInUse(
1713                     rClipRange.aStart.Col(), rClipRange.aStart.Row(),
1714                     rClipRange.aEnd.Col(), rClipRange.aEnd.Row(), aUsedNames);
1715 
1716     pClipDoc->pRangeName->FreeAll();
1717     for (sal_uInt16 i = 0; i < pRangeName->GetCount(); i++)        //! DB-Bereiche Pivot-Bereiche auch !!!
1718     {
1719         sal_uInt16 nIndex = ((ScRangeData*)((*pRangeName)[i]))->GetIndex();
1720         bool bInUse = ( aUsedNames.find(nIndex) != aUsedNames.end() );
1721         if (bInUse)
1722         {
1723             ScRangeData* pData = new ScRangeData(*((*pRangeName)[i]));
1724             if (!pClipDoc->pRangeName->Insert(pData))
1725                 delete pData;
1726             else
1727                 pData->SetIndex(nIndex);
1728         }
1729     }
1730 }
1731 
1732 ScDocument::NumFmtMergeHandler::NumFmtMergeHandler(ScDocument* pDoc, ScDocument* pSrcDoc) :
1733         mpDoc(pDoc)
1734 {
1735     mpDoc->MergeNumberFormatter(pSrcDoc);
1736 }
1737 
1738 ScDocument::NumFmtMergeHandler::~NumFmtMergeHandler()
1739 {
1740     mpDoc->pFormatExchangeList = NULL;
1741 }
1742 
1743 void ScDocument::MergeNumberFormatter(ScDocument* pSrcDoc)
1744 {
1745     SvNumberFormatter* pThisFormatter = xPoolHelper->GetFormTable();
1746     SvNumberFormatter* pOtherFormatter = pSrcDoc->xPoolHelper->GetFormTable();
1747     if (pOtherFormatter && pOtherFormatter != pThisFormatter)
1748     {
1749         SvNumberFormatterIndexTable* pExchangeList =
1750                  pThisFormatter->MergeFormatter(*(pOtherFormatter));
1751         if (pExchangeList->Count() > 0)
1752             pFormatExchangeList = pExchangeList;
1753     }
1754 }
1755 
1756 void ScDocument::CopyRangeNamesFromClip(ScDocument* pClipDoc, ScClipRangeNameData& rRangeNames)
1757 {
1758     sal_uInt16 nClipRangeNameCount = pClipDoc->pRangeName->GetCount();
1759     ScClipRangeNameData aClipRangeNames;
1760 
1761     // array containing range names which might need update of indices
1762     aClipRangeNames.mpRangeNames.resize(nClipRangeNameCount, NULL);
1763 
1764     for (sal_uInt16 i = 0; i < nClipRangeNameCount; ++i)        //! DB-Bereiche Pivot-Bereiche auch
1765     {
1766         /*  Copy only if the name doesn't exist in this document.
1767             If it exists we use the already existing name instead,
1768             another possibility could be to create new names if
1769             documents differ.
1770             A proper solution would ask the user how to proceed.
1771             The adjustment of the indices in the formulas is done later.
1772         */
1773         ScRangeData* pClipRangeData = (*pClipDoc->pRangeName)[i];
1774         sal_uInt16 k;
1775         if ( pRangeName->SearchName( pClipRangeData->GetName(), k ) )
1776         {
1777             aClipRangeNames.mpRangeNames[i] = NULL;  // range name not inserted
1778             sal_uInt16 nOldIndex = pClipRangeData->GetIndex();
1779             sal_uInt16 nNewIndex = ((*pRangeName)[k])->GetIndex();
1780             aClipRangeNames.insert(nOldIndex, nNewIndex);
1781             if ( !aClipRangeNames.mbReplace )
1782                 aClipRangeNames.mbReplace = ( nOldIndex != nNewIndex );
1783         }
1784         else
1785         {
1786             ScRangeData* pData = new ScRangeData( *pClipRangeData );
1787             pData->SetDocument(this);
1788             if ( pRangeName->FindIndex( pData->GetIndex() ) )
1789                 pData->SetIndex(0);     // need new index, done in Insert
1790             if ( pRangeName->Insert( pData ) )
1791             {
1792                 aClipRangeNames.mpRangeNames[i] = pData;
1793                 sal_uInt16 nOldIndex = pClipRangeData->GetIndex();
1794                 sal_uInt16 nNewIndex = pData->GetIndex();
1795                 aClipRangeNames.insert(nOldIndex, nNewIndex);
1796                 if ( !aClipRangeNames.mbReplace )
1797                     aClipRangeNames.mbReplace = ( nOldIndex != nNewIndex );
1798             }
1799             else
1800             {   // must be an overflow
1801                 delete pData;
1802                 aClipRangeNames.mpRangeNames[i] = NULL;
1803                 aClipRangeNames.insert(pClipRangeData->GetIndex(), 0);
1804                 aClipRangeNames.mbReplace = true;
1805             }
1806         }
1807     }
1808     rRangeNames = aClipRangeNames;
1809 }
1810 
1811 void ScDocument::UpdateRangeNamesInFormulas(
1812     ScClipRangeNameData& rRangeNames, const ScRangeList& rDestRanges, const ScMarkData& rMark,
1813     SCCOL nXw, SCROW nYw)
1814 {
1815     // nXw and nYw are the extra width and height of the destination range
1816     // extended due to presence of merged cell(s).
1817 
1818     if (!rRangeNames.mbReplace)
1819         return;
1820 
1821     // first update all inserted named formulas if they contain other
1822     // range names and used indices changed
1823     size_t nRangeNameCount = rRangeNames.mpRangeNames.size();
1824     for (size_t i = 0; i < nRangeNameCount; ++i)        //! DB-Bereiche Pivot-Bereiche auch
1825     {
1826         if ( rRangeNames.mpRangeNames[i] )
1827             rRangeNames.mpRangeNames[i]->ReplaceRangeNamesInUse(rRangeNames.maRangeMap);
1828     }
1829     // then update the formulas, they might need just the updated range names
1830     for (sal_uLong nRange = 0; nRange < rDestRanges.Count(); ++nRange)
1831     {
1832         const ScRange* pRange = rDestRanges.GetObject( nRange);
1833         SCCOL nCol1 = pRange->aStart.Col();
1834         SCROW nRow1 = pRange->aStart.Row();
1835         SCCOL nCol2 = pRange->aEnd.Col();
1836         SCROW nRow2 = pRange->aEnd.Row();
1837 
1838         SCCOL nC1 = nCol1;
1839         SCROW nR1 = nRow1;
1840         SCCOL nC2 = nC1 + nXw;
1841         if (nC2 > nCol2)
1842             nC2 = nCol2;
1843         SCROW nR2 = nR1 + nYw;
1844         if (nR2 > nRow2)
1845             nR2 = nRow2;
1846         do
1847         {
1848             do
1849             {
1850                 for (SCTAB k = 0; k <= MAXTAB; k++)
1851                 {
1852                     if ( pTab[k] && rMark.GetTableSelect(k) )
1853                         pTab[k]->ReplaceRangeNamesInUse(nC1, nR1,
1854                             nC2, nR2, rRangeNames.maRangeMap);
1855                 }
1856                 nC1 = nC2 + 1;
1857                 nC2 = Min((SCCOL)(nC1 + nXw), nCol2);
1858             } while (nC1 <= nCol2);
1859             nC1 = nCol1;
1860             nC2 = nC1 + nXw;
1861             if (nC2 > nCol2)
1862                 nC2 = nCol2;
1863             nR1 = nR2 + 1;
1864             nR2 = Min((SCROW)(nR1 + nYw), nRow2);
1865         } while (nR1 <= nRow2);
1866     }
1867 }
1868 
1869 ScClipParam& ScDocument::GetClipParam()
1870 {
1871     if (!mpClipParam.get())
1872         mpClipParam.reset(new ScClipParam);
1873 
1874     return *mpClipParam;
1875 }
1876 
1877 void ScDocument::SetClipParam(const ScClipParam& rParam)
1878 {
1879     mpClipParam.reset(new ScClipParam(rParam));
1880 }
1881 
1882 sal_Bool ScDocument::IsClipboardSource() const
1883 {
1884     ScDocument* pClipDoc = SC_MOD()->GetClipDoc();
1885     return pClipDoc && pClipDoc->xPoolHelper.isValid() &&
1886             xPoolHelper->GetDocPool() == pClipDoc->xPoolHelper->GetDocPool();
1887 }
1888 
1889 
1890 void ScDocument::StartListeningFromClip( SCCOL nCol1, SCROW nRow1,
1891                                         SCCOL nCol2, SCROW nRow2,
1892                                         const ScMarkData& rMark, sal_uInt16 nInsFlag )
1893 {
1894     if (nInsFlag & IDF_CONTENTS)
1895     {
1896         for (SCTAB i = 0; i <= MAXTAB; i++)
1897             if (pTab[i])
1898                 if (rMark.GetTableSelect(i))
1899                     pTab[i]->StartListeningInArea( nCol1, nRow1, nCol2, nRow2 );
1900     }
1901 }
1902 
1903 
1904 void ScDocument::BroadcastFromClip( SCCOL nCol1, SCROW nRow1,
1905                                     SCCOL nCol2, SCROW nRow2,
1906                                     const ScMarkData& rMark, sal_uInt16 nInsFlag )
1907 {
1908     if (nInsFlag & IDF_CONTENTS)
1909     {
1910         ScBulkBroadcast aBulkBroadcast( GetBASM());
1911         for (SCTAB i = 0; i <= MAXTAB; i++)
1912             if (pTab[i])
1913                 if (rMark.GetTableSelect(i))
1914                     pTab[i]->BroadcastInArea( nCol1, nRow1, nCol2, nRow2 );
1915     }
1916 }
1917 
1918 
1919 void ScDocument::CopyBlockFromClip( SCCOL nCol1, SCROW nRow1,
1920                                     SCCOL nCol2, SCROW nRow2,
1921                                     const ScMarkData& rMark,
1922                                     SCsCOL nDx, SCsROW nDy,
1923                                     const ScCopyBlockFromClipParams* pCBFCP )
1924 {
1925     ScTable** ppClipTab = pCBFCP->pClipDoc->pTab;
1926     SCTAB nTabEnd = pCBFCP->nTabEnd;
1927     SCTAB nClipTab = 0;
1928     for (SCTAB i = pCBFCP->nTabStart; i <= nTabEnd; i++)
1929     {
1930         if (pTab[i] && rMark.GetTableSelect(i) )
1931         {
1932             while (!ppClipTab[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
1933 
1934             pTab[i]->CopyFromClip( nCol1, nRow1, nCol2, nRow2, nDx, nDy,
1935                 pCBFCP->nInsFlag, pCBFCP->bAsLink, pCBFCP->bSkipAttrForEmpty, ppClipTab[nClipTab] );
1936 
1937             if ( pCBFCP->pClipDoc->pDrawLayer && ( pCBFCP->nInsFlag & IDF_OBJECTS ) )
1938             {
1939                 //  also copy drawing objects
1940 
1941                 // drawing layer must be created before calling CopyFromClip
1942                 // (ScDocShell::MakeDrawLayer also does InitItems etc.)
1943                 DBG_ASSERT( pDrawLayer, "CopyBlockFromClip: No drawing layer" );
1944                 if ( pDrawLayer )
1945                 {
1946                     //  For GetMMRect, the row heights in the target document must already be valid
1947                     //  (copied in an extra step before pasting, or updated after pasting cells, but
1948                     //  before pasting objects).
1949 
1950                     Rectangle aSourceRect = pCBFCP->pClipDoc->GetMMRect(
1951                                     nCol1-nDx, nRow1-nDy, nCol2-nDx, nRow2-nDy, nClipTab );
1952                     Rectangle aDestRect = GetMMRect( nCol1, nRow1, nCol2, nRow2, i );
1953                     pDrawLayer->CopyFromClip( pCBFCP->pClipDoc->pDrawLayer, nClipTab, aSourceRect,
1954                                                 ScAddress( nCol1, nRow1, i ), aDestRect );
1955                 }
1956             }
1957 
1958             nClipTab = (nClipTab+1) % (MAXTAB+1);
1959         }
1960     }
1961     if ( pCBFCP->nInsFlag & IDF_CONTENTS )
1962     {
1963         nClipTab = 0;
1964         for (SCTAB i = pCBFCP->nTabStart; i <= nTabEnd; i++)
1965         {
1966             if (pTab[i] && rMark.GetTableSelect(i) )
1967             {
1968                 while (!ppClipTab[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
1969                 SCsTAB nDz = ((SCsTAB)i) - nClipTab;
1970 
1971                 //  #89081# ranges of consecutive selected tables (in clipboard and dest. doc)
1972                 //  must be handled in one UpdateReference call
1973                 SCTAB nFollow = 0;
1974                 while ( i + nFollow < nTabEnd
1975                         && rMark.GetTableSelect( i + nFollow + 1 )
1976                         && nClipTab + nFollow < MAXTAB
1977                         && ppClipTab[nClipTab + nFollow + 1] )
1978                     ++nFollow;
1979 
1980                 if ( pCBFCP->pClipDoc->GetClipParam().mbCutMode )
1981                 {
1982                     sal_Bool bOldInserting = IsInsertingFromOtherDoc();
1983                     SetInsertingFromOtherDoc( sal_True);
1984                     UpdateReference( URM_MOVE,
1985                         nCol1, nRow1, i, nCol2, nRow2, i+nFollow,
1986                         nDx, nDy, nDz, pCBFCP->pRefUndoDoc, sal_False );
1987                     SetInsertingFromOtherDoc( bOldInserting);
1988                 }
1989                 else
1990                     UpdateReference( URM_COPY,
1991                         nCol1, nRow1, i, nCol2, nRow2, i+nFollow,
1992                         nDx, nDy, nDz, pCBFCP->pRefUndoDoc, sal_False );
1993 
1994                 nClipTab = (nClipTab+nFollow+1) % (MAXTAB+1);
1995                 i = sal::static_int_cast<SCTAB>( i + nFollow );
1996             }
1997         }
1998     }
1999 }
2000 
2001 
2002 void ScDocument::CopyNonFilteredFromClip( SCCOL nCol1, SCROW nRow1,
2003                                     SCCOL nCol2, SCROW nRow2,
2004                                     const ScMarkData& rMark,
2005                                     SCsCOL nDx, SCsROW /* nDy */,
2006                                     const ScCopyBlockFromClipParams* pCBFCP,
2007                                     SCROW & rClipStartRow )
2008 {
2009     //  call CopyBlockFromClip for ranges of consecutive non-filtered rows
2010     //  nCol1/nRow1 etc. is in target doc
2011 
2012     //  filtered state is taken from first used table in clipboard (as in GetClipArea)
2013     SCTAB nFlagTab = 0;
2014     ScTable** ppClipTab = pCBFCP->pClipDoc->pTab;
2015     while ( nFlagTab < MAXTAB && !ppClipTab[nFlagTab] )
2016         ++nFlagTab;
2017 
2018     SCROW nSourceRow = rClipStartRow;
2019     SCROW nSourceEnd = 0;
2020     if (pCBFCP->pClipDoc->GetClipParam().maRanges.Count())
2021         nSourceEnd = pCBFCP->pClipDoc->GetClipParam().maRanges.First()->aEnd.Row();
2022     SCROW nDestRow = nRow1;
2023 
2024     while ( nSourceRow <= nSourceEnd && nDestRow <= nRow2 )
2025     {
2026         // skip filtered rows
2027         nSourceRow = pCBFCP->pClipDoc->FirstNonFilteredRow(nSourceRow, nSourceEnd, nFlagTab);
2028 
2029         if ( nSourceRow <= nSourceEnd )
2030         {
2031             // look for more non-filtered rows following
2032             SCROW nLastRow = nSourceRow;
2033             pCBFCP->pClipDoc->RowFiltered(nSourceRow, nFlagTab, NULL, &nLastRow);
2034             SCROW nFollow = nLastRow - nSourceRow;
2035 
2036             if (nFollow > nSourceEnd - nSourceRow)
2037                 nFollow = nSourceEnd - nSourceRow;
2038             if (nFollow > nRow2 - nDestRow)
2039                 nFollow = nRow2 - nDestRow;
2040 
2041             SCsROW nNewDy = ((SCsROW)nDestRow) - nSourceRow;
2042             CopyBlockFromClip( nCol1, nDestRow, nCol2, nDestRow + nFollow, rMark, nDx, nNewDy, pCBFCP );
2043 
2044             nSourceRow += nFollow + 1;
2045             nDestRow += nFollow + 1;
2046         }
2047     }
2048     rClipStartRow = nSourceRow;
2049 }
2050 
2051 
2052 void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMark,
2053                                 sal_uInt16 nInsFlag,
2054                                 ScDocument* pRefUndoDoc, ScDocument* pClipDoc, sal_Bool bResetCut,
2055                                 sal_Bool bAsLink, sal_Bool bIncludeFiltered, sal_Bool bSkipAttrForEmpty,
2056                                 const ScRangeList * pDestRanges )
2057 {
2058     if (!bIsClip)
2059     {
2060         if (!pClipDoc)
2061         {
2062             DBG_ERROR("CopyFromClip: no ClipDoc");
2063             pClipDoc = SC_MOD()->GetClipDoc();
2064         }
2065         if (pClipDoc->bIsClip && pClipDoc->GetTableCount())
2066         {
2067             sal_Bool bOldAutoCalc = GetAutoCalc();
2068             SetAutoCalc( sal_False );   // avoid multiple recalculations
2069 
2070             NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
2071 
2072             ScClipRangeNameData aClipRangeNames;
2073             CopyRangeNamesFromClip(pClipDoc, aClipRangeNames);
2074 
2075             SCCOL nAllCol1 = rDestRange.aStart.Col();
2076             SCROW nAllRow1 = rDestRange.aStart.Row();
2077             SCCOL nAllCol2 = rDestRange.aEnd.Col();
2078             SCROW nAllRow2 = rDestRange.aEnd.Row();
2079 
2080             SCCOL nXw = 0;
2081             SCROW nYw = 0;
2082             ScRange aClipRange = pClipDoc->GetClipParam().getWholeRange();
2083             for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)    // find largest merge overlap
2084                 if (pClipDoc->pTab[nTab])                   // all sheets of the clipboard content
2085                 {
2086                     SCCOL nThisEndX = aClipRange.aEnd.Col();
2087                     SCROW nThisEndY = aClipRange.aEnd.Row();
2088                     pClipDoc->ExtendMerge( aClipRange.aStart.Col(),
2089                                             aClipRange.aStart.Row(),
2090                                             nThisEndX, nThisEndY, nTab );
2091                     // only extra value from ExtendMerge
2092                     nThisEndX = sal::static_int_cast<SCCOL>( nThisEndX - aClipRange.aEnd.Col() );
2093                     nThisEndY = sal::static_int_cast<SCROW>( nThisEndY - aClipRange.aEnd.Row() );
2094                     if ( nThisEndX > nXw )
2095                         nXw = nThisEndX;
2096                     if ( nThisEndY > nYw )
2097                         nYw = nThisEndY;
2098                 }
2099 
2100             SCCOL nDestAddX;
2101             SCROW nDestAddY;
2102             pClipDoc->GetClipArea( nDestAddX, nDestAddY, bIncludeFiltered );
2103             nXw = sal::static_int_cast<SCCOL>( nXw + nDestAddX );
2104             nYw = sal::static_int_cast<SCROW>( nYw + nDestAddY );   // ClipArea, plus ExtendMerge value
2105 
2106             /*  Decide which contents to delete before copying. Delete all
2107                 contents if nInsFlag contains any real content flag.
2108                 #i102056# Notes are pasted from clipboard in a second pass,
2109                 together with the special flag IDF_ADDNOTES that states to not
2110                 overwrite/delete existing cells but to insert the notes into
2111                 these cells. In this case, just delete old notes from the
2112                 destination area. */
2113             sal_uInt16 nDelFlag = IDF_NONE;
2114             if ( (nInsFlag & (IDF_CONTENTS | IDF_ADDNOTES)) == (IDF_NOTE | IDF_ADDNOTES) )
2115                 nDelFlag |= IDF_NOTE;
2116             else if ( nInsFlag & IDF_CONTENTS )
2117                 nDelFlag |= IDF_CONTENTS;
2118             //  With bSkipAttrForEmpty, don't remove attributes, copy
2119             //  on top of existing attributes instead.
2120             if ( ( nInsFlag & IDF_ATTRIB ) && !bSkipAttrForEmpty )
2121                 nDelFlag |= IDF_ATTRIB;
2122 
2123             ScCopyBlockFromClipParams aCBFCP;
2124             aCBFCP.pRefUndoDoc = pRefUndoDoc;
2125             aCBFCP.pClipDoc = pClipDoc;
2126             aCBFCP.nInsFlag = nInsFlag;
2127             aCBFCP.bAsLink  = bAsLink;
2128             aCBFCP.bSkipAttrForEmpty = bSkipAttrForEmpty;
2129             aCBFCP.nTabStart = MAXTAB;      // wird in der Schleife angepasst
2130             aCBFCP.nTabEnd = 0;             // wird in der Schleife angepasst
2131 
2132             //  Inc/DecRecalcLevel einmal aussen, damit nicht fuer jeden Block
2133             //  die Draw-Seitengroesse neu berechnet werden muss
2134             //! nur wenn ganze Zeilen/Spalten kopiert werden?
2135 
2136             for (SCTAB j = 0; j <= MAXTAB; j++)
2137                 if (pTab[j] && rMark.GetTableSelect(j))
2138                 {
2139                     if ( j < aCBFCP.nTabStart )
2140                         aCBFCP.nTabStart = j;
2141                     aCBFCP.nTabEnd = j;
2142                     pTab[j]->IncRecalcLevel();
2143                 }
2144 
2145             ScRangeList aLocalRangeList;
2146             if (!pDestRanges)
2147             {
2148                 aLocalRangeList.Append( rDestRange);
2149                 pDestRanges = &aLocalRangeList;
2150             }
2151 
2152             bInsertingFromOtherDoc = sal_True;  // kein Broadcast/Listener aufbauen bei Insert
2153 
2154             // bei mindestens 64 Zeilen wird in ScColumn::CopyFromClip voralloziert
2155             sal_Bool bDoDouble = ( nYw < 64 && nAllRow2 - nAllRow1 > 64);
2156             sal_Bool bOldDouble = ScColumn::bDoubleAlloc;
2157             if (bDoDouble)
2158                 ScColumn::bDoubleAlloc = sal_True;
2159 
2160             SCCOL nClipStartCol = aClipRange.aStart.Col();
2161             SCROW nClipStartRow = aClipRange.aStart.Row();
2162             // WaE: commented because unused:   SCCOL nClipEndCol = pClipDoc->aClipRange.aEnd.Col();
2163             SCROW nClipEndRow = aClipRange.aEnd.Row();
2164             for (sal_uLong nRange = 0; nRange < pDestRanges->Count(); ++nRange)
2165             {
2166                 const ScRange* pRange = pDestRanges->GetObject( nRange);
2167                 SCCOL nCol1 = pRange->aStart.Col();
2168                 SCROW nRow1 = pRange->aStart.Row();
2169                 SCCOL nCol2 = pRange->aEnd.Col();
2170                 SCROW nRow2 = pRange->aEnd.Row();
2171 
2172                 DeleteArea(nCol1, nRow1, nCol2, nRow2, rMark, nDelFlag);
2173 
2174                 SCCOL nC1 = nCol1;
2175                 SCROW nR1 = nRow1;
2176                 SCCOL nC2 = nC1 + nXw;
2177                 if (nC2 > nCol2)
2178                     nC2 = nCol2;
2179                 SCROW nR2 = nR1 + nYw;
2180                 if (nR2 > nRow2)
2181                     nR2 = nRow2;
2182 
2183                 do
2184                 {
2185                     // Pasting is done column-wise, when pasting to a filtered
2186                     // area this results in partitioning and we have to
2187                     // remember and reset the start row for each column until
2188                     // it can be advanced for the next chunk of unfiltered
2189                     // rows.
2190                     SCROW nSaveClipStartRow = nClipStartRow;
2191                     do
2192                     {
2193                         nClipStartRow = nSaveClipStartRow;
2194                         SCsCOL nDx = ((SCsCOL)nC1) - nClipStartCol;
2195                         SCsROW nDy = ((SCsROW)nR1) - nClipStartRow;
2196                         if ( bIncludeFiltered )
2197                         {
2198                             CopyBlockFromClip( nC1, nR1, nC2, nR2, rMark, nDx,
2199                                     nDy, &aCBFCP );
2200                             nClipStartRow += nR2 - nR1 + 1;
2201                         }
2202                         else
2203                         {
2204                             CopyNonFilteredFromClip( nC1, nR1, nC2, nR2, rMark,
2205                                     nDx, nDy, &aCBFCP, nClipStartRow );
2206                         }
2207                         // Not needed for columns, but if it was this would be how to.
2208                         //if (nClipStartCol > nClipEndCol)
2209                         //    nClipStartCol = pClipDoc->aClipRange.aStart.Col();
2210                         nC1 = nC2 + 1;
2211                         nC2 = Min((SCCOL)(nC1 + nXw), nCol2);
2212                     } while (nC1 <= nCol2);
2213                     if (nClipStartRow > nClipEndRow)
2214                         nClipStartRow = aClipRange.aStart.Row();
2215                     nC1 = nCol1;
2216                     nC2 = nC1 + nXw;
2217                     if (nC2 > nCol2)
2218                         nC2 = nCol2;
2219                     nR1 = nR2 + 1;
2220                     nR2 = Min((SCROW)(nR1 + nYw), nRow2);
2221                 } while (nR1 <= nRow2);
2222             }
2223 
2224             ScColumn::bDoubleAlloc = bOldDouble;
2225 
2226             for (SCTAB k = 0; k <= MAXTAB; k++)
2227                 if (pTab[k] && rMark.GetTableSelect(k))
2228                     pTab[k]->DecRecalcLevel();
2229 
2230             bInsertingFromOtherDoc = sal_False;
2231 
2232             UpdateRangeNamesInFormulas(aClipRangeNames, *pDestRanges, rMark, nXw, nYw);
2233 
2234             // Listener aufbauen nachdem alles inserted wurde
2235             StartListeningFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
2236             // nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
2237             BroadcastFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
2238             if (bResetCut)
2239                 pClipDoc->GetClipParam().mbCutMode = false;
2240             SetAutoCalc( bOldAutoCalc );
2241         }
2242     }
2243 }
2244 
2245 static SCROW lcl_getLastNonFilteredRow(
2246     const ScBitMaskCompressedArray<SCROW, sal_uInt8>& rFlags, SCROW nBegRow, SCROW nEndRow,
2247     SCROW nRowCount)
2248 {
2249     SCROW nFilteredRow = rFlags.GetFirstForCondition(
2250         nBegRow, nEndRow, CR_FILTERED, CR_FILTERED);
2251 
2252     SCROW nRow = nFilteredRow - 1;
2253     if (nRow - nBegRow + 1 > nRowCount)
2254         // make sure the row range stays within the data size.
2255         nRow = nBegRow + nRowCount - 1;
2256 
2257     return nRow;
2258 }
2259 
2260 void ScDocument::CopyMultiRangeFromClip(
2261     const ScAddress& rDestPos, const ScMarkData& rMark, sal_uInt16 nInsFlag, ScDocument* pClipDoc,
2262     bool bResetCut, bool bAsLink, bool /*bIncludeFiltered*/, bool bSkipAttrForEmpty)
2263 {
2264     if (bIsClip)
2265         return;
2266 
2267     if (!pClipDoc->bIsClip || !pClipDoc->GetTableCount())
2268         // There is nothing in the clip doc to copy.
2269         return;
2270 
2271     sal_Bool bOldAutoCalc = GetAutoCalc();
2272     SetAutoCalc( sal_False );   // avoid multiple recalculations
2273 
2274     NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
2275 
2276     ScClipRangeNameData aClipRangeNames;
2277     CopyRangeNamesFromClip(pClipDoc, aClipRangeNames);
2278 
2279     SCCOL nCol1 = rDestPos.Col();
2280     SCROW nRow1 = rDestPos.Row();
2281     ScClipParam& rClipParam = pClipDoc->GetClipParam();
2282 
2283     ScCopyBlockFromClipParams aCBFCP;
2284     aCBFCP.pRefUndoDoc = NULL;
2285     aCBFCP.pClipDoc = pClipDoc;
2286     aCBFCP.nInsFlag = nInsFlag;
2287     aCBFCP.bAsLink  = bAsLink;
2288     aCBFCP.bSkipAttrForEmpty = bSkipAttrForEmpty;
2289     aCBFCP.nTabStart = MAXTAB;
2290     aCBFCP.nTabEnd = 0;
2291 
2292     for (SCTAB j = 0; j <= MAXTAB; ++j)
2293     {
2294         if (pTab[j] && rMark.GetTableSelect(j))
2295         {
2296             if ( j < aCBFCP.nTabStart )
2297                 aCBFCP.nTabStart = j;
2298             aCBFCP.nTabEnd = j;
2299             pTab[j]->IncRecalcLevel();
2300         }
2301     }
2302 
2303     ScRange aDestRange;
2304     rMark.GetMarkArea(aDestRange);
2305     SCROW nLastMarkedRow = aDestRange.aEnd.Row();
2306 
2307     bInsertingFromOtherDoc = sal_True;  // kein Broadcast/Listener aufbauen bei Insert
2308 
2309     SCROW nBegRow = nRow1;
2310     sal_uInt16 nDelFlag = IDF_CONTENTS;
2311     const ScBitMaskCompressedArray<SCROW, sal_uInt8>& rFlags = GetRowFlagsArray(aCBFCP.nTabStart);
2312 
2313     for (ScRange* p = rClipParam.maRanges.First(); p; p = rClipParam.maRanges.Next())
2314     {
2315         // The begin row must not be filtered.
2316 
2317         SCROW nRowCount = p->aEnd.Row() - p->aStart.Row() + 1;
2318 
2319         SCsCOL nDx = static_cast<SCsCOL>(nCol1 - p->aStart.Col());
2320         SCsROW nDy = static_cast<SCsROW>(nBegRow - p->aStart.Row());
2321         SCCOL nCol2 = nCol1 + p->aEnd.Col() - p->aStart.Col();
2322 
2323         SCROW nEndRow = lcl_getLastNonFilteredRow(rFlags, nBegRow, nLastMarkedRow, nRowCount);
2324 
2325         if (!bSkipAttrForEmpty)
2326             DeleteArea(nCol1, nBegRow, nCol2, nEndRow, rMark, nDelFlag);
2327 
2328         CopyBlockFromClip(nCol1, nBegRow, nCol2, nEndRow, rMark, nDx, nDy, &aCBFCP);
2329         nRowCount -= nEndRow - nBegRow + 1;
2330 
2331         while (nRowCount > 0)
2332         {
2333             // Get the first non-filtered row.
2334             SCROW nNonFilteredRow = rFlags.GetFirstForCondition(nEndRow+1, nLastMarkedRow, CR_FILTERED, 0);
2335             if (nNonFilteredRow > nLastMarkedRow)
2336                 return;
2337 
2338             SCROW nRowsSkipped = nNonFilteredRow - nEndRow - 1;
2339             nDy += nRowsSkipped;
2340 
2341             nBegRow = nNonFilteredRow;
2342             nEndRow = lcl_getLastNonFilteredRow(rFlags, nBegRow, nLastMarkedRow, nRowCount);
2343 
2344             if (!bSkipAttrForEmpty)
2345                 DeleteArea(nCol1, nBegRow, nCol2, nEndRow, rMark, nDelFlag);
2346 
2347             CopyBlockFromClip(nCol1, nBegRow, nCol2, nEndRow, rMark, nDx, nDy, &aCBFCP);
2348             nRowCount -= nEndRow - nBegRow + 1;
2349         }
2350 
2351         if (rClipParam.meDirection == ScClipParam::Row)
2352             // Begin row for the next range being pasted.
2353             nBegRow = rFlags.GetFirstForCondition(nEndRow+1, nLastMarkedRow, CR_FILTERED, 0);
2354         else
2355             nBegRow = nRow1;
2356 
2357         if (rClipParam.meDirection == ScClipParam::Column)
2358             nCol1 += p->aEnd.Col() - p->aStart.Col() + 1;
2359     }
2360 
2361     for (SCTAB i = 0; i <= MAXTAB; i++)
2362         if (pTab[i] && rMark.GetTableSelect(i))
2363             pTab[i]->DecRecalcLevel();
2364 
2365     bInsertingFromOtherDoc = sal_False;
2366 
2367     ScRangeList aRanges;
2368     aRanges.Append(aDestRange);
2369     SCCOL nCols = aDestRange.aEnd.Col() - aDestRange.aStart.Col() + 1;
2370     SCROW nRows = aDestRange.aEnd.Row() - aDestRange.aStart.Row() + 1;
2371     UpdateRangeNamesInFormulas(aClipRangeNames, aRanges, rMark, nCols-1, nRows-1);
2372 
2373     // Listener aufbauen nachdem alles inserted wurde
2374     StartListeningFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
2375                            aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
2376     // nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
2377     BroadcastFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
2378                       aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
2379 
2380     if (bResetCut)
2381         pClipDoc->GetClipParam().mbCutMode = false;
2382     SetAutoCalc( bOldAutoCalc );
2383 }
2384 
2385 void ScDocument::SetClipArea( const ScRange& rArea, sal_Bool bCut )
2386 {
2387     if (bIsClip)
2388     {
2389         ScClipParam& rClipParam = GetClipParam();
2390         rClipParam.maRanges.RemoveAll();
2391         rClipParam.maRanges.Append(rArea);
2392         rClipParam.mbCutMode = bCut;
2393     }
2394     else
2395     {
2396         DBG_ERROR("SetClipArea: kein Clip");
2397     }
2398 }
2399 
2400 
2401 void ScDocument::GetClipArea(SCCOL& nClipX, SCROW& nClipY, sal_Bool bIncludeFiltered)
2402 {
2403     if (!bIsClip)
2404     {
2405         DBG_ERROR("GetClipArea: kein Clip");
2406         return;
2407     }
2408 
2409     ScRangeList& rClipRanges = GetClipParam().maRanges;
2410     if (!rClipRanges.Count())
2411         // No clip range.  Bail out.
2412         return;
2413 
2414     ScRangePtr p = rClipRanges.First();
2415     SCCOL nStartCol = p->aStart.Col();
2416     SCCOL nEndCol   = p->aEnd.Col();
2417     SCROW nStartRow = p->aStart.Row();
2418     SCROW nEndRow   = p->aEnd.Row();
2419     for (p = rClipRanges.Next(); p; p = rClipRanges.Next())
2420     {
2421         if (p->aStart.Col() < nStartCol)
2422             nStartCol = p->aStart.Col();
2423         if (p->aStart.Row() < nStartRow)
2424             nStartRow = p->aStart.Row();
2425         if (p->aEnd.Col() > nEndCol)
2426             nEndCol = p->aEnd.Col();
2427         if (p->aEnd.Row() < nEndRow)
2428             nEndRow = p->aEnd.Row();
2429     }
2430 
2431     nClipX = nEndCol - nStartCol;
2432 
2433     if ( bIncludeFiltered )
2434         nClipY = nEndRow - nStartRow;
2435     else
2436     {
2437         //  count non-filtered rows
2438         //  count on first used table in clipboard
2439         SCTAB nCountTab = 0;
2440         while ( nCountTab < MAXTAB && !pTab[nCountTab] )
2441             ++nCountTab;
2442 
2443         SCROW nResult = CountNonFilteredRows(nStartRow, nEndRow, nCountTab);
2444 
2445         if ( nResult > 0 )
2446             nClipY = nResult - 1;
2447         else
2448             nClipY = 0;                 // always return at least 1 row
2449     }
2450 }
2451 
2452 
2453 void ScDocument::GetClipStart(SCCOL& nClipX, SCROW& nClipY)
2454 {
2455     if (bIsClip)
2456     {
2457         ScRangeList& rClipRanges = GetClipParam().maRanges;
2458         if (rClipRanges.Count())
2459         {
2460             nClipX = rClipRanges.First()->aStart.Col();
2461             nClipY = rClipRanges.First()->aStart.Row();
2462         }
2463     }
2464     else
2465     {
2466         DBG_ERROR("GetClipStart: kein Clip");
2467     }
2468 }
2469 
2470 
2471 sal_Bool ScDocument::HasClipFilteredRows()
2472 {
2473     //  count on first used table in clipboard
2474     SCTAB nCountTab = 0;
2475     while ( nCountTab < MAXTAB && !pTab[nCountTab] )
2476         ++nCountTab;
2477 
2478     ScRangeList& rClipRanges = GetClipParam().maRanges;
2479     if (!rClipRanges.Count())
2480         return false;
2481 
2482     for (ScRange* p = rClipRanges.First(); p; p = rClipRanges.Next())
2483     {
2484         bool bAnswer = pTab[nCountTab]->HasFilteredRows(p->aStart.Row(), p->aEnd.Row());
2485         if (bAnswer)
2486             return true;
2487     }
2488     return false;
2489 }
2490 
2491 
2492 void ScDocument::MixDocument( const ScRange& rRange, sal_uInt16 nFunction, sal_Bool bSkipEmpty,
2493                                     ScDocument* pSrcDoc )
2494 {
2495     SCTAB nTab1 = rRange.aStart.Tab();
2496     SCTAB nTab2 = rRange.aEnd.Tab();
2497     for (SCTAB i = nTab1; i <= nTab2; i++)
2498         if (pTab[i] && pSrcDoc->pTab[i])
2499             pTab[i]->MixData( rRange.aStart.Col(), rRange.aStart.Row(),
2500                                 rRange.aEnd.Col(), rRange.aEnd.Row(),
2501                                 nFunction, bSkipEmpty, pSrcDoc->pTab[i] );
2502 }
2503 
2504 
2505 void ScDocument::FillTab( const ScRange& rSrcArea, const ScMarkData& rMark,
2506                                 sal_uInt16 nFlags, sal_uInt16 nFunction,
2507                                 sal_Bool bSkipEmpty, sal_Bool bAsLink )
2508 {
2509     sal_uInt16 nDelFlags = nFlags;
2510     if (nDelFlags & IDF_CONTENTS)
2511         nDelFlags |= IDF_CONTENTS;          // immer alle Inhalte oder keine loeschen!
2512 
2513     SCTAB nSrcTab = rSrcArea.aStart.Tab();
2514 
2515     if (ValidTab(nSrcTab)  && pTab[nSrcTab])
2516     {
2517         SCCOL nStartCol = rSrcArea.aStart.Col();
2518         SCROW nStartRow = rSrcArea.aStart.Row();
2519         SCCOL nEndCol = rSrcArea.aEnd.Col();
2520         SCROW nEndRow = rSrcArea.aEnd.Row();
2521         ScDocument* pMixDoc = NULL;
2522         sal_Bool bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
2523 
2524         sal_Bool bOldAutoCalc = GetAutoCalc();
2525         SetAutoCalc( sal_False );                   // Mehrfachberechnungen vermeiden
2526 
2527         SCTAB nCount = GetTableCount();
2528         for (SCTAB i=0; i<nCount; i++)
2529             if ( i!=nSrcTab && pTab[i] && rMark.GetTableSelect(i) )
2530             {
2531                 if (bDoMix)
2532                 {
2533                     if (!pMixDoc)
2534                     {
2535                         pMixDoc = new ScDocument( SCDOCMODE_UNDO );
2536                         pMixDoc->InitUndo( this, i, i );
2537                     }
2538                     else
2539                         pMixDoc->AddUndoTab( i, i );
2540                     pTab[i]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2541                                             IDF_CONTENTS, sal_False, pMixDoc->pTab[i] );
2542                 }
2543                 pTab[i]->DeleteArea( nStartCol,nStartRow, nEndCol,nEndRow, nDelFlags);
2544                 pTab[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2545                                                  nFlags, sal_False, pTab[i], NULL, bAsLink );
2546 
2547                 if (bDoMix)
2548                     pTab[i]->MixData( nStartCol,nStartRow, nEndCol,nEndRow,
2549                                         nFunction, bSkipEmpty, pMixDoc->pTab[i] );
2550             }
2551 
2552         delete pMixDoc;
2553 
2554         SetAutoCalc( bOldAutoCalc );
2555     }
2556     else
2557     {
2558         DBG_ERROR("falsche Tabelle");
2559     }
2560 }
2561 
2562 
2563 void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
2564                                 sal_uInt16 nFlags, sal_uInt16 nFunction,
2565                                 sal_Bool bSkipEmpty, sal_Bool bAsLink )
2566 {
2567     sal_uInt16 nDelFlags = nFlags;
2568     if (nDelFlags & IDF_CONTENTS)
2569         nDelFlags |= IDF_CONTENTS;          // immer alle Inhalte oder keine loeschen!
2570 
2571     if (ValidTab(nSrcTab)  && pTab[nSrcTab])
2572     {
2573         ScDocument* pMixDoc = NULL;
2574         sal_Bool bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
2575 
2576         sal_Bool bOldAutoCalc = GetAutoCalc();
2577         SetAutoCalc( sal_False );                   // Mehrfachberechnungen vermeiden
2578 
2579         ScRange aArea;
2580         rMark.GetMultiMarkArea( aArea );
2581         SCCOL nStartCol = aArea.aStart.Col();
2582         SCROW nStartRow = aArea.aStart.Row();
2583         SCCOL nEndCol = aArea.aEnd.Col();
2584         SCROW nEndRow = aArea.aEnd.Row();
2585 
2586         SCTAB nCount = GetTableCount();
2587         for (SCTAB i=0; i<nCount; i++)
2588             if ( i!=nSrcTab && pTab[i] && rMark.GetTableSelect(i) )
2589             {
2590                 if (bDoMix)
2591                 {
2592                     if (!pMixDoc)
2593                     {
2594                         pMixDoc = new ScDocument( SCDOCMODE_UNDO );
2595                         pMixDoc->InitUndo( this, i, i );
2596                     }
2597                     else
2598                         pMixDoc->AddUndoTab( i, i );
2599                     pTab[i]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2600                                             IDF_CONTENTS, sal_True, pMixDoc->pTab[i], &rMark );
2601                 }
2602 
2603                 pTab[i]->DeleteSelection( nDelFlags, rMark );
2604                 pTab[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2605                                              nFlags, sal_True, pTab[i], &rMark, bAsLink );
2606 
2607                 if (bDoMix)
2608                     pTab[i]->MixMarked( rMark, nFunction, bSkipEmpty, pMixDoc->pTab[i] );
2609             }
2610 
2611         delete pMixDoc;
2612 
2613         SetAutoCalc( bOldAutoCalc );
2614     }
2615     else
2616     {
2617         DBG_ERROR("falsche Tabelle");
2618     }
2619 }
2620 
2621 
2622 void ScDocument::PutCell( SCCOL nCol, SCROW nRow, SCTAB nTab, ScBaseCell* pCell, sal_Bool bForceTab )
2623 {
2624     if (VALIDTAB(nTab))
2625     {
2626         if ( bForceTab && !pTab[nTab] )
2627         {
2628             sal_Bool bExtras = !bIsUndo;        // Spaltenbreiten, Zeilenhoehen, Flags
2629 
2630             pTab[nTab] = new ScTable(this, nTab,
2631                             String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("temp")),
2632                             bExtras, bExtras);
2633             ++nMaxTableNumber;
2634         }
2635 
2636         if (pTab[nTab])
2637             pTab[nTab]->PutCell( nCol, nRow, pCell );
2638     }
2639 }
2640 
2641 
2642 void ScDocument::PutCell( const ScAddress& rPos, ScBaseCell* pCell, sal_Bool bForceTab )
2643 {
2644     SCTAB nTab = rPos.Tab();
2645     if ( bForceTab && !pTab[nTab] )
2646     {
2647         sal_Bool bExtras = !bIsUndo;        // Spaltenbreiten, Zeilenhoehen, Flags
2648 
2649         pTab[nTab] = new ScTable(this, nTab,
2650                         String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("temp")),
2651                         bExtras, bExtras);
2652         ++nMaxTableNumber;
2653     }
2654 
2655     if (pTab[nTab])
2656         pTab[nTab]->PutCell( rPos, pCell );
2657 }
2658 
2659 
2660 sal_Bool ScDocument::SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rString,
2661                             SvNumberFormatter* pFormatter, bool bDetectNumberFormat )
2662 {
2663     if ( ValidTab(nTab) && pTab[nTab] )
2664         return pTab[nTab]->SetString( nCol, nRow, nTab, rString, pFormatter, bDetectNumberFormat );
2665     else
2666         return sal_False;
2667 }
2668 
2669 
2670 void ScDocument::SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal )
2671 {
2672     if (VALIDTAB(nTab))
2673         if (pTab[nTab])
2674             pTab[nTab]->SetValue( nCol, nRow, rVal );
2675 }
2676 
2677 
2678 void ScDocument::GetString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString )
2679 {
2680     if ( VALIDTAB(nTab) && pTab[nTab] )
2681         pTab[nTab]->GetString( nCol, nRow, rString );
2682     else
2683         rString.Erase();
2684 }
2685 
2686 
2687 void ScDocument::GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString )
2688 {
2689     if ( VALIDTAB(nTab) && pTab[nTab] )
2690         pTab[nTab]->GetInputString( nCol, nRow, rString );
2691     else
2692         rString.Erase();
2693 }
2694 
2695 
2696 sal_uInt16 ScDocument::GetStringForFormula( const ScAddress& rPos, rtl::OUString& rString )
2697 {
2698     // Used in formulas (add-in parameters etc), so it must use the same semantics as
2699     // ScInterpreter::GetCellString: always format values as numbers.
2700     // The return value is the error code.
2701 
2702     sal_uInt16 nErr = 0;
2703     String aStr;
2704     ScBaseCell* pCell = GetCell( rPos );
2705     if (pCell)
2706     {
2707         SvNumberFormatter* pFormatter = GetFormatTable();
2708         switch (pCell->GetCellType())
2709         {
2710             case CELLTYPE_STRING:
2711                 static_cast<ScStringCell*>(pCell)->GetString(aStr);
2712             break;
2713             case CELLTYPE_EDIT:
2714                 static_cast<ScEditCell*>(pCell)->GetString(aStr);
2715             break;
2716             case CELLTYPE_FORMULA:
2717             {
2718                 ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
2719                 nErr = pFCell->GetErrCode();
2720                 if (pFCell->IsValue())
2721                 {
2722                     double fVal = pFCell->GetValue();
2723                     sal_uInt32 nIndex = pFormatter->GetStandardFormat(
2724                                         NUMBERFORMAT_NUMBER,
2725                                         ScGlobal::eLnge);
2726                     pFormatter->GetInputLineString(fVal, nIndex, aStr);
2727                 }
2728                 else
2729                     pFCell->GetString(aStr);
2730             }
2731             break;
2732             case CELLTYPE_VALUE:
2733             {
2734                 double fVal = static_cast<ScValueCell*>(pCell)->GetValue();
2735                 sal_uInt32 nIndex = pFormatter->GetStandardFormat(
2736                                         NUMBERFORMAT_NUMBER,
2737                                         ScGlobal::eLnge);
2738                 pFormatter->GetInputLineString(fVal, nIndex, aStr);
2739             }
2740             break;
2741             default:
2742                 ;
2743         }
2744     }
2745     rString = aStr;
2746     return nErr;
2747 }
2748 
2749 
2750 void ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, double& rValue )
2751 {
2752     if ( VALIDTAB(nTab) && pTab[nTab] )
2753         rValue = pTab[nTab]->GetValue( nCol, nRow );
2754     else
2755         rValue = 0.0;
2756 }
2757 
2758 
2759 double ScDocument::GetValue( const ScAddress& rPos )
2760 {
2761     SCTAB nTab = rPos.Tab();
2762     if ( pTab[nTab] )
2763         return pTab[nTab]->GetValue( rPos );
2764     return 0.0;
2765 }
2766 
2767 
2768 void ScDocument::GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab,
2769                                   sal_uInt32& rFormat )
2770 {
2771     if (VALIDTAB(nTab))
2772         if (pTab[nTab])
2773         {
2774             rFormat = pTab[nTab]->GetNumberFormat( nCol, nRow );
2775             return ;
2776         }
2777     rFormat = 0;
2778 }
2779 
2780 
2781 sal_uInt32 ScDocument::GetNumberFormat( const ScAddress& rPos ) const
2782 {
2783     SCTAB nTab = rPos.Tab();
2784     if ( pTab[nTab] )
2785         return pTab[nTab]->GetNumberFormat( rPos );
2786     return 0;
2787 }
2788 
2789 
2790 void ScDocument::GetNumberFormatInfo( short& nType, sal_uLong& nIndex,
2791             const ScAddress& rPos, const ScBaseCell* pCell ) const
2792 {
2793     SCTAB nTab = rPos.Tab();
2794     if ( pTab[nTab] )
2795     {
2796         nIndex = pTab[nTab]->GetNumberFormat( rPos );
2797         if ( (nIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && pCell &&
2798                 pCell->GetCellType() == CELLTYPE_FORMULA )
2799             static_cast<const ScFormulaCell*>(pCell)->GetFormatInfo( nType, nIndex );
2800         else
2801             nType = GetFormatTable()->GetType( nIndex );
2802     }
2803     else
2804     {
2805         nType = NUMBERFORMAT_UNDEFINED;
2806         nIndex = 0;
2807     }
2808 }
2809 
2810 
2811 void ScDocument::GetFormula( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rFormula,
2812                              sal_Bool bAsciiExport ) const
2813 {
2814     if ( VALIDTAB(nTab) && pTab[nTab] )
2815             pTab[nTab]->GetFormula( nCol, nRow, rFormula, bAsciiExport );
2816     else
2817         rFormula.Erase();
2818 }
2819 
2820 
2821 CellType ScDocument::GetCellType( const ScAddress& rPos ) const
2822 {
2823     SCTAB nTab = rPos.Tab();
2824     if ( pTab[nTab] )
2825         return pTab[nTab]->GetCellType( rPos );
2826     return CELLTYPE_NONE;
2827 }
2828 
2829 
2830 void ScDocument::GetCellType( SCCOL nCol, SCROW nRow, SCTAB nTab,
2831         CellType& rCellType ) const
2832 {
2833     if (ValidTab(nTab) && pTab[nTab])
2834         rCellType = pTab[nTab]->GetCellType( nCol, nRow );
2835     else
2836         rCellType = CELLTYPE_NONE;
2837 }
2838 
2839 
2840 void ScDocument::GetCell( SCCOL nCol, SCROW nRow, SCTAB nTab,
2841         ScBaseCell*& rpCell ) const
2842 {
2843     if (ValidTab(nTab) && pTab[nTab])
2844         rpCell = pTab[nTab]->GetCell( nCol, nRow );
2845     else
2846     {
2847         DBG_ERROR("GetCell ohne Tabelle");
2848         rpCell = NULL;
2849     }
2850 }
2851 
2852 
2853 ScBaseCell* ScDocument::GetCell( const ScAddress& rPos ) const
2854 {
2855     SCTAB nTab = rPos.Tab();
2856     if (ValidTab(nTab) && pTab[nTab])
2857         return pTab[nTab]->GetCell( rPos );
2858 
2859     DBG_ERROR("GetCell ohne Tabelle");
2860     return NULL;
2861 }
2862 
2863 
2864 sal_Bool ScDocument::HasStringData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
2865 {
2866     if ( VALIDTAB(nTab) && pTab[nTab] )
2867             return pTab[nTab]->HasStringData( nCol, nRow );
2868     else
2869         return sal_False;
2870 }
2871 
2872 
2873 sal_Bool ScDocument::HasValueData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
2874 {
2875     if ( VALIDTAB(nTab) && pTab[nTab] )
2876             return pTab[nTab]->HasValueData( nCol, nRow );
2877     else
2878         return sal_False;
2879 }
2880 
2881 
2882 sal_Bool ScDocument::HasStringCells( const ScRange& rRange ) const
2883 {
2884     //  sal_True, wenn String- oder Editzellen im Bereich
2885 
2886     SCCOL nStartCol = rRange.aStart.Col();
2887     SCROW nStartRow = rRange.aStart.Row();
2888     SCTAB nStartTab = rRange.aStart.Tab();
2889     SCCOL nEndCol = rRange.aEnd.Col();
2890     SCROW nEndRow = rRange.aEnd.Row();
2891     SCTAB nEndTab = rRange.aEnd.Tab();
2892 
2893     for ( SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++ )
2894         if ( pTab[nTab] && pTab[nTab]->HasStringCells( nStartCol, nStartRow, nEndCol, nEndRow ) )
2895             return sal_True;
2896 
2897     return sal_False;
2898 }
2899 
2900 
2901 sal_Bool ScDocument::HasSelectionData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
2902 {
2903     sal_uInt32 nValidation = static_cast< const SfxUInt32Item* >( GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA ) )->GetValue();
2904     if( nValidation )
2905     {
2906         const ScValidationData* pData = GetValidationEntry( nValidation );
2907         if( pData && pData->HasSelectionList() )
2908             return sal_True;
2909     }
2910     return HasStringCells( ScRange( nCol, 0, nTab, nCol, MAXROW, nTab ) );
2911 }
2912 
2913 
2914 ScPostIt* ScDocument::GetNote( const ScAddress& rPos )
2915 {
2916     ScTable* pTable = ValidTab( rPos.Tab() ) ? pTab[ rPos.Tab() ] : 0;
2917     return pTable ? pTable->GetNote( rPos.Col(), rPos.Row() ) : 0;
2918 }
2919 
2920 
2921 void ScDocument::TakeNote( const ScAddress& rPos, ScPostIt*& rpNote )
2922 {
2923     if( ValidTab( rPos.Tab() ) && pTab[ rPos.Tab() ] )
2924         pTab[ rPos.Tab() ]->TakeNote( rPos.Col(), rPos.Row(), rpNote );
2925     else
2926         DELETEZ( rpNote );
2927 }
2928 
2929 
2930 ScPostIt* ScDocument::ReleaseNote( const ScAddress& rPos )
2931 {
2932     ScTable* pTable = ValidTab( rPos.Tab() ) ? pTab[ rPos.Tab() ] : 0;
2933     return pTable ? pTable->ReleaseNote( rPos.Col(), rPos.Row() ) : 0;
2934 }
2935 
2936 
2937 ScPostIt* ScDocument::GetOrCreateNote( const ScAddress& rPos )
2938 {
2939     ScPostIt* pNote = GetNote( rPos );
2940     if( !pNote )
2941     {
2942         pNote = new ScPostIt( *this, rPos, false );
2943         TakeNote( rPos, pNote );
2944     }
2945     return pNote;
2946 }
2947 
2948 
2949 void ScDocument::DeleteNote( const ScAddress& rPos )
2950 {
2951     if( ValidTab( rPos.Tab() ) && pTab[ rPos.Tab() ] )
2952         pTab[ rPos.Tab() ]->DeleteNote( rPos.Col(), rPos.Row() );
2953 }
2954 
2955 
2956 void ScDocument::InitializeNoteCaptions( SCTAB nTab, bool bForced )
2957 {
2958     if( ValidTab( nTab ) && pTab[ nTab ] )
2959         pTab[ nTab ]->InitializeNoteCaptions( bForced );
2960 }
2961 
2962 void ScDocument::InitializeAllNoteCaptions( bool bForced )
2963 {
2964     for( SCTAB nTab = 0; nTab < GetTableCount(); ++nTab )
2965         InitializeNoteCaptions( nTab, bForced );
2966 }
2967 
2968 void ScDocument::SetDirty()
2969 {
2970     sal_Bool bOldAutoCalc = GetAutoCalc();
2971     bAutoCalc = sal_False;      // keine Mehrfachberechnung
2972     {   // scope for bulk broadcast
2973         ScBulkBroadcast aBulkBroadcast( GetBASM());
2974         for (SCTAB i=0; i<=MAXTAB; i++)
2975             if (pTab[i]) pTab[i]->SetDirty();
2976     }
2977 
2978     //  Charts werden zwar auch ohne AutoCalc im Tracking auf Dirty gesetzt,
2979     //  wenn alle Formeln dirty sind, werden die Charts aber nicht mehr erwischt
2980     //  (#45205#) - darum alle Charts nochmal explizit
2981     if (pChartListenerCollection)
2982         pChartListenerCollection->SetDirty();
2983 
2984     SetAutoCalc( bOldAutoCalc );
2985 }
2986 
2987 
2988 void ScDocument::SetDirty( const ScRange& rRange )
2989 {
2990     sal_Bool bOldAutoCalc = GetAutoCalc();
2991     bAutoCalc = sal_False;      // keine Mehrfachberechnung
2992     {   // scope for bulk broadcast
2993         ScBulkBroadcast aBulkBroadcast( GetBASM());
2994         SCTAB nTab2 = rRange.aEnd.Tab();
2995         for (SCTAB i=rRange.aStart.Tab(); i<=nTab2; i++)
2996             if (pTab[i]) pTab[i]->SetDirty( rRange );
2997     }
2998     SetAutoCalc( bOldAutoCalc );
2999 }
3000 
3001 
3002 void ScDocument::SetTableOpDirty( const ScRange& rRange )
3003 {
3004     sal_Bool bOldAutoCalc = GetAutoCalc();
3005     bAutoCalc = sal_False;      // no multiple recalculation
3006     SCTAB nTab2 = rRange.aEnd.Tab();
3007     for (SCTAB i=rRange.aStart.Tab(); i<=nTab2; i++)
3008         if (pTab[i]) pTab[i]->SetTableOpDirty( rRange );
3009     SetAutoCalc( bOldAutoCalc );
3010 }
3011 
3012 
3013 void ScDocument::InterpretDirtyCells( const ScRangeList& rRanges )
3014 {
3015     sal_uLong nRangeCount = rRanges.Count();
3016     for (sal_uLong nPos=0; nPos<nRangeCount; nPos++)
3017     {
3018         ScCellIterator aIter( this, *rRanges.GetObject(nPos) );
3019         ScBaseCell* pCell = aIter.GetFirst();
3020         while (pCell)
3021         {
3022             if (pCell->GetCellType() == CELLTYPE_FORMULA)
3023             {
3024                 if ( static_cast<ScFormulaCell*>(pCell)->GetDirty() && GetAutoCalc() )
3025                     static_cast<ScFormulaCell*>(pCell)->Interpret();
3026             }
3027             pCell = aIter.GetNext();
3028         }
3029     }
3030 }
3031 
3032 
3033 void ScDocument::AddTableOpFormulaCell( ScFormulaCell* pCell )
3034 {
3035     ScInterpreterTableOpParams* p = aTableOpList.Last();
3036     if ( p && p->bCollectNotifications )
3037     {
3038         if ( p->bRefresh )
3039         {   // refresh pointers only
3040             p->aNotifiedFormulaCells.push_back( pCell );
3041         }
3042         else
3043         {   // init both, address and pointer
3044             p->aNotifiedFormulaCells.push_back( pCell );
3045             p->aNotifiedFormulaPos.push_back( pCell->aPos );
3046         }
3047     }
3048 }
3049 
3050 
3051 void ScDocument::CalcAll()
3052 {
3053     ClearLookupCaches();    // Ensure we don't deliver zombie data.
3054     sal_Bool bOldAutoCalc = GetAutoCalc();
3055     SetAutoCalc( sal_True );
3056     SCTAB i;
3057     for (i=0; i<=MAXTAB; i++)
3058         if (pTab[i]) pTab[i]->SetDirtyVar();
3059     for (i=0; i<=MAXTAB; i++)
3060         if (pTab[i]) pTab[i]->CalcAll();
3061     ClearFormulaTree();
3062     SetAutoCalc( bOldAutoCalc );
3063 }
3064 
3065 
3066 void ScDocument::CompileAll()
3067 {
3068     if ( pCondFormList )
3069         pCondFormList->CompileAll();
3070 
3071     for (SCTAB i=0; i<=MAXTAB; i++)
3072         if (pTab[i]) pTab[i]->CompileAll();
3073     SetDirty();
3074 }
3075 
3076 
3077 void ScDocument::CompileXML()
3078 {
3079     sal_Bool bOldAutoCalc = GetAutoCalc();
3080     SetAutoCalc( sal_False );
3081     ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(
3082                 STR_PROGRESS_CALCULATING ), GetXMLImportedFormulaCount() );
3083 
3084     // #b6355215# set AutoNameCache to speed up automatic name lookup
3085     DBG_ASSERT( !pAutoNameCache, "AutoNameCache already set" );
3086     pAutoNameCache = new ScAutoNameCache( this );
3087 
3088     for (SCTAB i=0; i<=MAXTAB; i++)
3089         if (pTab[i]) pTab[i]->CompileXML( aProgress );
3090 
3091     DELETEZ( pAutoNameCache );  // valid only during CompileXML, where cell contents don't change
3092 
3093     if ( pCondFormList )
3094         pCondFormList->CompileXML();
3095     if ( pValidationList )
3096         pValidationList->CompileXML();
3097 
3098     SetDirty();
3099     SetAutoCalc( bOldAutoCalc );
3100 }
3101 
3102 
3103 void ScDocument::CalcAfterLoad()
3104 {
3105     SCTAB i;
3106 
3107     if (bIsClip)    // Excel-Dateien werden aus dem Clipboard in ein Clip-Doc geladen
3108         return;     // dann wird erst beim Einfuegen in das richtige Doc berechnet
3109 
3110     bCalcingAfterLoad = sal_True;
3111     for ( i = 0; i <= MAXTAB; i++)
3112         if (pTab[i]) pTab[i]->CalcAfterLoad();
3113     for (i=0; i<=MAXTAB; i++)
3114         if (pTab[i]) pTab[i]->SetDirtyAfterLoad();
3115     bCalcingAfterLoad = sal_False;
3116 
3117     SetDetectiveDirty(sal_False);   // noch keine wirklichen Aenderungen
3118 
3119     // #i112436# If formula cells are already dirty, they don't broadcast further changes.
3120     // So the source ranges of charts must be interpreted even if they are not visible,
3121     // similar to ScMyShapeResizer::CreateChartListener for loading own files (i104899).
3122     if (pChartListenerCollection)
3123     {
3124         sal_uInt16 nChartCount = pChartListenerCollection->GetCount();
3125         for ( sal_uInt16 nIndex = 0; nIndex < nChartCount; nIndex++ )
3126         {
3127             ScChartListener* pChartListener = static_cast<ScChartListener*>(pChartListenerCollection->At(nIndex));
3128             InterpretDirtyCells(*pChartListener->GetRangeList());
3129         }
3130     }
3131 }
3132 
3133 
3134 sal_uInt16 ScDocument::GetErrCode( const ScAddress& rPos ) const
3135 {
3136     SCTAB nTab = rPos.Tab();
3137     if ( pTab[nTab] )
3138         return pTab[nTab]->GetErrCode( rPos );
3139     return 0;
3140 }
3141 
3142 
3143 void ScDocument::ResetChanged( const ScRange& rRange )
3144 {
3145     SCTAB nStartTab = rRange.aStart.Tab();
3146     SCTAB nEndTab = rRange.aEnd.Tab();
3147     for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
3148         if (pTab[nTab])
3149             pTab[nTab]->ResetChanged( rRange );
3150 }
3151 
3152 //
3153 //  Spaltenbreiten / Zeilenhoehen   --------------------------------------
3154 //
3155 
3156 
3157 void ScDocument::SetColWidth( SCCOL nCol, SCTAB nTab, sal_uInt16 nNewWidth )
3158 {
3159     if ( ValidTab(nTab) && pTab[nTab] )
3160         pTab[nTab]->SetColWidth( nCol, nNewWidth );
3161 }
3162 
3163 
3164 void ScDocument::SetRowHeight( SCROW nRow, SCTAB nTab, sal_uInt16 nNewHeight )
3165 {
3166     if ( ValidTab(nTab) && pTab[nTab] )
3167         pTab[nTab]->SetRowHeight( nRow, nNewHeight );
3168 }
3169 
3170 
3171 void ScDocument::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
3172 {
3173     if ( ValidTab(nTab) && pTab[nTab] )
3174         pTab[nTab]->SetRowHeightRange
3175             ( nStartRow, nEndRow, nNewHeight, 1.0, 1.0 );
3176 }
3177 
3178 void ScDocument::SetRowHeightOnly( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
3179 {
3180     if ( ValidTab(nTab) && pTab[nTab] )
3181         pTab[nTab]->SetRowHeightOnly( nStartRow, nEndRow, nNewHeight );
3182 }
3183 
3184 void ScDocument::SetManualHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_Bool bManual )
3185 {
3186     if ( ValidTab(nTab) && pTab[nTab] )
3187         pTab[nTab]->SetManualHeight( nStartRow, nEndRow, bManual );
3188 }
3189 
3190 
3191 sal_uInt16 ScDocument::GetColWidth( SCCOL nCol, SCTAB nTab ) const
3192 {
3193     if ( ValidTab(nTab) && pTab[nTab] )
3194         return pTab[nTab]->GetColWidth( nCol );
3195     DBG_ERROR("Falsche Tabellennummer");
3196     return 0;
3197 }
3198 
3199 
3200 sal_uInt16 ScDocument::GetOriginalWidth( SCCOL nCol, SCTAB nTab ) const
3201 {
3202     if ( ValidTab(nTab) && pTab[nTab] )
3203         return pTab[nTab]->GetOriginalWidth( nCol );
3204     DBG_ERROR("Falsche Tabellennummer");
3205     return 0;
3206 }
3207 
3208 
3209 sal_uInt16 ScDocument::GetCommonWidth( SCCOL nEndCol, SCTAB nTab ) const
3210 {
3211     if ( ValidTab(nTab) && pTab[nTab] )
3212         return pTab[nTab]->GetCommonWidth( nEndCol );
3213     DBG_ERROR("Wrong table number");
3214     return 0;
3215 }
3216 
3217 
3218 sal_uInt16 ScDocument::GetOriginalHeight( SCROW nRow, SCTAB nTab ) const
3219 {
3220     if ( ValidTab(nTab) && pTab[nTab] )
3221         return pTab[nTab]->GetOriginalHeight( nRow );
3222     DBG_ERROR("Wrong table number");
3223     return 0;
3224 }
3225 
3226 
3227 sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, bool bHiddenAsZero ) const
3228 {
3229     if ( ValidTab(nTab) && pTab[nTab] )
3230         return pTab[nTab]->GetRowHeight( nRow, NULL, NULL, bHiddenAsZero );
3231     DBG_ERROR("Wrong sheet number");
3232     return 0;
3233 }
3234 
3235 
3236 sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, SCROW* pStartRow, SCROW* pEndRow, bool bHiddenAsZero ) const
3237 {
3238     if ( ValidTab(nTab) && pTab[nTab] )
3239         return pTab[nTab]->GetRowHeight( nRow, pStartRow, pEndRow, bHiddenAsZero );
3240     DBG_ERROR("Wrong sheet number");
3241     return 0;
3242 }
3243 
3244 
3245 sal_uLong ScDocument::GetRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
3246 {
3247     if (nStartRow == nEndRow)
3248         return GetRowHeight( nStartRow, nTab);  // faster for a single row
3249 
3250     // check bounds because this method replaces former for(i=start;i<=end;++i) loops
3251     if (nStartRow > nEndRow)
3252         return 0;
3253 
3254     if ( ValidTab(nTab) && pTab[nTab] )
3255         return pTab[nTab]->GetRowHeight( nStartRow, nEndRow);
3256 
3257     DBG_ERROR("wrong sheet number");
3258     return 0;
3259 }
3260 
3261 SCROW ScDocument::GetRowForHeight( SCTAB nTab, sal_uLong nHeight ) const
3262 {
3263     return pTab[nTab]->GetRowForHeight(nHeight);
3264 }
3265 
3266 sal_uLong ScDocument::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow,
3267         SCTAB nTab, double fScale ) const
3268 {
3269     // faster for a single row
3270     if (nStartRow == nEndRow)
3271         return (sal_uLong) (GetRowHeight( nStartRow, nTab) * fScale);
3272 
3273     // check bounds because this method replaces former for(i=start;i<=end;++i) loops
3274     if (nStartRow > nEndRow)
3275         return 0;
3276 
3277     if ( ValidTab(nTab) && pTab[nTab] )
3278         return pTab[nTab]->GetScaledRowHeight( nStartRow, nEndRow, fScale);
3279 
3280     DBG_ERROR("wrong sheet number");
3281     return 0;
3282 }
3283 
3284 SCROW ScDocument::GetHiddenRowCount( SCROW nRow, SCTAB nTab ) const
3285 {
3286     if ( ValidTab(nTab) && pTab[nTab] )
3287         return pTab[nTab]->GetHiddenRowCount( nRow );
3288     DBG_ERROR("Falsche Tabellennummer");
3289     return 0;
3290 }
3291 
3292 
3293 sal_uLong ScDocument::GetColOffset( SCCOL nCol, SCTAB nTab ) const
3294 {
3295     if ( ValidTab(nTab) && pTab[nTab] )
3296         return pTab[nTab]->GetColOffset( nCol );
3297     DBG_ERROR("Falsche Tabellennummer");
3298     return 0;
3299 }
3300 
3301 
3302 sal_uLong ScDocument::GetRowOffset( SCROW nRow, SCTAB nTab ) const
3303 {
3304     if ( ValidTab(nTab) && pTab[nTab] )
3305         return pTab[nTab]->GetRowOffset( nRow );
3306     DBG_ERROR("Falsche Tabellennummer");
3307     return 0;
3308 }
3309 
3310 
3311 sal_uInt16 ScDocument::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, OutputDevice* pDev,
3312                                         double nPPTX, double nPPTY,
3313                                         const Fraction& rZoomX, const Fraction& rZoomY,
3314                                         sal_Bool bFormula, const ScMarkData* pMarkData,
3315                                         sal_Bool bSimpleTextImport )
3316 {
3317     if ( ValidTab(nTab) && pTab[nTab] )
3318         return pTab[nTab]->GetOptimalColWidth( nCol, pDev, nPPTX, nPPTY,
3319             rZoomX, rZoomY, bFormula, pMarkData, bSimpleTextImport );
3320     DBG_ERROR("Falsche Tabellennummer");
3321     return 0;
3322 }
3323 
3324 
3325 long ScDocument::GetNeededSize( SCCOL nCol, SCROW nRow, SCTAB nTab,
3326                                     OutputDevice* pDev,
3327                                     double nPPTX, double nPPTY,
3328                                     const Fraction& rZoomX, const Fraction& rZoomY,
3329                                     sal_Bool bWidth, sal_Bool bTotalSize )
3330 {
3331     if ( ValidTab(nTab) && pTab[nTab] )
3332         return pTab[nTab]->GetNeededSize
3333                 ( nCol, nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, bTotalSize );
3334     DBG_ERROR("Falsche Tabellennummer");
3335     return 0;
3336 }
3337 
3338 
3339 sal_Bool ScDocument::SetOptimalHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nExtra,
3340                                     OutputDevice* pDev,
3341                                     double nPPTX, double nPPTY,
3342                                     const Fraction& rZoomX, const Fraction& rZoomY,
3343                                     sal_Bool bShrink )
3344 {
3345 //! MarkToMulti();
3346     if ( ValidTab(nTab) && pTab[nTab] )
3347         return pTab[nTab]->SetOptimalHeight( nStartRow, nEndRow, nExtra,
3348                                                 pDev, nPPTX, nPPTY, rZoomX, rZoomY, bShrink );
3349     DBG_ERROR("Falsche Tabellennummer");
3350     return sal_False;
3351 }
3352 
3353 
3354 void ScDocument::UpdateAllRowHeights( OutputDevice* pDev, double nPPTX, double nPPTY,
3355                                     const Fraction& rZoomX, const Fraction& rZoomY, const ScMarkData* pTabMark )
3356 {
3357     // one progress across all (selected) sheets
3358 
3359     sal_uLong nCellCount = 0;
3360     for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
3361         if ( pTab[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
3362             nCellCount += pTab[nTab]->GetWeightedCount();
3363 
3364     ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), nCellCount );
3365 
3366     sal_uLong nProgressStart = 0;
3367     for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
3368         if ( pTab[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
3369         {
3370             pTab[nTab]->SetOptimalHeight( 0, MAXROW, 0,
3371                         pDev, nPPTX, nPPTY, rZoomX, rZoomY, sal_False, &aProgress, nProgressStart );
3372             nProgressStart += pTab[nTab]->GetWeightedCount();
3373         }
3374 }
3375 
3376 
3377 //
3378 //  Spalten-/Zeilen-Flags   ----------------------------------------------
3379 //
3380 
3381 void ScDocument::ShowCol(SCCOL nCol, SCTAB nTab, sal_Bool bShow)
3382 {
3383     if ( ValidTab(nTab) && pTab[nTab] )
3384         pTab[nTab]->ShowCol( nCol, bShow );
3385 }
3386 
3387 
3388 void ScDocument::ShowRow(SCROW nRow, SCTAB nTab, sal_Bool bShow)
3389 {
3390     if ( ValidTab(nTab) && pTab[nTab] )
3391         pTab[nTab]->ShowRow( nRow, bShow );
3392 }
3393 
3394 
3395 void ScDocument::ShowRows(SCROW nRow1, SCROW nRow2, SCTAB nTab, sal_Bool bShow)
3396 {
3397     if ( ValidTab(nTab) && pTab[nTab] )
3398         pTab[nTab]->ShowRows( nRow1, nRow2, bShow );
3399 }
3400 
3401 
3402 void ScDocument::SetColFlags( SCCOL nCol, SCTAB nTab, sal_uInt8 nNewFlags )
3403 {
3404     if ( ValidTab(nTab) && pTab[nTab] )
3405         pTab[nTab]->SetColFlags( nCol, nNewFlags );
3406 }
3407 
3408 
3409 void ScDocument::SetRowFlags( SCROW nRow, SCTAB nTab, sal_uInt8 nNewFlags )
3410 {
3411     if ( ValidTab(nTab) && pTab[nTab] )
3412         pTab[nTab]->SetRowFlags( nRow, nNewFlags );
3413 }
3414 
3415 
3416 void ScDocument::SetRowFlags( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt8 nNewFlags )
3417 {
3418     if ( ValidTab(nTab) && pTab[nTab] )
3419         pTab[nTab]->SetRowFlags( nStartRow, nEndRow, nNewFlags );
3420 }
3421 
3422 
3423 sal_uInt8 ScDocument::GetColFlags( SCCOL nCol, SCTAB nTab ) const
3424 {
3425     if ( ValidTab(nTab) && pTab[nTab] )
3426         return pTab[nTab]->GetColFlags( nCol );
3427     DBG_ERROR("Falsche Tabellennummer");
3428     return 0;
3429 }
3430 
3431 sal_uInt8 ScDocument::GetRowFlags( SCROW nRow, SCTAB nTab ) const
3432 {
3433     if ( ValidTab(nTab) && pTab[nTab] )
3434         return pTab[nTab]->GetRowFlags( nRow );
3435     DBG_ERROR("Falsche Tabellennummer");
3436     return 0;
3437 }
3438 
3439 ScBitMaskCompressedArray< SCROW, sal_uInt8> & ScDocument::GetRowFlagsArrayModifiable(
3440         SCTAB nTab )
3441 {
3442     return const_cast< ScBitMaskCompressedArray< SCROW, sal_uInt8> & >(
3443             GetRowFlagsArray( nTab));
3444 }
3445 
3446 const ScBitMaskCompressedArray< SCROW, sal_uInt8> & ScDocument::GetRowFlagsArray(
3447         SCTAB nTab ) const
3448 {
3449     const ScBitMaskCompressedArray< SCROW, sal_uInt8> * pFlags;
3450     if ( ValidTab(nTab) && pTab[nTab] )
3451         pFlags = pTab[nTab]->GetRowFlagsArray();
3452     else
3453     {
3454         DBG_ERROR("wrong sheet number");
3455         pFlags = 0;
3456     }
3457     if (!pFlags)
3458     {
3459         DBG_ERROR("no row flags at sheet");
3460         static ScBitMaskCompressedArray< SCROW, sal_uInt8> aDummy( MAXROW, 0);
3461         pFlags = &aDummy;
3462     }
3463     return *pFlags;
3464 }
3465 
3466 void ScDocument::GetAllRowBreaks(set<SCROW>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
3467 {
3468     if (!ValidTab(nTab) || !pTab[nTab])
3469         return;
3470 
3471     pTab[nTab]->GetAllRowBreaks(rBreaks, bPage, bManual);
3472 }
3473 
3474 void ScDocument::GetAllColBreaks(set<SCCOL>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
3475 {
3476     if (!ValidTab(nTab) || !pTab[nTab])
3477         return;
3478 
3479     pTab[nTab]->GetAllColBreaks(rBreaks, bPage, bManual);
3480 }
3481 
3482 ScBreakType ScDocument::HasRowBreak(SCROW nRow, SCTAB nTab) const
3483 {
3484     ScBreakType nType = BREAK_NONE;
3485     if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
3486         return nType;
3487 
3488     if (pTab[nTab]->HasRowPageBreak(nRow))
3489         nType |= BREAK_PAGE;
3490 
3491     if (pTab[nTab]->HasRowManualBreak(nRow))
3492         nType |= BREAK_MANUAL;
3493 
3494     return nType;
3495 }
3496 
3497 ScBreakType ScDocument::HasColBreak(SCCOL nCol, SCTAB nTab) const
3498 {
3499     ScBreakType nType = BREAK_NONE;
3500     if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
3501         return nType;
3502 
3503     if (pTab[nTab]->HasColPageBreak(nCol))
3504         nType |= BREAK_PAGE;
3505 
3506     if (pTab[nTab]->HasColManualBreak(nCol))
3507         nType |= BREAK_MANUAL;
3508 
3509     return nType;
3510 }
3511 
3512 void ScDocument::SetRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
3513 {
3514     if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
3515         return;
3516 
3517     pTab[nTab]->SetRowBreak(nRow, bPage, bManual);
3518 }
3519 
3520 void ScDocument::SetColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
3521 {
3522     if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
3523         return;
3524 
3525     pTab[nTab]->SetColBreak(nCol, bPage, bManual);
3526 }
3527 
3528 void ScDocument::RemoveRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
3529 {
3530     if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
3531         return;
3532 
3533     pTab[nTab]->RemoveRowBreak(nRow, bPage, bManual);
3534 }
3535 
3536 void ScDocument::RemoveColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
3537 {
3538     if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
3539         return;
3540 
3541     pTab[nTab]->RemoveColBreak(nCol, bPage, bManual);
3542 }
3543 
3544 Sequence<TablePageBreakData> ScDocument::GetRowBreakData(SCTAB nTab) const
3545 {
3546     if (!ValidTab(nTab) || !pTab[nTab])
3547         return Sequence<TablePageBreakData>();
3548 
3549     return pTab[nTab]->GetRowBreakData();
3550 }
3551 
3552 bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow)
3553 {
3554     if (!ValidTab(nTab) || !pTab[nTab])
3555         return false;
3556 
3557     return pTab[nTab]->RowHidden(nRow, pFirstRow, pLastRow);
3558 }
3559 
3560 bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW& rLastRow)
3561 {
3562     if (!ValidTab(nTab) || !pTab[nTab])
3563     {
3564         rLastRow = nRow;
3565         return false;
3566     }
3567 
3568     return pTab[nTab]->RowHidden(nRow, rLastRow);
3569 }
3570 
3571 
3572 bool ScDocument::HasHiddenRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3573 {
3574     if (!ValidTab(nTab) || !pTab[nTab])
3575         return false;
3576 
3577     return pTab[nTab]->HasHiddenRows(nStartRow, nEndRow);
3578 }
3579 
3580 bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL& rLastCol)
3581 {
3582     if (!ValidTab(nTab) || !pTab[nTab])
3583     {
3584         rLastCol = nCol;
3585         return false;
3586     }
3587 
3588     return pTab[nTab]->ColHidden(nCol, rLastCol);
3589 }
3590 
3591 bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol)
3592 {
3593     if (!ValidTab(nTab) || !pTab[nTab])
3594     {
3595         if (pFirstCol)
3596             *pFirstCol = nCol;
3597         if (pLastCol)
3598             *pLastCol = nCol;
3599         return false;
3600     }
3601 
3602     return pTab[nTab]->ColHidden(nCol, pFirstCol, pLastCol);
3603 }
3604 
3605 void ScDocument::SetRowHidden(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHidden)
3606 {
3607     if (!ValidTab(nTab) || !pTab[nTab])
3608         return;
3609 
3610     pTab[nTab]->SetRowHidden(nStartRow, nEndRow, bHidden);
3611 }
3612 
3613 void ScDocument::SetColHidden(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bHidden)
3614 {
3615     if (!ValidTab(nTab) || !pTab[nTab])
3616         return;
3617 
3618     pTab[nTab]->SetColHidden(nStartCol, nEndCol, bHidden);
3619 }
3620 
3621 SCROW ScDocument::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3622 {
3623     if (!ValidTab(nTab) || !pTab[nTab])
3624         return ::std::numeric_limits<SCROW>::max();;
3625 
3626     return pTab[nTab]->FirstVisibleRow(nStartRow, nEndRow);
3627 }
3628 
3629 SCROW ScDocument::LastVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3630 {
3631     if (!ValidTab(nTab) || !pTab[nTab])
3632         return ::std::numeric_limits<SCROW>::max();;
3633 
3634     return pTab[nTab]->LastVisibleRow(nStartRow, nEndRow);
3635 }
3636 
3637 SCROW ScDocument::CountVisibleRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3638 {
3639     if (!ValidTab(nTab) || !pTab[nTab])
3640         return 0;
3641 
3642     return pTab[nTab]->CountVisibleRows(nStartRow, nEndRow);
3643 }
3644 
3645 bool ScDocument::RowFiltered(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow)
3646 {
3647     if (!ValidTab(nTab) || !pTab[nTab])
3648         return false;
3649 
3650     return pTab[nTab]->RowFiltered(nRow, pFirstRow, pLastRow);
3651 }
3652 
3653 bool ScDocument::HasFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3654 {
3655     if (!ValidTab(nTab) || !pTab[nTab])
3656         return false;
3657 
3658     return pTab[nTab]->HasFilteredRows(nStartRow, nEndRow);
3659 }
3660 
3661 bool ScDocument::ColFiltered(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol)
3662 {
3663     if (!ValidTab(nTab) || !pTab[nTab])
3664         return false;
3665 
3666     return pTab[nTab]->ColFiltered(nCol, pFirstCol, pLastCol);
3667 }
3668 
3669 void ScDocument::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bFiltered)
3670 {
3671     if (!ValidTab(nTab) || !pTab[nTab])
3672         return;
3673 
3674     pTab[nTab]->SetRowFiltered(nStartRow, nEndRow, bFiltered);
3675 }
3676 
3677 void ScDocument::SetColFiltered(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bFiltered)
3678 {
3679     if (!ValidTab(nTab) || !pTab[nTab])
3680         return;
3681 
3682     pTab[nTab]->SetColFiltered(nStartCol, nEndCol, bFiltered);
3683 }
3684 
3685 SCROW ScDocument::FirstNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3686 {
3687     if (!ValidTab(nTab) || !pTab[nTab])
3688         return ::std::numeric_limits<SCROW>::max();;
3689 
3690     return pTab[nTab]->FirstNonFilteredRow(nStartRow, nEndRow);
3691 }
3692 
3693 SCROW ScDocument::LastNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3694 {
3695     if (!ValidTab(nTab) || !pTab[nTab])
3696         return ::std::numeric_limits<SCROW>::max();;
3697 
3698     return pTab[nTab]->LastNonFilteredRow(nStartRow, nEndRow);
3699 }
3700 
3701 SCROW ScDocument::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3702 {
3703     if (!ValidTab(nTab) || !pTab[nTab])
3704         return 0;
3705 
3706     return pTab[nTab]->CountNonFilteredRows(nStartRow, nEndRow);
3707 }
3708 
3709 void ScDocument::SyncColRowFlags()
3710 {
3711     for (SCTAB i = 0; i <= nMaxTableNumber; ++i)
3712     {
3713         if (!ValidTab(i) || !pTab[i])
3714             continue;
3715 
3716         pTab[i]->SyncColRowFlags();
3717     }
3718 }
3719 
3720 SCROW ScDocument::GetLastFlaggedRow( SCTAB nTab ) const
3721 {
3722     if ( ValidTab(nTab) && pTab[nTab] )
3723         return pTab[nTab]->GetLastFlaggedRow();
3724     return 0;
3725 }
3726 
3727 
3728 SCCOL ScDocument::GetLastChangedCol( SCTAB nTab ) const
3729 {
3730     if ( ValidTab(nTab) && pTab[nTab] )
3731         return pTab[nTab]->GetLastChangedCol();
3732     return 0;
3733 }
3734 
3735 SCROW ScDocument::GetLastChangedRow( SCTAB nTab ) const
3736 {
3737     if ( ValidTab(nTab) && pTab[nTab] )
3738         return pTab[nTab]->GetLastChangedRow();
3739     return 0;
3740 }
3741 
3742 
3743 SCCOL ScDocument::GetNextDifferentChangedCol( SCTAB nTab, SCCOL nStart) const
3744 {
3745     if ( ValidTab(nTab) && pTab[nTab] )
3746     {
3747         sal_uInt8 nStartFlags = pTab[nTab]->GetColFlags(nStart);
3748         sal_uInt16 nStartWidth = pTab[nTab]->GetOriginalWidth(nStart);
3749         for (SCCOL nCol = nStart + 1; nCol <= MAXCOL; nCol++)
3750         {
3751             if (((nStartFlags & CR_MANUALBREAK) != (pTab[nTab]->GetColFlags(nCol) & CR_MANUALBREAK)) ||
3752                 (nStartWidth != pTab[nTab]->GetOriginalWidth(nCol)) ||
3753                 ((nStartFlags & CR_HIDDEN) != (pTab[nTab]->GetColFlags(nCol) & CR_HIDDEN)) )
3754                 return nCol;
3755         }
3756         return MAXCOL+1;
3757     }
3758     return 0;
3759 }
3760 
3761 SCROW ScDocument::GetNextDifferentChangedRow( SCTAB nTab, SCROW nStart, bool bCareManualSize) const
3762 {
3763     const ScBitMaskCompressedArray< SCROW, sal_uInt8> * pRowFlagsArray;
3764     if ( ValidTab(nTab) && pTab[nTab] && ((pRowFlagsArray = pTab[nTab]->GetRowFlagsArray()) != NULL) &&
3765             pTab[nTab]->mpRowHeights && pTab[nTab]->mpHiddenRows )
3766     {
3767         size_t nIndex;          // ignored
3768         SCROW nFlagsEndRow;
3769         SCROW nHiddenEndRow;
3770         SCROW nHeightEndRow;
3771         sal_uInt8 nFlags;
3772         bool bHidden;
3773         sal_uInt16 nHeight;
3774         sal_uInt8 nStartFlags = nFlags = pRowFlagsArray->GetValue( nStart, nIndex, nFlagsEndRow);
3775         bool bStartHidden = bHidden = pTab[nTab]->RowHidden( nStart, NULL, &nHiddenEndRow);
3776         sal_uInt16 nStartHeight = nHeight = pTab[nTab]->GetRowHeight( nStart, NULL, &nHeightEndRow, false);
3777         SCROW nRow;
3778         while ((nRow = std::min( nHiddenEndRow, std::min( nFlagsEndRow, nHeightEndRow)) + 1) <= MAXROW)
3779         {
3780             if (nFlagsEndRow < nRow)
3781                 nFlags = pRowFlagsArray->GetValue( nRow, nIndex, nFlagsEndRow);
3782             if (nHiddenEndRow < nRow)
3783                 bHidden = pTab[nTab]->RowHidden( nRow, NULL, &nHiddenEndRow);
3784             if (nHeightEndRow < nRow)
3785                 nHeight = pTab[nTab]->GetRowHeight( nRow, NULL, &nHeightEndRow, false);
3786             if (    ((nStartFlags & CR_MANUALBREAK) != (nFlags & CR_MANUALBREAK)) ||
3787                     ((nStartFlags & CR_MANUALSIZE) != (nFlags & CR_MANUALSIZE)) ||
3788                     (bStartHidden != bHidden) ||
3789                     (bCareManualSize && (nStartFlags & CR_MANUALSIZE) && (nStartHeight != nHeight)) ||
3790                     (!bCareManualSize && ((nStartHeight != nHeight))))
3791                 return nRow;
3792         }
3793         return MAXROW+1;
3794     }
3795     return 0;
3796 }
3797 
3798 sal_Bool ScDocument::GetColDefault( SCTAB nTab, SCCOL nCol, SCROW nLastRow, SCROW& nDefault)
3799 {
3800     sal_Bool bRet(sal_False);
3801     nDefault = 0;
3802     ScDocAttrIterator aDocAttrItr(this, nTab, nCol, 0, nCol, nLastRow);
3803     SCCOL nColumn;
3804     SCROW nStartRow;
3805     SCROW nEndRow;
3806     const ScPatternAttr* pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
3807     if (nEndRow < nLastRow)
3808     {
3809         ScDefaultAttrSet aSet;
3810         ScDefaultAttrSet::iterator aItr = aSet.end();
3811         while (pAttr)
3812         {
3813             ScDefaultAttr aAttr(pAttr);
3814             aItr = aSet.find(aAttr);
3815             if (aItr == aSet.end())
3816             {
3817                 aAttr.nCount = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
3818                 aAttr.nFirst = nStartRow;
3819                 aSet.insert(aAttr);
3820             }
3821             else
3822             {
3823                 aAttr.nCount = aItr->nCount + static_cast<SCSIZE>(nEndRow - nStartRow + 1);
3824                 aAttr.nFirst = aItr->nFirst;
3825                 aSet.erase(aItr);
3826                 aSet.insert(aAttr);
3827             }
3828             pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
3829         }
3830         ScDefaultAttrSet::iterator aDefaultItr = aSet.begin();
3831         aItr = aDefaultItr;
3832         aItr++;
3833         while (aItr != aSet.end())
3834         {
3835             // for entries with equal count, use the one with the lowest start row,
3836             // don't use the random order of pointer comparisons
3837             if ( aItr->nCount > aDefaultItr->nCount ||
3838                  ( aItr->nCount == aDefaultItr->nCount && aItr->nFirst < aDefaultItr->nFirst ) )
3839                 aDefaultItr = aItr;
3840             aItr++;
3841         }
3842         nDefault = aDefaultItr->nFirst;
3843         bRet = sal_True;
3844     }
3845     else
3846         bRet = sal_True;
3847     return bRet;
3848 }
3849 
3850 sal_Bool ScDocument::GetRowDefault( SCTAB /* nTab */, SCROW /* nRow */, SCCOL /* nLastCol */, SCCOL& /* nDefault */ )
3851 {
3852     sal_Bool bRet(sal_False);
3853     return bRet;
3854 }
3855 
3856 void ScDocument::StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
3857 {
3858     if ( ValidTab(nTab) && pTab[nTab] )
3859         pTab[nTab]->StripHidden( rX1, rY1, rX2, rY2 );
3860 }
3861 
3862 
3863 void ScDocument::ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
3864 {
3865     if ( ValidTab(nTab) && pTab[nTab] )
3866         pTab[nTab]->ExtendHidden( rX1, rY1, rX2, rY2 );
3867 }
3868 
3869 //
3870 //  Attribute   ----------------------------------------------------------
3871 //
3872 
3873 const SfxPoolItem* ScDocument::GetAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich ) const
3874 {
3875     if ( ValidTab(nTab)  && pTab[nTab] )
3876     {
3877         const SfxPoolItem* pTemp = pTab[nTab]->GetAttr( nCol, nRow, nWhich );
3878         if (pTemp)
3879             return pTemp;
3880         else
3881         {
3882             DBG_ERROR( "Attribut Null" );
3883         }
3884     }
3885     return &xPoolHelper->GetDocPool()->GetDefaultItem( nWhich );
3886 }
3887 
3888 
3889 const ScPatternAttr* ScDocument::GetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3890 {
3891     if ( ValidTab(nTab)  && pTab[nTab] )
3892         return pTab[nTab]->GetPattern( nCol, nRow );
3893     return NULL;
3894 }
3895 
3896 
3897 const ScPatternAttr* ScDocument::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
3898 {
3899     if ( ValidTab(nTab)  && pTab[nTab] )
3900         return pTab[nTab]->GetMostUsedPattern( nCol, nStartRow, nEndRow );
3901     return NULL;
3902 }
3903 
3904 
3905 void ScDocument::ApplyAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem& rAttr )
3906 {
3907     if ( ValidTab(nTab)  && pTab[nTab] )
3908         pTab[nTab]->ApplyAttr( nCol, nRow, rAttr );
3909 }
3910 
3911 
3912 void ScDocument::ApplyPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr )
3913 {
3914     if ( ValidTab(nTab)  && pTab[nTab] )
3915         pTab[nTab]->ApplyPattern( nCol, nRow, rAttr );
3916 }
3917 
3918 
3919 void ScDocument::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow,
3920                         SCCOL nEndCol, SCROW nEndRow,
3921                         const ScMarkData& rMark,
3922                         const ScPatternAttr& rAttr )
3923 {
3924     for (SCTAB i=0; i <= MAXTAB; i++)
3925         if (pTab[i])
3926             if (rMark.GetTableSelect(i))
3927                 pTab[i]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
3928 }
3929 
3930 
3931 void ScDocument::ApplyPatternAreaTab( SCCOL nStartCol, SCROW nStartRow,
3932                         SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScPatternAttr& rAttr )
3933 {
3934     if (VALIDTAB(nTab))
3935         if (pTab[nTab])
3936             pTab[nTab]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
3937 }
3938 
3939 void ScDocument::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
3940         const ScMarkData& rMark, const ScPatternAttr& rPattern, short nNewType )
3941 {
3942     for (SCTAB i=0; i <= MAXTAB; i++)
3943         if (pTab[i])
3944             if (rMark.GetTableSelect(i))
3945                 pTab[i]->ApplyPatternIfNumberformatIncompatible( rRange, rPattern, nNewType );
3946 }
3947 
3948 
3949 void ScDocument::ApplyStyle( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScStyleSheet& rStyle)
3950 {
3951     if (VALIDTAB(nTab))
3952         if (pTab[nTab])
3953             pTab[nTab]->ApplyStyle( nCol, nRow, rStyle );
3954 }
3955 
3956 
3957 void ScDocument::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow,
3958                         SCCOL nEndCol, SCROW nEndRow,
3959                         const ScMarkData& rMark,
3960                         const ScStyleSheet& rStyle)
3961 {
3962     for (SCTAB i=0; i <= MAXTAB; i++)
3963         if (pTab[i])
3964             if (rMark.GetTableSelect(i))
3965                 pTab[i]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
3966 }
3967 
3968 
3969 void ScDocument::ApplyStyleAreaTab( SCCOL nStartCol, SCROW nStartRow,
3970                         SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScStyleSheet& rStyle)
3971 {
3972     if (VALIDTAB(nTab))
3973         if (pTab[nTab])
3974             pTab[nTab]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
3975 }
3976 
3977 
3978 void ScDocument::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
3979 {
3980     // ApplySelectionStyle needs multi mark
3981     if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
3982     {
3983         ScRange aRange;
3984         rMark.GetMarkArea( aRange );
3985         ApplyStyleArea( aRange.aStart.Col(), aRange.aStart.Row(),
3986                           aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rStyle );
3987     }
3988     else
3989     {
3990         for (SCTAB i=0; i<=MAXTAB; i++)
3991             if ( pTab[i] && rMark.GetTableSelect(i) )
3992                     pTab[i]->ApplySelectionStyle( rStyle, rMark );
3993     }
3994 }
3995 
3996 
3997 void ScDocument::ApplySelectionLineStyle( const ScMarkData& rMark,
3998                     const SvxBorderLine* pLine, sal_Bool bColorOnly )
3999 {
4000     if ( bColorOnly && !pLine )
4001         return;
4002 
4003     for (SCTAB i=0; i<=MAXTAB; i++)
4004         if (pTab[i])
4005             if (rMark.GetTableSelect(i))
4006                 pTab[i]->ApplySelectionLineStyle( rMark, pLine, bColorOnly );
4007 }
4008 
4009 
4010 const ScStyleSheet* ScDocument::GetStyle( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4011 {
4012     if ( VALIDTAB(nTab) && pTab[nTab] )
4013         return pTab[nTab]->GetStyle(nCol, nRow);
4014     else
4015         return NULL;
4016 }
4017 
4018 
4019 const ScStyleSheet* ScDocument::GetSelectionStyle( const ScMarkData& rMark ) const
4020 {
4021     sal_Bool    bEqual = sal_True;
4022     sal_Bool    bFound;
4023 
4024     const ScStyleSheet* pStyle = NULL;
4025     const ScStyleSheet* pNewStyle;
4026 
4027     if ( rMark.IsMultiMarked() )
4028         for (SCTAB i=0; i<=MAXTAB && bEqual; i++)
4029             if (pTab[i] && rMark.GetTableSelect(i))
4030             {
4031                 pNewStyle = pTab[i]->GetSelectionStyle( rMark, bFound );
4032                 if (bFound)
4033                 {
4034                     if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
4035                         bEqual = sal_False;                                             // unterschiedliche
4036                     pStyle = pNewStyle;
4037                 }
4038             }
4039     if ( rMark.IsMarked() )
4040     {
4041         ScRange aRange;
4042         rMark.GetMarkArea( aRange );
4043         for (SCTAB i=aRange.aStart.Tab(); i<=aRange.aEnd.Tab() && bEqual; i++)
4044             if (pTab[i] && rMark.GetTableSelect(i))
4045             {
4046                 pNewStyle = pTab[i]->GetAreaStyle( bFound,
4047                                         aRange.aStart.Col(), aRange.aStart.Row(),
4048                                         aRange.aEnd.Col(),   aRange.aEnd.Row()   );
4049                 if (bFound)
4050                 {
4051                     if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
4052                         bEqual = sal_False;                                             // unterschiedliche
4053                     pStyle = pNewStyle;
4054                 }
4055             }
4056     }
4057 
4058     return bEqual ? pStyle : NULL;
4059 }
4060 
4061 
4062 void ScDocument::StyleSheetChanged( const SfxStyleSheetBase* pStyleSheet, sal_Bool bRemoved,
4063                                     OutputDevice* pDev,
4064                                     double nPPTX, double nPPTY,
4065                                     const Fraction& rZoomX, const Fraction& rZoomY )
4066 {
4067     for (SCTAB i=0; i <= MAXTAB; i++)
4068         if (pTab[i])
4069             pTab[i]->StyleSheetChanged
4070                 ( pStyleSheet, bRemoved, pDev, nPPTX, nPPTY, rZoomX, rZoomY );
4071 
4072     if ( pStyleSheet && pStyleSheet->GetName() == ScGlobal::GetRscString(STR_STYLENAME_STANDARD) )
4073     {
4074         //  update attributes for all note objects
4075         ScDetectiveFunc::UpdateAllComments( *this );
4076     }
4077 }
4078 
4079 
4080 sal_Bool ScDocument::IsStyleSheetUsed( const ScStyleSheet& rStyle, sal_Bool bGatherAllStyles ) const
4081 {
4082     if ( bStyleSheetUsageInvalid || rStyle.GetUsage() == ScStyleSheet::UNKNOWN )
4083     {
4084         if ( bGatherAllStyles )
4085         {
4086             SfxStyleSheetIterator aIter( xPoolHelper->GetStylePool(),
4087                     SFX_STYLE_FAMILY_PARA );
4088             for ( const SfxStyleSheetBase* pStyle = aIter.First(); pStyle;
4089                                            pStyle = aIter.Next() )
4090             {
4091                 const ScStyleSheet* pScStyle = PTR_CAST( ScStyleSheet, pStyle );
4092                 if ( pScStyle )
4093                     pScStyle->SetUsage( ScStyleSheet::NOTUSED );
4094             }
4095         }
4096 
4097         sal_Bool bIsUsed = sal_False;
4098 
4099         for ( SCTAB i=0; i<=MAXTAB; i++ )
4100         {
4101             if ( pTab[i] )
4102             {
4103                 if ( pTab[i]->IsStyleSheetUsed( rStyle, bGatherAllStyles ) )
4104                 {
4105                     if ( !bGatherAllStyles )
4106                         return sal_True;
4107                     bIsUsed = sal_True;
4108                 }
4109             }
4110         }
4111 
4112         if ( bGatherAllStyles )
4113             bStyleSheetUsageInvalid = sal_False;
4114 
4115         return bIsUsed;
4116     }
4117 
4118     return rStyle.GetUsage() == ScStyleSheet::USED;
4119 }
4120 
4121 
4122 sal_Bool ScDocument::ApplyFlagsTab( SCCOL nStartCol, SCROW nStartRow,
4123                         SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, sal_Int16 nFlags )
4124 {
4125     if (VALIDTAB(nTab))
4126         if (pTab[nTab])
4127             return pTab[nTab]->ApplyFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
4128 
4129     DBG_ERROR("ApplyFlags: falsche Tabelle");
4130     return sal_False;
4131 }
4132 
4133 
4134 sal_Bool ScDocument::RemoveFlagsTab( SCCOL nStartCol, SCROW nStartRow,
4135                         SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, sal_Int16 nFlags )
4136 {
4137     if (VALIDTAB(nTab))
4138         if (pTab[nTab])
4139             return pTab[nTab]->RemoveFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
4140 
4141     DBG_ERROR("RemoveFlags: falsche Tabelle");
4142     return sal_False;
4143 }
4144 
4145 
4146 void ScDocument::SetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr,
4147                                 sal_Bool bPutToPool )
4148 {
4149     if (VALIDTAB(nTab))
4150         if (pTab[nTab])
4151             pTab[nTab]->SetPattern( nCol, nRow, rAttr, bPutToPool );
4152 }
4153 
4154 
4155 void ScDocument::SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr,
4156                                 sal_Bool bPutToPool )
4157 {
4158     SCTAB nTab = rPos.Tab();
4159     if (pTab[nTab])
4160         pTab[nTab]->SetPattern( rPos, rAttr, bPutToPool );
4161 }
4162 
4163 
4164 ScPatternAttr* ScDocument::CreateSelectionPattern( const ScMarkData& rMark, sal_Bool bDeep )
4165 {
4166     ScMergePatternState aState;
4167 
4168     if ( rMark.IsMultiMarked() )                                // multi selection
4169     {
4170         for (SCTAB i=0; i<=MAXTAB; i++)
4171             if (pTab[i] && rMark.GetTableSelect(i))
4172                 pTab[i]->MergeSelectionPattern( aState, rMark, bDeep );
4173     }
4174     if ( rMark.IsMarked() )                                     // simle selection
4175     {
4176         ScRange aRange;
4177         rMark.GetMarkArea(aRange);
4178         for (SCTAB i=0; i<=MAXTAB; i++)
4179             if (pTab[i] && rMark.GetTableSelect(i))
4180                 pTab[i]->MergePatternArea( aState,
4181                                 aRange.aStart.Col(), aRange.aStart.Row(),
4182                                 aRange.aEnd.Col(), aRange.aEnd.Row(), bDeep );
4183     }
4184 
4185     DBG_ASSERT( aState.pItemSet, "SelectionPattern Null" );
4186     if (aState.pItemSet)
4187         return new ScPatternAttr( aState.pItemSet );
4188     else
4189         return new ScPatternAttr( GetPool() );      // empty
4190 }
4191 
4192 
4193 const ScPatternAttr* ScDocument::GetSelectionPattern( const ScMarkData& rMark, sal_Bool bDeep )
4194 {
4195     delete pSelectionAttr;
4196     pSelectionAttr = CreateSelectionPattern( rMark, bDeep );
4197     return pSelectionAttr;
4198 }
4199 
4200 
4201 void ScDocument::GetSelectionFrame( const ScMarkData& rMark,
4202                                     SvxBoxItem&     rLineOuter,
4203                                     SvxBoxInfoItem& rLineInner )
4204 {
4205     rLineOuter.SetLine(NULL, BOX_LINE_TOP);
4206     rLineOuter.SetLine(NULL, BOX_LINE_BOTTOM);
4207     rLineOuter.SetLine(NULL, BOX_LINE_LEFT);
4208     rLineOuter.SetLine(NULL, BOX_LINE_RIGHT);
4209     rLineOuter.SetDistance(0);
4210 
4211     rLineInner.SetLine(NULL, BOXINFO_LINE_HORI);
4212     rLineInner.SetLine(NULL, BOXINFO_LINE_VERT);
4213     rLineInner.SetTable(sal_True);
4214     rLineInner.SetDist(sal_True);
4215     rLineInner.SetMinDist(sal_False);
4216 
4217     ScLineFlags aFlags;
4218 
4219     if (rMark.IsMarked())
4220     {
4221         ScRange aRange;
4222         rMark.GetMarkArea(aRange);
4223         rLineInner.EnableHor( aRange.aStart.Row() != aRange.aEnd.Row() );
4224         rLineInner.EnableVer( aRange.aStart.Col() != aRange.aEnd.Col() );
4225         for (SCTAB i=0; i<=MAXTAB; i++)
4226             if (pTab[i] && rMark.GetTableSelect(i))
4227                 pTab[i]->MergeBlockFrame( &rLineOuter, &rLineInner, aFlags,
4228                                           aRange.aStart.Col(), aRange.aStart.Row(),
4229                                           aRange.aEnd.Col(),   aRange.aEnd.Row() );
4230     }
4231 
4232         //  Don't care Status auswerten
4233 
4234     rLineInner.SetValid( VALID_LEFT,   ( aFlags.nLeft != SC_LINE_DONTCARE ) );
4235     rLineInner.SetValid( VALID_RIGHT,  ( aFlags.nRight != SC_LINE_DONTCARE ) );
4236     rLineInner.SetValid( VALID_TOP,    ( aFlags.nTop != SC_LINE_DONTCARE ) );
4237     rLineInner.SetValid( VALID_BOTTOM, ( aFlags.nBottom != SC_LINE_DONTCARE ) );
4238     rLineInner.SetValid( VALID_HORI,   ( aFlags.nHori != SC_LINE_DONTCARE ) );
4239     rLineInner.SetValid( VALID_VERT,   ( aFlags.nVert != SC_LINE_DONTCARE ) );
4240 }
4241 
4242 
4243 bool ScDocument::HasAttrib( SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
4244                             SCCOL nCol2, SCROW nRow2, SCTAB nTab2, sal_uInt16 nMask )
4245 {
4246     if ( nMask & HASATTR_ROTATE )
4247     {
4248         //  Attribut im Dokument ueberhaupt verwendet?
4249         //  (wie in fillinfo)
4250 
4251         ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4252 
4253         sal_Bool bAnyItem = sal_False;
4254         sal_uInt32 nRotCount = pPool->GetItemCount2( ATTR_ROTATE_VALUE );
4255         for (sal_uInt32 nItem=0; nItem<nRotCount; nItem++)
4256         {
4257             const SfxPoolItem* pItem = pPool->GetItem2( ATTR_ROTATE_VALUE, nItem );
4258             if ( pItem )
4259             {
4260                 // 90 or 270 degrees is former SvxOrientationItem - only look for other values
4261                 // (see ScPatternAttr::GetCellOrientation)
4262                 sal_Int32 nAngle = static_cast<const SfxInt32Item*>(pItem)->GetValue();
4263                 if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
4264                 {
4265                     bAnyItem = sal_True;
4266                     break;
4267                 }
4268             }
4269         }
4270         if (!bAnyItem)
4271             nMask &= ~HASATTR_ROTATE;
4272     }
4273 
4274     if ( nMask & HASATTR_RTL )
4275     {
4276         //  first check if right-to left is in the pool at all
4277         //  (the same item is used in cell and page format)
4278 
4279         ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4280 
4281         sal_Bool bHasRtl = sal_False;
4282         sal_uInt32 nDirCount = pPool->GetItemCount2( ATTR_WRITINGDIR );
4283         for (sal_uInt32 nItem=0; nItem<nDirCount; nItem++)
4284         {
4285             const SfxPoolItem* pItem = pPool->GetItem2( ATTR_WRITINGDIR, nItem );
4286             if ( pItem && ((const SvxFrameDirectionItem*)pItem)->GetValue() == FRMDIR_HORI_RIGHT_TOP )
4287             {
4288                 bHasRtl = sal_True;
4289                 break;
4290             }
4291         }
4292         if (!bHasRtl)
4293             nMask &= ~HASATTR_RTL;
4294     }
4295 
4296     if (!nMask)
4297         return false;
4298 
4299     bool bFound = false;
4300     for (SCTAB i=nTab1; i<=nTab2 && !bFound; i++)
4301         if (pTab[i])
4302         {
4303             if ( nMask & HASATTR_RTL )
4304             {
4305                 if ( GetEditTextDirection(i) == EE_HTEXTDIR_R2L )       // sheet default
4306                     bFound = true;
4307             }
4308             if ( nMask & HASATTR_RIGHTORCENTER )
4309             {
4310                 //  On a RTL sheet, don't start to look for the default left value
4311                 //  (which is then logically right), instead always assume sal_True.
4312                 //  That way, ScAttrArray::HasAttrib doesn't have to handle RTL sheets.
4313 
4314                 if ( IsLayoutRTL(i) )
4315                     bFound = true;
4316             }
4317 
4318             if ( !bFound )
4319                 bFound = pTab[i]->HasAttrib( nCol1, nRow1, nCol2, nRow2, nMask );
4320         }
4321 
4322     return bFound;
4323 }
4324 
4325 bool ScDocument::HasAttrib( const ScRange& rRange, sal_uInt16 nMask )
4326 {
4327     return HasAttrib( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
4328                       rRange.aEnd.Col(),   rRange.aEnd.Row(),   rRange.aEnd.Tab(),
4329                       nMask );
4330 }
4331 
4332 void ScDocument::FindMaxRotCol( SCTAB nTab, RowInfo* pRowInfo, SCSIZE nArrCount,
4333                                 SCCOL nX1, SCCOL nX2 ) const
4334 {
4335     if ( ValidTab(nTab)  && pTab[nTab] )
4336         pTab[nTab]->FindMaxRotCol( pRowInfo, nArrCount, nX1, nX2 );
4337     else
4338     {
4339         DBG_ERRORFILE("FindMaxRotCol: falsche Tabelle");
4340     }
4341 }
4342 
4343 void ScDocument::GetBorderLines( SCCOL nCol, SCROW nRow, SCTAB nTab,
4344                         const SvxBorderLine** ppLeft, const SvxBorderLine** ppTop,
4345                         const SvxBorderLine** ppRight, const SvxBorderLine** ppBottom ) const
4346 {
4347     //! Seitengrenzen fuer Druck beruecksichtigen !!!!!
4348 
4349     const SvxBoxItem* pThisAttr = (const SvxBoxItem*) GetEffItem( nCol, nRow, nTab, ATTR_BORDER );
4350     DBG_ASSERT(pThisAttr,"wo ist das Attribut?");
4351 
4352     const SvxBorderLine* pLeftLine   = pThisAttr->GetLeft();
4353     const SvxBorderLine* pTopLine    = pThisAttr->GetTop();
4354     const SvxBorderLine* pRightLine  = pThisAttr->GetRight();
4355     const SvxBorderLine* pBottomLine = pThisAttr->GetBottom();
4356 
4357     if ( nCol > 0 )
4358     {
4359         const SvxBorderLine* pOther = ((const SvxBoxItem*)
4360                                 GetEffItem( nCol-1, nRow, nTab, ATTR_BORDER ))->GetRight();
4361         if ( ScHasPriority( pOther, pLeftLine ) )
4362             pLeftLine = pOther;
4363     }
4364     if ( nRow > 0 )
4365     {
4366         const SvxBorderLine* pOther = ((const SvxBoxItem*)
4367                                 GetEffItem( nCol, nRow-1, nTab, ATTR_BORDER ))->GetBottom();
4368         if ( ScHasPriority( pOther, pTopLine ) )
4369             pTopLine = pOther;
4370     }
4371     if ( nCol < MAXCOL )
4372     {
4373         const SvxBorderLine* pOther = ((const SvxBoxItem*)
4374                                 GetEffItem( nCol+1, nRow, nTab, ATTR_BORDER ))->GetLeft();
4375         if ( ScHasPriority( pOther, pRightLine ) )
4376             pRightLine = pOther;
4377     }
4378     if ( nRow < MAXROW )
4379     {
4380         const SvxBorderLine* pOther = ((const SvxBoxItem*)
4381                                 GetEffItem( nCol, nRow+1, nTab, ATTR_BORDER ))->GetTop();
4382         if ( ScHasPriority( pOther, pBottomLine ) )
4383             pBottomLine = pOther;
4384     }
4385 
4386     if (ppLeft)
4387         *ppLeft = pLeftLine;
4388     if (ppTop)
4389         *ppTop = pTopLine;
4390     if (ppRight)
4391         *ppRight = pRightLine;
4392     if (ppBottom)
4393         *ppBottom = pBottomLine;
4394 }
4395 
4396 sal_Bool ScDocument::IsBlockEmpty( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
4397                                         SCCOL nEndCol, SCROW nEndRow, bool bIgnoreNotes ) const
4398 {
4399     if (VALIDTAB(nTab))
4400         if (pTab[nTab])
4401             return pTab[nTab]->IsBlockEmpty( nStartCol, nStartRow, nEndCol, nEndRow, bIgnoreNotes );
4402 
4403     DBG_ERROR("Falsche Tabellennummer");
4404     return sal_False;
4405 }
4406 
4407 
4408 void ScDocument::LockTable(SCTAB nTab)
4409 {
4410     if ( ValidTab(nTab)  && pTab[nTab] )
4411         pTab[nTab]->LockTable();
4412     else
4413     {
4414         DBG_ERROR("Falsche Tabellennummer");
4415     }
4416 }
4417 
4418 
4419 void ScDocument::UnlockTable(SCTAB nTab)
4420 {
4421     if ( ValidTab(nTab)  && pTab[nTab] )
4422         pTab[nTab]->UnlockTable();
4423     else
4424     {
4425         DBG_ERROR("Falsche Tabellennummer");
4426     }
4427 }
4428 
4429 
4430 sal_Bool ScDocument::IsBlockEditable( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
4431                                         SCCOL nEndCol, SCROW nEndRow,
4432                                         sal_Bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
4433 {
4434     // import into read-only document is possible
4435     if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
4436     {
4437         if ( pOnlyNotBecauseOfMatrix )
4438             *pOnlyNotBecauseOfMatrix = sal_False;
4439         return sal_False;
4440     }
4441 
4442     if (VALIDTAB(nTab))
4443         if (pTab[nTab])
4444             return pTab[nTab]->IsBlockEditable( nStartCol, nStartRow, nEndCol,
4445                 nEndRow, pOnlyNotBecauseOfMatrix );
4446 
4447     DBG_ERROR("Falsche Tabellennummer");
4448     if ( pOnlyNotBecauseOfMatrix )
4449         *pOnlyNotBecauseOfMatrix = sal_False;
4450     return sal_False;
4451 }
4452 
4453 
4454 sal_Bool ScDocument::IsSelectionEditable( const ScMarkData& rMark,
4455             sal_Bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
4456 {
4457     // import into read-only document is possible
4458     if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
4459     {
4460         if ( pOnlyNotBecauseOfMatrix )
4461             *pOnlyNotBecauseOfMatrix = sal_False;
4462         return sal_False;
4463     }
4464 
4465     ScRange aRange;
4466     rMark.GetMarkArea(aRange);
4467 
4468     sal_Bool bOk = sal_True;
4469     sal_Bool bMatrix = ( pOnlyNotBecauseOfMatrix != NULL );
4470     for ( SCTAB i=0; i<=MAXTAB && (bOk || bMatrix); i++ )
4471     {
4472         if ( pTab[i] && rMark.GetTableSelect(i) )
4473         {
4474             if (rMark.IsMarked())
4475             {
4476                 if ( !pTab[i]->IsBlockEditable( aRange.aStart.Col(),
4477                         aRange.aStart.Row(), aRange.aEnd.Col(),
4478                         aRange.aEnd.Row(), pOnlyNotBecauseOfMatrix ) )
4479                 {
4480                     bOk = sal_False;
4481                     if ( pOnlyNotBecauseOfMatrix )
4482                         bMatrix = *pOnlyNotBecauseOfMatrix;
4483                 }
4484             }
4485             if (rMark.IsMultiMarked())
4486             {
4487                 if ( !pTab[i]->IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix ) )
4488                 {
4489                     bOk = sal_False;
4490                     if ( pOnlyNotBecauseOfMatrix )
4491                         bMatrix = *pOnlyNotBecauseOfMatrix;
4492                 }
4493             }
4494         }
4495     }
4496 
4497     if ( pOnlyNotBecauseOfMatrix )
4498         *pOnlyNotBecauseOfMatrix = ( !bOk && bMatrix );
4499 
4500     return bOk;
4501 }
4502 
4503 
4504 sal_Bool ScDocument::HasSelectedBlockMatrixFragment( SCCOL nStartCol, SCROW nStartRow,
4505                                 SCCOL nEndCol, SCROW nEndRow,
4506                                 const ScMarkData& rMark ) const
4507 {
4508     sal_Bool bOk = sal_True;
4509     for (SCTAB i=0; i<=MAXTAB && bOk; i++)
4510         if (pTab[i])
4511             if (rMark.GetTableSelect(i))
4512                 if (pTab[i]->HasBlockMatrixFragment( nStartCol, nStartRow, nEndCol, nEndRow ))
4513                     bOk = sal_False;
4514 
4515     return !bOk;
4516 }
4517 
4518 
4519 sal_Bool ScDocument::GetMatrixFormulaRange( const ScAddress& rCellPos, ScRange& rMatrix )
4520 {
4521     //  if rCell is part of a matrix formula, return its complete range
4522 
4523     sal_Bool bRet = sal_False;
4524     ScBaseCell* pCell = GetCell( rCellPos );
4525     if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
4526     {
4527         ScAddress aOrigin = rCellPos;
4528         if ( ((ScFormulaCell*)pCell)->GetMatrixOrigin( aOrigin ) )
4529         {
4530             if ( aOrigin != rCellPos )
4531                 pCell = GetCell( aOrigin );
4532             if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
4533             {
4534                 SCCOL nSizeX;
4535                 SCROW nSizeY;
4536                 ((ScFormulaCell*)pCell)->GetMatColsRows(nSizeX,nSizeY);
4537                 if ( !(nSizeX > 0 && nSizeY > 0) )
4538                 {
4539                     // GetMatrixEdge computes also dimensions of the matrix
4540                     // if not already done (may occur if document is loaded
4541                     // from old file format).
4542                     // Needs an "invalid" initialized address.
4543                     aOrigin.SetInvalid();
4544                     ((ScFormulaCell*)pCell)->GetMatrixEdge(aOrigin);
4545                     ((ScFormulaCell*)pCell)->GetMatColsRows(nSizeX,nSizeY);
4546                 }
4547                 if ( nSizeX > 0 && nSizeY > 0 )
4548                 {
4549                     ScAddress aEnd( aOrigin.Col() + nSizeX - 1,
4550                                     aOrigin.Row() + nSizeY - 1,
4551                                     aOrigin.Tab() );
4552 
4553                     rMatrix.aStart = aOrigin;
4554                     rMatrix.aEnd = aEnd;
4555                     bRet = sal_True;
4556                 }
4557             }
4558         }
4559     }
4560     return bRet;
4561 }
4562 
4563 
4564 sal_Bool ScDocument::ExtendOverlapped( SCCOL& rStartCol, SCROW& rStartRow,
4565                                 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
4566 {
4567     sal_Bool bFound = sal_False;
4568     if ( ValidColRow(rStartCol,rStartRow) && ValidColRow(nEndCol,nEndRow) && ValidTab(nTab) )
4569     {
4570         if (pTab[nTab])
4571         {
4572             SCCOL nCol;
4573             SCCOL nOldCol = rStartCol;
4574             SCROW nOldRow = rStartRow;
4575             for (nCol=nOldCol; nCol<=nEndCol; nCol++)
4576                 while (((ScMergeFlagAttr*)GetAttr(nCol,rStartRow,nTab,ATTR_MERGE_FLAG))->
4577                             IsVerOverlapped())
4578                     --rStartRow;
4579 
4580             //!     weiterreichen ?
4581 
4582             ScAttrArray* pAttrArray = pTab[nTab]->aCol[nOldCol].pAttrArray;
4583             SCSIZE nIndex;
4584             pAttrArray->Search( nOldRow, nIndex );
4585             SCROW nAttrPos = nOldRow;
4586             while (nAttrPos<=nEndRow)
4587             {
4588                 DBG_ASSERT( nIndex < pAttrArray->nCount, "Falscher Index im AttrArray" );
4589 
4590                 if (((ScMergeFlagAttr&)pAttrArray->pData[nIndex].pPattern->
4591                         GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped())
4592                 {
4593                     SCROW nLoopEndRow = Min( nEndRow, pAttrArray->pData[nIndex].nRow );
4594                     for (SCROW nAttrRow = nAttrPos; nAttrRow <= nLoopEndRow; nAttrRow++)
4595                     {
4596                         SCCOL nTempCol = nOldCol;
4597                         do
4598                             --nTempCol;
4599                         while (((ScMergeFlagAttr*)GetAttr(nTempCol,nAttrRow,nTab,ATTR_MERGE_FLAG))
4600                                 ->IsHorOverlapped());
4601                         if (nTempCol < rStartCol)
4602                             rStartCol = nTempCol;
4603                     }
4604                 }
4605                 nAttrPos = pAttrArray->pData[nIndex].nRow + 1;
4606                 ++nIndex;
4607             }
4608         }
4609     }
4610     else
4611     {
4612         DBG_ERROR("ExtendOverlapped: falscher Bereich");
4613     }
4614 
4615     return bFound;
4616 }
4617 
4618 
4619 sal_Bool ScDocument::ExtendMergeSel( SCCOL nStartCol, SCROW nStartRow,
4620                               SCCOL& rEndCol, SCROW& rEndRow,
4621                               const ScMarkData& rMark, sal_Bool bRefresh, sal_Bool bAttrs )
4622 {
4623     // use all selected sheets from rMark
4624 
4625     sal_Bool bFound = sal_False;
4626     SCCOL nOldEndCol = rEndCol;
4627     SCROW nOldEndRow = rEndRow;
4628 
4629     for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
4630         if ( pTab[nTab] && rMark.GetTableSelect(nTab) )
4631         {
4632             SCCOL nThisEndCol = nOldEndCol;
4633             SCROW nThisEndRow = nOldEndRow;
4634             if ( ExtendMerge( nStartCol, nStartRow, nThisEndCol, nThisEndRow, nTab, bRefresh, bAttrs ) )
4635                 bFound = sal_True;
4636             if ( nThisEndCol > rEndCol )
4637                 rEndCol = nThisEndCol;
4638             if ( nThisEndRow > rEndRow )
4639                 rEndRow = nThisEndRow;
4640         }
4641 
4642     return bFound;
4643 }
4644 
4645 
4646 sal_Bool ScDocument::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
4647                               SCCOL& rEndCol,  SCROW& rEndRow,
4648                               SCTAB nTab, sal_Bool bRefresh, sal_Bool bAttrs )
4649 {
4650     sal_Bool bFound = sal_False;
4651     if ( ValidColRow(nStartCol,nStartRow) && ValidColRow(rEndCol,rEndRow) && ValidTab(nTab) )
4652     {
4653         if (pTab[nTab])
4654             bFound = pTab[nTab]->ExtendMerge( nStartCol, nStartRow, rEndCol, rEndRow, bRefresh, bAttrs );
4655 
4656         if (bRefresh)
4657             RefreshAutoFilter( nStartCol, nStartRow, rEndCol, rEndRow, nTab );
4658     }
4659     else
4660     {
4661         DBG_ERROR("ExtendMerge: falscher Bereich");
4662     }
4663 
4664     return bFound;
4665 }
4666 
4667 
4668 sal_Bool ScDocument::ExtendMerge( ScRange& rRange, sal_Bool bRefresh, sal_Bool bAttrs )
4669 {
4670     sal_Bool bFound = sal_False;
4671     SCTAB nStartTab = rRange.aStart.Tab();
4672     SCTAB nEndTab   = rRange.aEnd.Tab();
4673     SCCOL nEndCol   = rRange.aEnd.Col();
4674     SCROW nEndRow   = rRange.aEnd.Row();
4675 
4676     PutInOrder( nStartTab, nEndTab );
4677     for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++ )
4678     {
4679         SCCOL nExtendCol = rRange.aEnd.Col();
4680         SCROW nExtendRow = rRange.aEnd.Row();
4681         if (ExtendMerge( rRange.aStart.Col(), rRange.aStart.Row(),
4682                          nExtendCol,          nExtendRow,
4683                          nTab, bRefresh, bAttrs ) )
4684         {
4685             bFound = sal_True;
4686             if (nExtendCol > nEndCol) nEndCol = nExtendCol;
4687             if (nExtendRow > nEndRow) nEndRow = nExtendRow;
4688         }
4689     }
4690 
4691     rRange.aEnd.SetCol(nEndCol);
4692     rRange.aEnd.SetRow(nEndRow);
4693 
4694     return bFound;
4695 }
4696 
4697 sal_Bool ScDocument::ExtendTotalMerge( ScRange& rRange )
4698 {
4699     //  Bereich genau dann auf zusammengefasste Zellen erweitern, wenn
4700     //  dadurch keine neuen nicht-ueberdeckten Zellen getroffen werden
4701 
4702     sal_Bool bRet = sal_False;
4703     ScRange aExt = rRange;
4704     if (ExtendMerge(aExt))
4705     {
4706         if ( aExt.aEnd.Row() > rRange.aEnd.Row() )
4707         {
4708             ScRange aTest = aExt;
4709             aTest.aStart.SetRow( rRange.aEnd.Row() + 1 );
4710             if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
4711                 aExt.aEnd.SetRow(rRange.aEnd.Row());
4712         }
4713         if ( aExt.aEnd.Col() > rRange.aEnd.Col() )
4714         {
4715             ScRange aTest = aExt;
4716             aTest.aStart.SetCol( rRange.aEnd.Col() + 1 );
4717             if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
4718                 aExt.aEnd.SetCol(rRange.aEnd.Col());
4719         }
4720 
4721         bRet = ( aExt.aEnd != rRange.aEnd );
4722         rRange = aExt;
4723     }
4724     return bRet;
4725 }
4726 
4727 sal_Bool ScDocument::ExtendOverlapped( ScRange& rRange )
4728 {
4729     sal_Bool bFound = sal_False;
4730     SCTAB nStartTab = rRange.aStart.Tab();
4731     SCTAB nEndTab   = rRange.aEnd.Tab();
4732     SCCOL nStartCol = rRange.aStart.Col();
4733     SCROW nStartRow = rRange.aStart.Row();
4734 
4735     PutInOrder( nStartTab, nEndTab );
4736     for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++ )
4737     {
4738         SCCOL nExtendCol = rRange.aStart.Col();
4739         SCROW nExtendRow = rRange.aStart.Row();
4740         ExtendOverlapped( nExtendCol, nExtendRow,
4741                                 rRange.aEnd.Col(), rRange.aEnd.Row(), nTab );
4742         if (nExtendCol < nStartCol)
4743         {
4744             nStartCol = nExtendCol;
4745             bFound = sal_True;
4746         }
4747         if (nExtendRow < nStartRow)
4748         {
4749             nStartRow = nExtendRow;
4750             bFound = sal_True;
4751         }
4752     }
4753 
4754     rRange.aStart.SetCol(nStartCol);
4755     rRange.aStart.SetRow(nStartRow);
4756 
4757     return bFound;
4758 }
4759 
4760 sal_Bool ScDocument::RefreshAutoFilter( SCCOL nStartCol, SCROW nStartRow,
4761                                     SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
4762 {
4763     sal_uInt16 nCount = pDBCollection->GetCount();
4764     sal_uInt16 i;
4765     ScDBData* pData;
4766     SCTAB nDBTab;
4767     SCCOL nDBStartCol;
4768     SCROW nDBStartRow;
4769     SCCOL nDBEndCol;
4770     SCROW nDBEndRow;
4771 
4772     //      Autofilter loeschen
4773 
4774     sal_Bool bChange = RemoveFlagsTab( nStartCol,nStartRow, nEndCol,nEndRow, nTab, SC_MF_AUTO );
4775 
4776     //      Autofilter setzen
4777 
4778     for (i=0; i<nCount; i++)
4779     {
4780         pData = (*pDBCollection)[i];
4781         if (pData->HasAutoFilter())
4782         {
4783             pData->GetArea( nDBTab, nDBStartCol,nDBStartRow, nDBEndCol,nDBEndRow );
4784             if ( nDBTab==nTab && nDBStartRow<=nEndRow && nDBEndRow>=nStartRow &&
4785                                     nDBStartCol<=nEndCol && nDBEndCol>=nStartCol )
4786             {
4787                 if (ApplyFlagsTab( nDBStartCol,nDBStartRow, nDBEndCol,nDBStartRow,
4788                                     nDBTab, SC_MF_AUTO ))
4789                     bChange = sal_True;
4790             }
4791         }
4792     }
4793     return bChange;
4794 }
4795 
4796 
4797 sal_Bool ScDocument::IsHorOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4798 {
4799     const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
4800                                         GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
4801     if (pAttr)
4802         return pAttr->IsHorOverlapped();
4803     else
4804     {
4805         DBG_ERROR("Overlapped: Attr==0");
4806         return sal_False;
4807     }
4808 }
4809 
4810 
4811 sal_Bool ScDocument::IsVerOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4812 {
4813     const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
4814                                         GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
4815     if (pAttr)
4816         return pAttr->IsVerOverlapped();
4817     else
4818     {
4819         DBG_ERROR("Overlapped: Attr==0");
4820         return sal_False;
4821     }
4822 }
4823 
4824 
4825 void ScDocument::ApplySelectionFrame( const ScMarkData& rMark,
4826                                       const SvxBoxItem* pLineOuter,
4827                                       const SvxBoxInfoItem* pLineInner )
4828 {
4829     ScRangeList aRangeList;
4830     rMark.FillRangeListWithMarks( &aRangeList, sal_False );
4831     sal_uLong nRangeCount = aRangeList.Count();
4832     for (SCTAB i=0; i<=MAXTAB; i++)
4833     {
4834         if (pTab[i] && rMark.GetTableSelect(i))
4835         {
4836             for (sal_uLong j=0; j<nRangeCount; j++)
4837             {
4838                 ScRange aRange = *aRangeList.GetObject(j);
4839                 pTab[i]->ApplyBlockFrame( pLineOuter, pLineInner,
4840                     aRange.aStart.Col(), aRange.aStart.Row(),
4841                     aRange.aEnd.Col(),   aRange.aEnd.Row() );
4842             }
4843         }
4844     }
4845 }
4846 
4847 
4848 void ScDocument::ApplyFrameAreaTab( const ScRange& rRange,
4849                                     const SvxBoxItem* pLineOuter,
4850                                     const SvxBoxInfoItem* pLineInner )
4851 {
4852     SCTAB nStartTab = rRange.aStart.Tab();
4853     SCTAB nEndTab = rRange.aStart.Tab();
4854     for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
4855         if (pTab[nTab])
4856             pTab[nTab]->ApplyBlockFrame( pLineOuter, pLineInner,
4857                                          rRange.aStart.Col(), rRange.aStart.Row(),
4858                                          rRange.aEnd.Col(),   rRange.aEnd.Row() );
4859 }
4860 
4861 
4862 void ScDocument::ApplySelectionPattern( const ScPatternAttr& rAttr, const ScMarkData& rMark )
4863 {
4864     const SfxItemSet* pSet = &rAttr.GetItemSet();
4865     sal_Bool bSet = sal_False;
4866     sal_uInt16 i;
4867     for (i=ATTR_PATTERN_START; i<=ATTR_PATTERN_END && !bSet; i++)
4868         if (pSet->GetItemState(i) == SFX_ITEM_SET)
4869             bSet = sal_True;
4870 
4871     if (bSet)
4872     {
4873         // ApplySelectionCache needs multi mark
4874         if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
4875         {
4876             ScRange aRange;
4877             rMark.GetMarkArea( aRange );
4878             ApplyPatternArea( aRange.aStart.Col(), aRange.aStart.Row(),
4879                               aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rAttr );
4880         }
4881         else
4882         {
4883             SfxItemPoolCache aCache( xPoolHelper->GetDocPool(), pSet );
4884             for (SCTAB nTab=0; nTab<=MAXTAB; nTab++)
4885                 if (pTab[nTab])
4886                     if (rMark.GetTableSelect(nTab))
4887                         pTab[nTab]->ApplySelectionCache( &aCache, rMark );
4888         }
4889     }
4890 }
4891 
4892 
4893 void ScDocument::ChangeSelectionIndent( sal_Bool bIncrement, const ScMarkData& rMark )
4894 {
4895     for (SCTAB i=0; i<=MAXTAB; i++)
4896         if (pTab[i] && rMark.GetTableSelect(i))
4897             pTab[i]->ChangeSelectionIndent( bIncrement, rMark );
4898 }
4899 
4900 
4901 void ScDocument::ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark )
4902 {
4903     for (SCTAB i=0; i<=MAXTAB; i++)
4904         if (pTab[i] && rMark.GetTableSelect(i))
4905             pTab[i]->ClearSelectionItems( pWhich, rMark );
4906 }
4907 
4908 
4909 void ScDocument::DeleteSelection( sal_uInt16 nDelFlag, const ScMarkData& rMark )
4910 {
4911     for (SCTAB i=0; i<=MAXTAB; i++)
4912         if (pTab[i] && rMark.GetTableSelect(i))
4913             pTab[i]->DeleteSelection( nDelFlag, rMark );
4914 }
4915 
4916 
4917 void ScDocument::DeleteSelectionTab( SCTAB nTab, sal_uInt16 nDelFlag, const ScMarkData& rMark )
4918 {
4919     if (ValidTab(nTab)  && pTab[nTab])
4920         pTab[nTab]->DeleteSelection( nDelFlag, rMark );
4921     else
4922     {
4923         DBG_ERROR("Falsche Tabelle");
4924     }
4925 }
4926 
4927 
4928 ScPatternAttr* ScDocument::GetDefPattern() const
4929 {
4930     return (ScPatternAttr*) &xPoolHelper->GetDocPool()->GetDefaultItem(ATTR_PATTERN);
4931 }
4932 
4933 
4934 ScDocumentPool* ScDocument::GetPool()
4935 {
4936     return xPoolHelper->GetDocPool();
4937 }
4938 
4939 
4940 
4941 ScStyleSheetPool* ScDocument::GetStyleSheetPool() const
4942 {
4943     return xPoolHelper->GetStylePool();
4944 }
4945 
4946 
4947 SCSIZE ScDocument::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
4948                             SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, ScDirection eDir )
4949 {
4950     PutInOrder(nStartCol, nEndCol);
4951     PutInOrder(nStartRow, nEndRow);
4952     PutInOrder(nStartTab, nEndTab);
4953     if (VALIDTAB(nStartTab))
4954     {
4955         if (pTab[nStartTab])
4956             return pTab[nStartTab]->GetEmptyLinesInBlock(nStartCol, nStartRow, nEndCol, nEndRow, eDir);
4957         else
4958             return 0;
4959     }
4960     else
4961         return 0;
4962 }
4963 
4964 
4965 void ScDocument::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY )
4966 {
4967     if (ValidTab(nTab) && pTab[nTab])
4968         pTab[nTab]->FindAreaPos( rCol, rRow, nMovX, nMovY );
4969 }
4970 
4971 
4972 void ScDocument::GetNextPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY,
4973                                 sal_Bool bMarked, sal_Bool bUnprotected, const ScMarkData& rMark )
4974 {
4975     DBG_ASSERT( !nMovX || !nMovY, "GetNextPos: nur X oder Y" );
4976 
4977     ScMarkData aCopyMark = rMark;
4978     aCopyMark.SetMarking(sal_False);
4979     aCopyMark.MarkToMulti();
4980 
4981     if (ValidTab(nTab) && pTab[nTab])
4982         pTab[nTab]->GetNextPos( rCol, rRow, nMovX, nMovY, bMarked, bUnprotected, aCopyMark );
4983 }
4984 
4985 //
4986 //  Datei-Operationen
4987 //
4988 
4989 
4990 void ScDocument::UpdStlShtPtrsFrmNms()
4991 {
4992     ScPatternAttr::pDoc = this;
4993 
4994     ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4995 
4996     sal_uInt32 nCount = pPool->GetItemCount2(ATTR_PATTERN);
4997     ScPatternAttr* pPattern;
4998     for (sal_uInt32 i=0; i<nCount; i++)
4999     {
5000         pPattern = (ScPatternAttr*)pPool->GetItem2(ATTR_PATTERN, i);
5001         if (pPattern)
5002             pPattern->UpdateStyleSheet();
5003     }
5004     ((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).UpdateStyleSheet();
5005 }
5006 
5007 
5008 void ScDocument::StylesToNames()
5009 {
5010     ScPatternAttr::pDoc = this;
5011 
5012     ScDocumentPool* pPool = xPoolHelper->GetDocPool();
5013 
5014     sal_uInt32 nCount = pPool->GetItemCount2(ATTR_PATTERN);
5015     ScPatternAttr* pPattern;
5016     for (sal_uInt32 i=0; i<nCount; i++)
5017     {
5018         pPattern = (ScPatternAttr*)pPool->GetItem2(ATTR_PATTERN, i);
5019         if (pPattern)
5020             pPattern->StyleToName();
5021     }
5022     ((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).StyleToName();
5023 }
5024 
5025 
5026 sal_uLong ScDocument::GetCellCount() const
5027 {
5028     sal_uLong nCellCount = 0L;
5029 
5030     for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
5031         if ( pTab[nTab] )
5032             nCellCount += pTab[nTab]->GetCellCount();
5033 
5034     return nCellCount;
5035 }
5036 
5037 SCSIZE ScDocument::GetCellCount(SCTAB nTab, SCCOL nCol) const
5038 {
5039     if (!ValidTab(nTab) || !pTab[nTab])
5040         return 0;
5041 
5042     return pTab[nTab]->GetCellCount(nCol);
5043 }
5044 
5045 sal_uLong ScDocument::GetCodeCount() const
5046 {
5047     sal_uLong nCodeCount = 0;
5048 
5049     for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
5050         if ( pTab[nTab] )
5051             nCodeCount += pTab[nTab]->GetCodeCount();
5052 
5053     return nCodeCount;
5054 }
5055 
5056 
5057 sal_uLong ScDocument::GetWeightedCount() const
5058 {
5059     sal_uLong nCellCount = 0L;
5060 
5061     for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
5062         if ( pTab[nTab] )
5063             nCellCount += pTab[nTab]->GetWeightedCount();
5064 
5065     return nCellCount;
5066 }
5067 
5068 
5069 void ScDocument::PageStyleModified( SCTAB nTab, const String& rNewName )
5070 {
5071     if ( ValidTab(nTab)  && pTab[nTab] )
5072         pTab[nTab]->PageStyleModified( rNewName );
5073 }
5074 
5075 
5076 void ScDocument::SetPageStyle( SCTAB nTab, const String& rName )
5077 {
5078     if ( ValidTab(nTab)  && pTab[nTab] )
5079         pTab[nTab]->SetPageStyle( rName );
5080 }
5081 
5082 
5083 const String& ScDocument::GetPageStyle( SCTAB nTab ) const
5084 {
5085     if ( ValidTab(nTab)  && pTab[nTab] )
5086         return pTab[nTab]->GetPageStyle();
5087 
5088     return EMPTY_STRING;
5089 }
5090 
5091 
5092 void ScDocument::SetPageSize( SCTAB nTab, const Size& rSize )
5093 {
5094     if ( ValidTab(nTab)  && pTab[nTab] )
5095         pTab[nTab]->SetPageSize( rSize );
5096 }
5097 
5098 Size ScDocument::GetPageSize( SCTAB nTab ) const
5099 {
5100     if ( ValidTab(nTab)  && pTab[nTab] )
5101         return pTab[nTab]->GetPageSize();
5102 
5103     DBG_ERROR("falsche Tab");
5104     return Size();
5105 }
5106 
5107 
5108 void ScDocument::SetRepeatArea( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow )
5109 {
5110     if ( ValidTab(nTab)  && pTab[nTab] )
5111         pTab[nTab]->SetRepeatArea( nStartCol, nEndCol, nStartRow, nEndRow );
5112 }
5113 
5114 void ScDocument::InvalidatePageBreaks(SCTAB nTab)
5115 {
5116     if (ValidTab(nTab) && pTab[nTab])
5117         pTab[nTab]->InvalidatePageBreaks();
5118 }
5119 
5120 void ScDocument::UpdatePageBreaks( SCTAB nTab, const ScRange* pUserArea )
5121 {
5122     if ( ValidTab(nTab)  && pTab[nTab] )
5123         pTab[nTab]->UpdatePageBreaks( pUserArea );
5124 }
5125 
5126 void ScDocument::RemoveManualBreaks( SCTAB nTab )
5127 {
5128     if ( ValidTab(nTab)  && pTab[nTab] )
5129         pTab[nTab]->RemoveManualBreaks();
5130 }
5131 
5132 sal_Bool ScDocument::HasManualBreaks( SCTAB nTab ) const
5133 {
5134     if ( ValidTab(nTab)  && pTab[nTab] )
5135         return pTab[nTab]->HasManualBreaks();
5136 
5137     DBG_ERROR("falsche Tab");
5138     return sal_False;
5139 }
5140 
5141 
5142 void ScDocument::GetDocStat( ScDocStat& rDocStat )
5143 {
5144     rDocStat.nTableCount = GetTableCount();
5145     rDocStat.aDocName    = aDocName;
5146     rDocStat.nCellCount  = GetCellCount();
5147 }
5148 
5149 
5150 sal_Bool ScDocument::HasPrintRange()
5151 {
5152     sal_Bool bResult = sal_False;
5153 
5154     for ( SCTAB i=0; !bResult && i<nMaxTableNumber; i++ )
5155         if ( pTab[i] )
5156             bResult = pTab[i]->IsPrintEntireSheet() || (pTab[i]->GetPrintRangeCount() > 0);
5157 
5158     return bResult;
5159 }
5160 
5161 
5162 sal_Bool ScDocument::IsPrintEntireSheet( SCTAB nTab ) const
5163 {
5164     return (ValidTab(nTab) ) && pTab[nTab] && pTab[nTab]->IsPrintEntireSheet();
5165 }
5166 
5167 
5168 sal_uInt16 ScDocument::GetPrintRangeCount( SCTAB nTab )
5169 {
5170     if (ValidTab(nTab) && pTab[nTab])
5171         return pTab[nTab]->GetPrintRangeCount();
5172 
5173     return 0;
5174 }
5175 
5176 
5177 const ScRange* ScDocument::GetPrintRange( SCTAB nTab, sal_uInt16 nPos )
5178 {
5179     if (ValidTab(nTab) && pTab[nTab])
5180         return pTab[nTab]->GetPrintRange(nPos);
5181 
5182     return NULL;
5183 }
5184 
5185 
5186 const ScRange* ScDocument::GetRepeatColRange( SCTAB nTab )
5187 {
5188     if (ValidTab(nTab) && pTab[nTab])
5189         return pTab[nTab]->GetRepeatColRange();
5190 
5191     return NULL;
5192 }
5193 
5194 
5195 const ScRange* ScDocument::GetRepeatRowRange( SCTAB nTab )
5196 {
5197     if (ValidTab(nTab) && pTab[nTab])
5198         return pTab[nTab]->GetRepeatRowRange();
5199 
5200     return NULL;
5201 }
5202 
5203 
5204 void ScDocument::ClearPrintRanges( SCTAB nTab )
5205 {
5206     if (ValidTab(nTab) && pTab[nTab])
5207         pTab[nTab]->ClearPrintRanges();
5208 }
5209 
5210 
5211 void ScDocument::AddPrintRange( SCTAB nTab, const ScRange& rNew )
5212 {
5213     if (ValidTab(nTab) && pTab[nTab])
5214         pTab[nTab]->AddPrintRange( rNew );
5215 }
5216 
5217 
5218 //UNUSED2009-05 void ScDocument::SetPrintRange( SCTAB nTab, const ScRange& rNew )
5219 //UNUSED2009-05 {
5220 //UNUSED2009-05     if (ValidTab(nTab) && pTab[nTab])
5221 //UNUSED2009-05         pTab[nTab]->SetPrintRange( rNew );
5222 //UNUSED2009-05 }
5223 
5224 
5225 void ScDocument::SetPrintEntireSheet( SCTAB nTab )
5226 {
5227     if (ValidTab(nTab) && pTab[nTab])
5228         pTab[nTab]->SetPrintEntireSheet();
5229 }
5230 
5231 
5232 void ScDocument::SetRepeatColRange( SCTAB nTab, const ScRange* pNew )
5233 {
5234     if (ValidTab(nTab) && pTab[nTab])
5235         pTab[nTab]->SetRepeatColRange( pNew );
5236 }
5237 
5238 
5239 void ScDocument::SetRepeatRowRange( SCTAB nTab, const ScRange* pNew )
5240 {
5241     if (ValidTab(nTab) && pTab[nTab])
5242         pTab[nTab]->SetRepeatRowRange( pNew );
5243 }
5244 
5245 
5246 ScPrintRangeSaver* ScDocument::CreatePrintRangeSaver() const
5247 {
5248     SCTAB nCount = GetTableCount();
5249     ScPrintRangeSaver* pNew = new ScPrintRangeSaver( nCount );
5250     for (SCTAB i=0; i<nCount; i++)
5251         if (pTab[i])
5252             pTab[i]->FillPrintSaver( pNew->GetTabData(i) );
5253     return pNew;
5254 }
5255 
5256 
5257 void ScDocument::RestorePrintRanges( const ScPrintRangeSaver& rSaver )
5258 {
5259     SCTAB nCount = rSaver.GetTabCount();
5260     for (SCTAB i=0; i<nCount; i++)
5261         if (pTab[i])
5262             pTab[i]->RestorePrintRanges( rSaver.GetTabData(i) );
5263 }
5264 
5265 
5266 sal_Bool ScDocument::NeedPageResetAfterTab( SCTAB nTab ) const
5267 {
5268     //  Die Seitennummern-Zaehlung faengt bei einer Tabelle neu an, wenn eine
5269     //  andere Vorlage als bei der vorherigen gesetzt ist (nur Namen vergleichen)
5270     //  und eine Seitennummer angegeben ist (nicht 0)
5271 
5272     if ( nTab < MAXTAB && pTab[nTab] && pTab[nTab+1] )
5273     {
5274         String aNew = pTab[nTab+1]->GetPageStyle();
5275         if ( aNew != pTab[nTab]->GetPageStyle() )
5276         {
5277             SfxStyleSheetBase* pStyle = xPoolHelper->GetStylePool()->Find( aNew, SFX_STYLE_FAMILY_PAGE );
5278             if ( pStyle )
5279             {
5280                 const SfxItemSet& rSet = pStyle->GetItemSet();
5281                 sal_uInt16 nFirst = ((const SfxUInt16Item&)rSet.Get(ATTR_PAGE_FIRSTPAGENO)).GetValue();
5282                 if ( nFirst != 0 )
5283                     return sal_True;        // Seitennummer in neuer Vorlage angegeben
5284             }
5285         }
5286     }
5287 
5288     return sal_False;       // sonst nicht
5289 }
5290 
5291 SfxUndoManager* ScDocument::GetUndoManager()
5292 {
5293     if (!mpUndoManager)
5294     {
5295         // to support enhanced text edit for draw objects, use an SdrUndoManager
5296         mpUndoManager = new SdrUndoManager;
5297     }
5298 
5299     return mpUndoManager;
5300 }
5301 
5302 ScRowBreakIterator* ScDocument::GetRowBreakIterator(SCTAB nTab) const
5303 {
5304     if (ValidTab(nTab) && pTab[nTab])
5305         return new ScRowBreakIterator(pTab[nTab]->maRowPageBreaks);
5306     return NULL;
5307 }
5308 
5309 void ScDocument::EnableUndo( bool bVal )
5310 {
5311     GetUndoManager()->EnableUndo(bVal);
5312     if( pDrawLayer ) pDrawLayer->EnableUndo(bVal);
5313     mbUndoEnabled = bVal;
5314 }
5315 
5316 bool ScDocument::IsInVBAMode() const
5317 {
5318     bool bResult = false;
5319     if ( pShell )
5320     {
5321         com::sun::star::uno::Reference< com::sun::star::script::vba::XVBACompatibility > xVBA( pShell->GetBasicContainer(), com::sun::star::uno::UNO_QUERY );
5322         bResult = xVBA.is() && xVBA->getVBACompatibilityMode();
5323     }
5324     return bResult;
5325 }
5326