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