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