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