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