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