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