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