xref: /trunk/main/sc/source/core/data/document.cxx (revision 30acf5e801d38c3701bf451b42e514ce81855b4c)
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             (pCBFCP->pClipDoc->GetClipParam().getSourceDocID() == GetDocumentID()) ) // #118023# only update references for *intra-document* cut and paste
1970     {
1971         nClipTab = 0;
1972         for (SCTAB i = pCBFCP->nTabStart; i <= nTabEnd; i++)
1973         {
1974             if (pTab[i] && rMark.GetTableSelect(i) )
1975             {
1976                 while (!ppClipTab[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
1977                 SCsTAB nDz = ((SCsTAB)i) - nClipTab;
1978 
1979                 //  #89081# ranges of consecutive selected tables (in clipboard and dest. doc)
1980                 //  must be handled in one UpdateReference call
1981                 SCTAB nFollow = 0;
1982                 while ( i + nFollow < nTabEnd
1983                         && rMark.GetTableSelect( i + nFollow + 1 )
1984                         && nClipTab + nFollow < MAXTAB
1985                         && ppClipTab[nClipTab + nFollow + 1] )
1986                     ++nFollow;
1987 
1988                 if ( pCBFCP->pClipDoc->GetClipParam().mbCutMode )
1989                 {
1990                     sal_Bool bOldInserting = IsInsertingFromOtherDoc();
1991                     SetInsertingFromOtherDoc( sal_True);
1992                     UpdateReference( URM_MOVE,
1993                         nCol1, nRow1, i, nCol2, nRow2, i+nFollow,
1994                         nDx, nDy, nDz, pCBFCP->pRefUndoDoc, sal_False );
1995                     SetInsertingFromOtherDoc( bOldInserting);
1996                 }
1997                 else
1998                     UpdateReference( URM_COPY,
1999                         nCol1, nRow1, i, nCol2, nRow2, i+nFollow,
2000                         nDx, nDy, nDz, pCBFCP->pRefUndoDoc, sal_False );
2001 
2002                 nClipTab = (nClipTab+nFollow+1) % (MAXTAB+1);
2003                 i = sal::static_int_cast<SCTAB>( i + nFollow );
2004             }
2005         }
2006     }
2007 }
2008 
2009 
2010 void ScDocument::CopyNonFilteredFromClip( SCCOL nCol1, SCROW nRow1,
2011                                     SCCOL nCol2, SCROW nRow2,
2012                                     const ScMarkData& rMark,
2013                                     SCsCOL nDx, SCsROW /* nDy */,
2014                                     const ScCopyBlockFromClipParams* pCBFCP,
2015                                     SCROW & rClipStartRow )
2016 {
2017     //  call CopyBlockFromClip for ranges of consecutive non-filtered rows
2018     //  nCol1/nRow1 etc. is in target doc
2019 
2020     //  filtered state is taken from first used table in clipboard (as in GetClipArea)
2021     SCTAB nFlagTab = 0;
2022     ScTable** ppClipTab = pCBFCP->pClipDoc->pTab;
2023     while ( nFlagTab < MAXTAB && !ppClipTab[nFlagTab] )
2024         ++nFlagTab;
2025 
2026     SCROW nSourceRow = rClipStartRow;
2027     SCROW nSourceEnd = 0;
2028     if (pCBFCP->pClipDoc->GetClipParam().maRanges.Count())
2029         nSourceEnd = pCBFCP->pClipDoc->GetClipParam().maRanges.First()->aEnd.Row();
2030     SCROW nDestRow = nRow1;
2031 
2032     while ( nSourceRow <= nSourceEnd && nDestRow <= nRow2 )
2033     {
2034         // skip filtered rows
2035         nSourceRow = pCBFCP->pClipDoc->FirstNonFilteredRow(nSourceRow, nSourceEnd, nFlagTab);
2036 
2037         if ( nSourceRow <= nSourceEnd )
2038         {
2039             // look for more non-filtered rows following
2040             SCROW nLastRow = nSourceRow;
2041             pCBFCP->pClipDoc->RowFiltered(nSourceRow, nFlagTab, NULL, &nLastRow);
2042             SCROW nFollow = nLastRow - nSourceRow;
2043 
2044             if (nFollow > nSourceEnd - nSourceRow)
2045                 nFollow = nSourceEnd - nSourceRow;
2046             if (nFollow > nRow2 - nDestRow)
2047                 nFollow = nRow2 - nDestRow;
2048 
2049             SCsROW nNewDy = ((SCsROW)nDestRow) - nSourceRow;
2050             CopyBlockFromClip( nCol1, nDestRow, nCol2, nDestRow + nFollow, rMark, nDx, nNewDy, pCBFCP );
2051 
2052             nSourceRow += nFollow + 1;
2053             nDestRow += nFollow + 1;
2054         }
2055     }
2056     rClipStartRow = nSourceRow;
2057 }
2058 
2059 
2060 void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMark,
2061                                 sal_uInt16 nInsFlag,
2062                                 ScDocument* pRefUndoDoc, ScDocument* pClipDoc, sal_Bool bResetCut,
2063                                 sal_Bool bAsLink, sal_Bool bIncludeFiltered, sal_Bool bSkipAttrForEmpty,
2064                                 const ScRangeList * pDestRanges )
2065 {
2066     if (!bIsClip)
2067     {
2068         if (!pClipDoc)
2069         {
2070             DBG_ERROR("CopyFromClip: no ClipDoc");
2071             pClipDoc = SC_MOD()->GetClipDoc();
2072         }
2073         if (pClipDoc->bIsClip && pClipDoc->GetTableCount())
2074         {
2075             sal_Bool bOldAutoCalc = GetAutoCalc();
2076             SetAutoCalc( sal_False );   // avoid multiple recalculations
2077 
2078             NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
2079 
2080             ScClipRangeNameData aClipRangeNames;
2081             CopyRangeNamesFromClip(pClipDoc, aClipRangeNames);
2082 
2083             SCCOL nAllCol1 = rDestRange.aStart.Col();
2084             SCROW nAllRow1 = rDestRange.aStart.Row();
2085             SCCOL nAllCol2 = rDestRange.aEnd.Col();
2086             SCROW nAllRow2 = rDestRange.aEnd.Row();
2087 
2088             SCCOL nXw = 0;
2089             SCROW nYw = 0;
2090             ScRange aClipRange = pClipDoc->GetClipParam().getWholeRange();
2091             for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)    // find largest merge overlap
2092                 if (pClipDoc->pTab[nTab])                   // all sheets of the clipboard content
2093                 {
2094                     SCCOL nThisEndX = aClipRange.aEnd.Col();
2095                     SCROW nThisEndY = aClipRange.aEnd.Row();
2096                     pClipDoc->ExtendMerge( aClipRange.aStart.Col(),
2097                                             aClipRange.aStart.Row(),
2098                                             nThisEndX, nThisEndY, nTab );
2099                     // only extra value from ExtendMerge
2100                     nThisEndX = sal::static_int_cast<SCCOL>( nThisEndX - aClipRange.aEnd.Col() );
2101                     nThisEndY = sal::static_int_cast<SCROW>( nThisEndY - aClipRange.aEnd.Row() );
2102                     if ( nThisEndX > nXw )
2103                         nXw = nThisEndX;
2104                     if ( nThisEndY > nYw )
2105                         nYw = nThisEndY;
2106                 }
2107 
2108             SCCOL nDestAddX;
2109             SCROW nDestAddY;
2110             pClipDoc->GetClipArea( nDestAddX, nDestAddY, bIncludeFiltered );
2111             nXw = sal::static_int_cast<SCCOL>( nXw + nDestAddX );
2112             nYw = sal::static_int_cast<SCROW>( nYw + nDestAddY );   // ClipArea, plus ExtendMerge value
2113 
2114             /*  Decide which contents to delete before copying. Delete all
2115                 contents if nInsFlag contains any real content flag.
2116                 #i102056# Notes are pasted from clipboard in a second pass,
2117                 together with the special flag IDF_ADDNOTES that states to not
2118                 overwrite/delete existing cells but to insert the notes into
2119                 these cells. In this case, just delete old notes from the
2120                 destination area. */
2121             sal_uInt16 nDelFlag = IDF_NONE;
2122             if ( (nInsFlag & (IDF_CONTENTS | IDF_ADDNOTES)) == (IDF_NOTE | IDF_ADDNOTES) )
2123                 nDelFlag |= IDF_NOTE;
2124             else if ( nInsFlag & IDF_CONTENTS )
2125                 nDelFlag |= IDF_CONTENTS;
2126             //  With bSkipAttrForEmpty, don't remove attributes, copy
2127             //  on top of existing attributes instead.
2128             if ( ( nInsFlag & IDF_ATTRIB ) && !bSkipAttrForEmpty )
2129                 nDelFlag |= IDF_ATTRIB;
2130 
2131             ScCopyBlockFromClipParams aCBFCP;
2132             aCBFCP.pRefUndoDoc = pRefUndoDoc;
2133             aCBFCP.pClipDoc = pClipDoc;
2134             aCBFCP.nInsFlag = nInsFlag;
2135             aCBFCP.bAsLink  = bAsLink;
2136             aCBFCP.bSkipAttrForEmpty = bSkipAttrForEmpty;
2137             aCBFCP.nTabStart = MAXTAB;      // wird in der Schleife angepasst
2138             aCBFCP.nTabEnd = 0;             // wird in der Schleife angepasst
2139 
2140             //  Inc/DecRecalcLevel einmal aussen, damit nicht fuer jeden Block
2141             //  die Draw-Seitengroesse neu berechnet werden muss
2142             //! nur wenn ganze Zeilen/Spalten kopiert werden?
2143 
2144             for (SCTAB j = 0; j <= MAXTAB; j++)
2145                 if (pTab[j] && rMark.GetTableSelect(j))
2146                 {
2147                     if ( j < aCBFCP.nTabStart )
2148                         aCBFCP.nTabStart = j;
2149                     aCBFCP.nTabEnd = j;
2150                     pTab[j]->IncRecalcLevel();
2151                 }
2152 
2153             ScRangeList aLocalRangeList;
2154             if (!pDestRanges)
2155             {
2156                 aLocalRangeList.Append( rDestRange);
2157                 pDestRanges = &aLocalRangeList;
2158             }
2159 
2160             bInsertingFromOtherDoc = sal_True;  // kein Broadcast/Listener aufbauen bei Insert
2161 
2162             // bei mindestens 64 Zeilen wird in ScColumn::CopyFromClip voralloziert
2163             sal_Bool bDoDouble = ( nYw < 64 && nAllRow2 - nAllRow1 > 64);
2164             sal_Bool bOldDouble = ScColumn::bDoubleAlloc;
2165             if (bDoDouble)
2166                 ScColumn::bDoubleAlloc = sal_True;
2167 
2168             SCCOL nClipStartCol = aClipRange.aStart.Col();
2169             SCROW nClipStartRow = aClipRange.aStart.Row();
2170             // WaE: commented because unused:   SCCOL nClipEndCol = pClipDoc->aClipRange.aEnd.Col();
2171             SCROW nClipEndRow = aClipRange.aEnd.Row();
2172             for (sal_uLong nRange = 0; nRange < pDestRanges->Count(); ++nRange)
2173             {
2174                 const ScRange* pRange = pDestRanges->GetObject( nRange);
2175                 SCCOL nCol1 = pRange->aStart.Col();
2176                 SCROW nRow1 = pRange->aStart.Row();
2177                 SCCOL nCol2 = pRange->aEnd.Col();
2178                 SCROW nRow2 = pRange->aEnd.Row();
2179 
2180                 DeleteArea(nCol1, nRow1, nCol2, nRow2, rMark, nDelFlag);
2181 
2182                 SCCOL nC1 = nCol1;
2183                 SCROW nR1 = nRow1;
2184                 SCCOL nC2 = nC1 + nXw;
2185                 if (nC2 > nCol2)
2186                     nC2 = nCol2;
2187                 SCROW nR2 = nR1 + nYw;
2188                 if (nR2 > nRow2)
2189                     nR2 = nRow2;
2190 
2191                 const unsigned PERFORMANCEOPTIMIZATION4PATTERNTHRESHOLD = 8192;
2192                 bool bNeedPerformanceOptimization4Pattern = nRow2 - nRow1 > PERFORMANCEOPTIMIZATION4PATTERNTHRESHOLD;
2193                 std::vector< std::vector< SCSIZE > > vvPatternCount( bNeedPerformanceOptimization4Pattern ? nCol2 - nCol1 + 1 : 0 );
2194                 std::vector< SCTAB > vTables;
2195 
2196                 if( bNeedPerformanceOptimization4Pattern )
2197                 {
2198                     for (SCTAB i = aCBFCP.nTabStart; i <= aCBFCP.nTabEnd; i++)
2199                         if (pTab[i] && rMark.GetTableSelect( i ) )
2200                             vTables.push_back( i );
2201 
2202                     for( SCSIZE i = 0; i < vvPatternCount.size(); i++ )
2203                     {
2204                         vvPatternCount[i].resize( vTables.size() );
2205 
2206                         for( std::vector< SCTAB >::size_type j = 0; j<vTables.size(); j++ )
2207                             vvPatternCount[i][j] = this->GetPatternCount( vTables[j], nCol1+i );
2208                     }
2209                 }
2210 
2211                 do
2212                 {
2213                     // Pasting is done column-wise, when pasting to a filtered
2214                     // area this results in partitioning and we have to
2215                     // remember and reset the start row for each column until
2216                     // it can be advanced for the next chunk of unfiltered
2217                     // rows.
2218                     SCROW nSaveClipStartRow = nClipStartRow;
2219                     do
2220                     {
2221                         nClipStartRow = nSaveClipStartRow;
2222                         SCsCOL nDx = ((SCsCOL)nC1) - nClipStartCol;
2223                         SCsROW nDy = ((SCsROW)nR1) - nClipStartRow;
2224                         if ( bIncludeFiltered )
2225                         {
2226                             CopyBlockFromClip( nC1, nR1, nC2, nR2, rMark, nDx,
2227                                     nDy, &aCBFCP );
2228                             nClipStartRow += nR2 - nR1 + 1;
2229                         }
2230                         else
2231                         {
2232                             CopyNonFilteredFromClip( nC1, nR1, nC2, nR2, rMark,
2233                                     nDx, nDy, &aCBFCP, nClipStartRow );
2234                         }
2235                         // Not needed for columns, but if it was this would be how to.
2236                         //if (nClipStartCol > nClipEndCol)
2237                         //    nClipStartCol = pClipDoc->aClipRange.aStart.Col();
2238                         nC1 = nC2 + 1;
2239                         nC2 = Min((SCCOL)(nC1 + nXw), nCol2);
2240                     } while (nC1 <= nCol2);
2241                     if (nClipStartRow > nClipEndRow)
2242                         nClipStartRow = aClipRange.aStart.Row();
2243                     nC1 = nCol1;
2244                     nC2 = nC1 + nXw;
2245                     if (nC2 > nCol2)
2246                         nC2 = nCol2;
2247 
2248                     if( bNeedPerformanceOptimization4Pattern && vvPatternCount.size() )
2249                     {
2250                         for( SCSIZE i = 0; i < vvPatternCount.size(); i++ )
2251                         {
2252                             vvPatternCount[i].resize( vTables.size() );
2253 
2254                             for( std::vector< SCTAB >::size_type j = 0; j<vTables.size(); j++ )
2255                                 this->ReservedPatternCount( vTables[j], nCol1+i, vvPatternCount[i][j] + ( this->GetPatternCount( vTables[j], nCol1+i, nR1, nR2 ) ) * ( ( nRow2 - nRow1 + 1 ) / ( nYw + 1 ) ) );
2256                         }
2257 
2258                         bNeedPerformanceOptimization4Pattern = false;
2259                         vvPatternCount.clear();
2260                     }
2261 
2262                     nR1 = nR2 + 1;
2263                     nR2 = Min((SCROW)(nR1 + nYw), nRow2);
2264                 } while (nR1 <= nRow2);
2265             }
2266 
2267             ScColumn::bDoubleAlloc = bOldDouble;
2268 
2269             for (SCTAB k = 0; k <= MAXTAB; k++)
2270                 if (pTab[k] && rMark.GetTableSelect(k))
2271                     pTab[k]->DecRecalcLevel();
2272 
2273             bInsertingFromOtherDoc = sal_False;
2274 
2275             UpdateRangeNamesInFormulas(aClipRangeNames, *pDestRanges, rMark, nXw, nYw);
2276 
2277             // Listener aufbauen nachdem alles inserted wurde
2278             StartListeningFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
2279             // nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
2280             BroadcastFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
2281             if (bResetCut)
2282                 pClipDoc->GetClipParam().mbCutMode = false;
2283             SetAutoCalc( bOldAutoCalc );
2284         }
2285     }
2286 }
2287 
2288 static SCROW lcl_getLastNonFilteredRow(
2289     const ScBitMaskCompressedArray<SCROW, sal_uInt8>& rFlags, SCROW nBegRow, SCROW nEndRow,
2290     SCROW nRowCount)
2291 {
2292     SCROW nFilteredRow = rFlags.GetFirstForCondition(
2293         nBegRow, nEndRow, CR_FILTERED, CR_FILTERED);
2294 
2295     SCROW nRow = nFilteredRow - 1;
2296     if (nRow - nBegRow + 1 > nRowCount)
2297         // make sure the row range stays within the data size.
2298         nRow = nBegRow + nRowCount - 1;
2299 
2300     return nRow;
2301 }
2302 
2303 void ScDocument::CopyMultiRangeFromClip(
2304     const ScAddress& rDestPos, const ScMarkData& rMark, sal_uInt16 nInsFlag, ScDocument* pClipDoc,
2305     bool bResetCut, bool bAsLink, bool /*bIncludeFiltered*/, bool bSkipAttrForEmpty)
2306 {
2307     if (bIsClip)
2308         return;
2309 
2310     if (!pClipDoc->bIsClip || !pClipDoc->GetTableCount())
2311         // There is nothing in the clip doc to copy.
2312         return;
2313 
2314     sal_Bool bOldAutoCalc = GetAutoCalc();
2315     SetAutoCalc( sal_False );   // avoid multiple recalculations
2316 
2317     NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
2318 
2319     ScClipRangeNameData aClipRangeNames;
2320     CopyRangeNamesFromClip(pClipDoc, aClipRangeNames);
2321 
2322     SCCOL nCol1 = rDestPos.Col();
2323     SCROW nRow1 = rDestPos.Row();
2324     ScClipParam& rClipParam = pClipDoc->GetClipParam();
2325 
2326     ScCopyBlockFromClipParams aCBFCP;
2327     aCBFCP.pRefUndoDoc = NULL;
2328     aCBFCP.pClipDoc = pClipDoc;
2329     aCBFCP.nInsFlag = nInsFlag;
2330     aCBFCP.bAsLink  = bAsLink;
2331     aCBFCP.bSkipAttrForEmpty = bSkipAttrForEmpty;
2332     aCBFCP.nTabStart = MAXTAB;
2333     aCBFCP.nTabEnd = 0;
2334 
2335     for (SCTAB j = 0; j <= MAXTAB; ++j)
2336     {
2337         if (pTab[j] && rMark.GetTableSelect(j))
2338         {
2339             if ( j < aCBFCP.nTabStart )
2340                 aCBFCP.nTabStart = j;
2341             aCBFCP.nTabEnd = j;
2342             pTab[j]->IncRecalcLevel();
2343         }
2344     }
2345 
2346     ScRange aDestRange;
2347     rMark.GetMarkArea(aDestRange);
2348     SCROW nLastMarkedRow = aDestRange.aEnd.Row();
2349 
2350     bInsertingFromOtherDoc = sal_True;  // kein Broadcast/Listener aufbauen bei Insert
2351 
2352     SCROW nBegRow = nRow1;
2353     sal_uInt16 nDelFlag = IDF_CONTENTS;
2354     const ScBitMaskCompressedArray<SCROW, sal_uInt8>& rFlags = GetRowFlagsArray(aCBFCP.nTabStart);
2355 
2356     for (ScRange* p = rClipParam.maRanges.First(); p; p = rClipParam.maRanges.Next())
2357     {
2358         // The begin row must not be filtered.
2359 
2360         SCROW nRowCount = p->aEnd.Row() - p->aStart.Row() + 1;
2361 
2362         SCsCOL nDx = static_cast<SCsCOL>(nCol1 - p->aStart.Col());
2363         SCsROW nDy = static_cast<SCsROW>(nBegRow - p->aStart.Row());
2364         SCCOL nCol2 = nCol1 + p->aEnd.Col() - p->aStart.Col();
2365 
2366         SCROW nEndRow = lcl_getLastNonFilteredRow(rFlags, nBegRow, nLastMarkedRow, nRowCount);
2367 
2368         if (!bSkipAttrForEmpty)
2369             DeleteArea(nCol1, nBegRow, nCol2, nEndRow, rMark, nDelFlag);
2370 
2371         CopyBlockFromClip(nCol1, nBegRow, nCol2, nEndRow, rMark, nDx, nDy, &aCBFCP);
2372         nRowCount -= nEndRow - nBegRow + 1;
2373 
2374         while (nRowCount > 0)
2375         {
2376             // Get the first non-filtered row.
2377             SCROW nNonFilteredRow = rFlags.GetFirstForCondition(nEndRow+1, nLastMarkedRow, CR_FILTERED, 0);
2378             if (nNonFilteredRow > nLastMarkedRow)
2379                 return;
2380 
2381             SCROW nRowsSkipped = nNonFilteredRow - nEndRow - 1;
2382             nDy += nRowsSkipped;
2383 
2384             nBegRow = nNonFilteredRow;
2385             nEndRow = lcl_getLastNonFilteredRow(rFlags, nBegRow, nLastMarkedRow, nRowCount);
2386 
2387             if (!bSkipAttrForEmpty)
2388                 DeleteArea(nCol1, nBegRow, nCol2, nEndRow, rMark, nDelFlag);
2389 
2390             CopyBlockFromClip(nCol1, nBegRow, nCol2, nEndRow, rMark, nDx, nDy, &aCBFCP);
2391             nRowCount -= nEndRow - nBegRow + 1;
2392         }
2393 
2394         if (rClipParam.meDirection == ScClipParam::Row)
2395             // Begin row for the next range being pasted.
2396             nBegRow = rFlags.GetFirstForCondition(nEndRow+1, nLastMarkedRow, CR_FILTERED, 0);
2397         else
2398             nBegRow = nRow1;
2399 
2400         if (rClipParam.meDirection == ScClipParam::Column)
2401             nCol1 += p->aEnd.Col() - p->aStart.Col() + 1;
2402     }
2403 
2404     for (SCTAB i = 0; i <= MAXTAB; i++)
2405         if (pTab[i] && rMark.GetTableSelect(i))
2406             pTab[i]->DecRecalcLevel();
2407 
2408     bInsertingFromOtherDoc = sal_False;
2409 
2410     ScRangeList aRanges;
2411     aRanges.Append(aDestRange);
2412     SCCOL nCols = aDestRange.aEnd.Col() - aDestRange.aStart.Col() + 1;
2413     SCROW nRows = aDestRange.aEnd.Row() - aDestRange.aStart.Row() + 1;
2414     UpdateRangeNamesInFormulas(aClipRangeNames, aRanges, rMark, nCols-1, nRows-1);
2415 
2416     // Listener aufbauen nachdem alles inserted wurde
2417     StartListeningFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
2418                            aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
2419     // nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
2420     BroadcastFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
2421                       aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
2422 
2423     if (bResetCut)
2424         pClipDoc->GetClipParam().mbCutMode = false;
2425     SetAutoCalc( bOldAutoCalc );
2426 }
2427 
2428 void ScDocument::SetClipArea( const ScRange& rArea, sal_Bool bCut )
2429 {
2430     if (bIsClip)
2431     {
2432         ScClipParam& rClipParam = GetClipParam();
2433         rClipParam.maRanges.RemoveAll();
2434         rClipParam.maRanges.Append(rArea);
2435         rClipParam.mbCutMode = bCut;
2436     }
2437     else
2438     {
2439         DBG_ERROR("SetClipArea: kein Clip");
2440     }
2441 }
2442 
2443 
2444 void ScDocument::GetClipArea(SCCOL& nClipX, SCROW& nClipY, sal_Bool bIncludeFiltered)
2445 {
2446     if (!bIsClip)
2447     {
2448         DBG_ERROR("GetClipArea: kein Clip");
2449         return;
2450     }
2451 
2452     ScRangeList& rClipRanges = GetClipParam().maRanges;
2453     if (!rClipRanges.Count())
2454         // No clip range.  Bail out.
2455         return;
2456 
2457     ScRangePtr p = rClipRanges.First();
2458     SCCOL nStartCol = p->aStart.Col();
2459     SCCOL nEndCol   = p->aEnd.Col();
2460     SCROW nStartRow = p->aStart.Row();
2461     SCROW nEndRow   = p->aEnd.Row();
2462     for (p = rClipRanges.Next(); p; p = rClipRanges.Next())
2463     {
2464         if (p->aStart.Col() < nStartCol)
2465             nStartCol = p->aStart.Col();
2466         if (p->aStart.Row() < nStartRow)
2467             nStartRow = p->aStart.Row();
2468         if (p->aEnd.Col() > nEndCol)
2469             nEndCol = p->aEnd.Col();
2470         if (p->aEnd.Row() < nEndRow)
2471             nEndRow = p->aEnd.Row();
2472     }
2473 
2474     nClipX = nEndCol - nStartCol;
2475 
2476     if ( bIncludeFiltered )
2477         nClipY = nEndRow - nStartRow;
2478     else
2479     {
2480         //  count non-filtered rows
2481         //  count on first used table in clipboard
2482         SCTAB nCountTab = 0;
2483         while ( nCountTab < MAXTAB && !pTab[nCountTab] )
2484             ++nCountTab;
2485 
2486         SCROW nResult = CountNonFilteredRows(nStartRow, nEndRow, nCountTab);
2487 
2488         if ( nResult > 0 )
2489             nClipY = nResult - 1;
2490         else
2491             nClipY = 0;                 // always return at least 1 row
2492     }
2493 }
2494 
2495 
2496 void ScDocument::GetClipStart(SCCOL& nClipX, SCROW& nClipY)
2497 {
2498     if (bIsClip)
2499     {
2500         ScRangeList& rClipRanges = GetClipParam().maRanges;
2501         if (rClipRanges.Count())
2502         {
2503             nClipX = rClipRanges.First()->aStart.Col();
2504             nClipY = rClipRanges.First()->aStart.Row();
2505         }
2506     }
2507     else
2508     {
2509         DBG_ERROR("GetClipStart: kein Clip");
2510     }
2511 }
2512 
2513 
2514 sal_Bool ScDocument::HasClipFilteredRows()
2515 {
2516     //  count on first used table in clipboard
2517     SCTAB nCountTab = 0;
2518     while ( nCountTab < MAXTAB && !pTab[nCountTab] )
2519         ++nCountTab;
2520 
2521     ScRangeList& rClipRanges = GetClipParam().maRanges;
2522     if (!rClipRanges.Count())
2523         return false;
2524 
2525     for (ScRange* p = rClipRanges.First(); p; p = rClipRanges.Next())
2526     {
2527         bool bAnswer = pTab[nCountTab]->HasFilteredRows(p->aStart.Row(), p->aEnd.Row());
2528         if (bAnswer)
2529             return true;
2530     }
2531     return false;
2532 }
2533 
2534 
2535 void ScDocument::MixDocument( const ScRange& rRange, sal_uInt16 nFunction, sal_Bool bSkipEmpty,
2536                                     ScDocument* pSrcDoc )
2537 {
2538     SCTAB nTab1 = rRange.aStart.Tab();
2539     SCTAB nTab2 = rRange.aEnd.Tab();
2540     for (SCTAB i = nTab1; i <= nTab2; i++)
2541         if (pTab[i] && pSrcDoc->pTab[i])
2542             pTab[i]->MixData( rRange.aStart.Col(), rRange.aStart.Row(),
2543                                 rRange.aEnd.Col(), rRange.aEnd.Row(),
2544                                 nFunction, bSkipEmpty, pSrcDoc->pTab[i] );
2545 }
2546 
2547 
2548 void ScDocument::FillTab( const ScRange& rSrcArea, const ScMarkData& rMark,
2549                                 sal_uInt16 nFlags, sal_uInt16 nFunction,
2550                                 sal_Bool bSkipEmpty, sal_Bool bAsLink )
2551 {
2552     sal_uInt16 nDelFlags = nFlags;
2553     if (nDelFlags & IDF_CONTENTS)
2554         nDelFlags |= IDF_CONTENTS;          // immer alle Inhalte oder keine loeschen!
2555 
2556     SCTAB nSrcTab = rSrcArea.aStart.Tab();
2557 
2558     if (ValidTab(nSrcTab)  && pTab[nSrcTab])
2559     {
2560         SCCOL nStartCol = rSrcArea.aStart.Col();
2561         SCROW nStartRow = rSrcArea.aStart.Row();
2562         SCCOL nEndCol = rSrcArea.aEnd.Col();
2563         SCROW nEndRow = rSrcArea.aEnd.Row();
2564         ScDocument* pMixDoc = NULL;
2565         sal_Bool bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
2566 
2567         sal_Bool bOldAutoCalc = GetAutoCalc();
2568         SetAutoCalc( sal_False );                   // Mehrfachberechnungen vermeiden
2569 
2570         SCTAB nCount = GetTableCount();
2571         for (SCTAB i=0; i<nCount; i++)
2572             if ( i!=nSrcTab && pTab[i] && rMark.GetTableSelect(i) )
2573             {
2574                 if (bDoMix)
2575                 {
2576                     if (!pMixDoc)
2577                     {
2578                         pMixDoc = new ScDocument( SCDOCMODE_UNDO );
2579                         pMixDoc->InitUndo( this, i, i );
2580                     }
2581                     else
2582                         pMixDoc->AddUndoTab( i, i );
2583                     pTab[i]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2584                                             IDF_CONTENTS, sal_False, pMixDoc->pTab[i] );
2585                 }
2586                 pTab[i]->DeleteArea( nStartCol,nStartRow, nEndCol,nEndRow, nDelFlags);
2587                 pTab[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2588                                                  nFlags, sal_False, pTab[i], NULL, bAsLink );
2589 
2590                 if (bDoMix)
2591                     pTab[i]->MixData( nStartCol,nStartRow, nEndCol,nEndRow,
2592                                         nFunction, bSkipEmpty, pMixDoc->pTab[i] );
2593             }
2594 
2595         delete pMixDoc;
2596 
2597         SetAutoCalc( bOldAutoCalc );
2598     }
2599     else
2600     {
2601         DBG_ERROR("falsche Tabelle");
2602     }
2603 }
2604 
2605 
2606 void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
2607                                 sal_uInt16 nFlags, sal_uInt16 nFunction,
2608                                 sal_Bool bSkipEmpty, sal_Bool bAsLink )
2609 {
2610     sal_uInt16 nDelFlags = nFlags;
2611     if (nDelFlags & IDF_CONTENTS)
2612         nDelFlags |= IDF_CONTENTS;          // immer alle Inhalte oder keine loeschen!
2613 
2614     if (ValidTab(nSrcTab)  && pTab[nSrcTab])
2615     {
2616         ScDocument* pMixDoc = NULL;
2617         sal_Bool bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
2618 
2619         sal_Bool bOldAutoCalc = GetAutoCalc();
2620         SetAutoCalc( sal_False );                   // Mehrfachberechnungen vermeiden
2621 
2622         ScRange aArea;
2623         rMark.GetMultiMarkArea( aArea );
2624         SCCOL nStartCol = aArea.aStart.Col();
2625         SCROW nStartRow = aArea.aStart.Row();
2626         SCCOL nEndCol = aArea.aEnd.Col();
2627         SCROW nEndRow = aArea.aEnd.Row();
2628 
2629         SCTAB nCount = GetTableCount();
2630         for (SCTAB i=0; i<nCount; i++)
2631             if ( i!=nSrcTab && pTab[i] && rMark.GetTableSelect(i) )
2632             {
2633                 if (bDoMix)
2634                 {
2635                     if (!pMixDoc)
2636                     {
2637                         pMixDoc = new ScDocument( SCDOCMODE_UNDO );
2638                         pMixDoc->InitUndo( this, i, i );
2639                     }
2640                     else
2641                         pMixDoc->AddUndoTab( i, i );
2642                     pTab[i]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2643                                             IDF_CONTENTS, sal_True, pMixDoc->pTab[i], &rMark );
2644                 }
2645 
2646                 pTab[i]->DeleteSelection( nDelFlags, rMark );
2647                 pTab[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2648                                              nFlags, sal_True, pTab[i], &rMark, bAsLink );
2649 
2650                 if (bDoMix)
2651                     pTab[i]->MixMarked( rMark, nFunction, bSkipEmpty, pMixDoc->pTab[i] );
2652             }
2653 
2654         delete pMixDoc;
2655 
2656         SetAutoCalc( bOldAutoCalc );
2657     }
2658     else
2659     {
2660         DBG_ERROR("falsche Tabelle");
2661     }
2662 }
2663 
2664 
2665 void ScDocument::PutCell( SCCOL nCol, SCROW nRow, SCTAB nTab, ScBaseCell* pCell, sal_Bool bForceTab )
2666 {
2667     if (VALIDTAB(nTab))
2668     {
2669         if ( bForceTab && !pTab[nTab] )
2670         {
2671             sal_Bool bExtras = !bIsUndo;        // Spaltenbreiten, Zeilenhoehen, Flags
2672 
2673             pTab[nTab] = new ScTable(this, nTab,
2674                             String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("temp")),
2675                             bExtras, bExtras);
2676             ++nMaxTableNumber;
2677         }
2678 
2679         if (pTab[nTab])
2680             pTab[nTab]->PutCell( nCol, nRow, pCell );
2681     }
2682 }
2683 
2684 
2685 void ScDocument::PutCell( const ScAddress& rPos, ScBaseCell* pCell, sal_Bool bForceTab )
2686 {
2687     SCTAB nTab = rPos.Tab();
2688     if ( bForceTab && !pTab[nTab] )
2689     {
2690         sal_Bool bExtras = !bIsUndo;        // Spaltenbreiten, Zeilenhoehen, Flags
2691 
2692         pTab[nTab] = new ScTable(this, nTab,
2693                         String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("temp")),
2694                         bExtras, bExtras);
2695         ++nMaxTableNumber;
2696     }
2697 
2698     if (pTab[nTab])
2699         pTab[nTab]->PutCell( rPos, pCell );
2700 }
2701 
2702 
2703 sal_Bool ScDocument::SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rString,
2704                             SvNumberFormatter* pFormatter, bool bDetectNumberFormat )
2705 {
2706     if ( ValidTab(nTab) && pTab[nTab] )
2707         return pTab[nTab]->SetString( nCol, nRow, nTab, rString, pFormatter, bDetectNumberFormat );
2708     else
2709         return sal_False;
2710 }
2711 
2712 
2713 void ScDocument::SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal )
2714 {
2715     if (VALIDTAB(nTab))
2716         if (pTab[nTab])
2717             pTab[nTab]->SetValue( nCol, nRow, rVal );
2718 }
2719 
2720 
2721 void ScDocument::GetString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString )
2722 {
2723     if ( VALIDTAB(nTab) && pTab[nTab] )
2724         pTab[nTab]->GetString( nCol, nRow, rString );
2725     else
2726         rString.Erase();
2727 }
2728 
2729 void ScDocument::FillDPCache( ScDPTableDataCache * pCache, SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow )
2730 {
2731     if ( VALIDTAB(nTab) && pTab[nTab] )
2732         pTab[nTab]->FillDPCache( pCache, nStartCol, nEndCol, nStartRow, nEndRow );
2733 }
2734 
2735 void ScDocument::GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString )
2736 {
2737     if ( VALIDTAB(nTab) && pTab[nTab] )
2738         pTab[nTab]->GetInputString( nCol, nRow, rString );
2739     else
2740         rString.Erase();
2741 }
2742 
2743 
2744 sal_uInt16 ScDocument::GetStringForFormula( const ScAddress& rPos, rtl::OUString& rString )
2745 {
2746     // Used in formulas (add-in parameters etc), so it must use the same semantics as
2747     // ScInterpreter::GetCellString: always format values as numbers.
2748     // The return value is the error code.
2749 
2750     sal_uInt16 nErr = 0;
2751     String aStr;
2752     ScBaseCell* pCell = GetCell( rPos );
2753     if (pCell)
2754     {
2755         SvNumberFormatter* pFormatter = GetFormatTable();
2756         switch (pCell->GetCellType())
2757         {
2758             case CELLTYPE_STRING:
2759                 static_cast<ScStringCell*>(pCell)->GetString(aStr);
2760             break;
2761             case CELLTYPE_EDIT:
2762                 static_cast<ScEditCell*>(pCell)->GetString(aStr);
2763             break;
2764             case CELLTYPE_FORMULA:
2765             {
2766                 ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
2767                 nErr = pFCell->GetErrCode();
2768                 if (pFCell->IsValue())
2769                 {
2770                     double fVal = pFCell->GetValue();
2771                     sal_uInt32 nIndex = pFormatter->GetStandardFormat(
2772                                         NUMBERFORMAT_NUMBER,
2773                                         ScGlobal::eLnge);
2774                     pFormatter->GetInputLineString(fVal, nIndex, aStr);
2775                 }
2776                 else
2777                     pFCell->GetString(aStr);
2778             }
2779             break;
2780             case CELLTYPE_VALUE:
2781             {
2782                 double fVal = static_cast<ScValueCell*>(pCell)->GetValue();
2783                 sal_uInt32 nIndex = pFormatter->GetStandardFormat(
2784                                         NUMBERFORMAT_NUMBER,
2785                                         ScGlobal::eLnge);
2786                 pFormatter->GetInputLineString(fVal, nIndex, aStr);
2787             }
2788             break;
2789             default:
2790                 ;
2791         }
2792     }
2793     rString = aStr;
2794     return nErr;
2795 }
2796 
2797 
2798 void ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, double& rValue )
2799 {
2800     if ( VALIDTAB(nTab) && pTab[nTab] )
2801         rValue = pTab[nTab]->GetValue( nCol, nRow );
2802     else
2803         rValue = 0.0;
2804 }
2805 
2806 
2807 double ScDocument::GetValue( const ScAddress& rPos )
2808 {
2809     SCTAB nTab = rPos.Tab();
2810     if ( pTab[nTab] )
2811         return pTab[nTab]->GetValue( rPos );
2812     return 0.0;
2813 }
2814 
2815 
2816 void ScDocument::GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab,
2817                                   sal_uInt32& rFormat )
2818 {
2819     if (VALIDTAB(nTab))
2820         if (pTab[nTab])
2821         {
2822             rFormat = pTab[nTab]->GetNumberFormat( nCol, nRow );
2823             return ;
2824         }
2825     rFormat = 0;
2826 }
2827 
2828 
2829 sal_uInt32 ScDocument::GetNumberFormat( const ScAddress& rPos ) const
2830 {
2831     SCTAB nTab = rPos.Tab();
2832     if ( pTab[nTab] )
2833         return pTab[nTab]->GetNumberFormat( rPos );
2834     return 0;
2835 }
2836 
2837 
2838 void ScDocument::GetNumberFormatInfo( short& nType, sal_uLong& nIndex,
2839             const ScAddress& rPos, const ScBaseCell* pCell ) const
2840 {
2841     SCTAB nTab = rPos.Tab();
2842     if ( pTab[nTab] )
2843     {
2844         nIndex = pTab[nTab]->GetNumberFormat( rPos );
2845         if ( (nIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && pCell &&
2846                 pCell->GetCellType() == CELLTYPE_FORMULA )
2847             static_cast<const ScFormulaCell*>(pCell)->GetFormatInfo( nType, nIndex );
2848         else
2849             nType = GetFormatTable()->GetType( nIndex );
2850     }
2851     else
2852     {
2853         nType = NUMBERFORMAT_UNDEFINED;
2854         nIndex = 0;
2855     }
2856 }
2857 
2858 
2859 void ScDocument::GetFormula( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rFormula,
2860                              sal_Bool bAsciiExport ) const
2861 {
2862     if ( VALIDTAB(nTab) && pTab[nTab] )
2863             pTab[nTab]->GetFormula( nCol, nRow, rFormula, bAsciiExport );
2864     else
2865         rFormula.Erase();
2866 }
2867 
2868 
2869 CellType ScDocument::GetCellType( const ScAddress& rPos ) const
2870 {
2871     SCTAB nTab = rPos.Tab();
2872     if ( pTab[nTab] )
2873         return pTab[nTab]->GetCellType( rPos );
2874     return CELLTYPE_NONE;
2875 }
2876 
2877 
2878 void ScDocument::GetCellType( SCCOL nCol, SCROW nRow, SCTAB nTab,
2879         CellType& rCellType ) const
2880 {
2881     if (ValidTab(nTab) && pTab[nTab])
2882         rCellType = pTab[nTab]->GetCellType( nCol, nRow );
2883     else
2884         rCellType = CELLTYPE_NONE;
2885 }
2886 
2887 
2888 void ScDocument::GetCell( SCCOL nCol, SCROW nRow, SCTAB nTab,
2889         ScBaseCell*& rpCell ) const
2890 {
2891     if (ValidTab(nTab) && pTab[nTab])
2892         rpCell = pTab[nTab]->GetCell( nCol, nRow );
2893     else
2894     {
2895         DBG_ERROR("GetCell ohne Tabelle");
2896         rpCell = NULL;
2897     }
2898 }
2899 
2900 
2901 ScBaseCell* ScDocument::GetCell( const ScAddress& rPos ) const
2902 {
2903     SCTAB nTab = rPos.Tab();
2904     if (ValidTab(nTab) && pTab[nTab])
2905         return pTab[nTab]->GetCell( rPos );
2906 
2907     DBG_ERROR("GetCell ohne Tabelle");
2908     return NULL;
2909 }
2910 
2911 
2912 sal_Bool ScDocument::HasStringData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
2913 {
2914     if ( VALIDTAB(nTab) && pTab[nTab] )
2915             return pTab[nTab]->HasStringData( nCol, nRow );
2916     else
2917         return sal_False;
2918 }
2919 
2920 
2921 sal_Bool ScDocument::HasValueData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
2922 {
2923     if ( VALIDTAB(nTab) && pTab[nTab] )
2924             return pTab[nTab]->HasValueData( nCol, nRow );
2925     else
2926         return sal_False;
2927 }
2928 
2929 
2930 sal_Bool ScDocument::HasStringCells( const ScRange& rRange ) const
2931 {
2932     //  sal_True, wenn String- oder Editzellen im Bereich
2933 
2934     SCCOL nStartCol = rRange.aStart.Col();
2935     SCROW nStartRow = rRange.aStart.Row();
2936     SCTAB nStartTab = rRange.aStart.Tab();
2937     SCCOL nEndCol = rRange.aEnd.Col();
2938     SCROW nEndRow = rRange.aEnd.Row();
2939     SCTAB nEndTab = rRange.aEnd.Tab();
2940 
2941     for ( SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++ )
2942         if ( pTab[nTab] && pTab[nTab]->HasStringCells( nStartCol, nStartRow, nEndCol, nEndRow ) )
2943             return sal_True;
2944 
2945     return sal_False;
2946 }
2947 
2948 
2949 sal_Bool ScDocument::HasSelectionData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
2950 {
2951     sal_uInt32 nValidation = static_cast< const SfxUInt32Item* >( GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA ) )->GetValue();
2952     if( nValidation )
2953     {
2954         const ScValidationData* pData = GetValidationEntry( nValidation );
2955         if( pData && pData->HasSelectionList() )
2956             return sal_True;
2957     }
2958     return HasStringCells( ScRange( nCol, 0, nTab, nCol, MAXROW, nTab ) );
2959 }
2960 
2961 
2962 ScPostIt* ScDocument::GetNote( const ScAddress& rPos )
2963 {
2964     ScTable* pTable = ValidTab( rPos.Tab() ) ? pTab[ rPos.Tab() ] : 0;
2965     return pTable ? pTable->GetNote( rPos.Col(), rPos.Row() ) : 0;
2966 }
2967 
2968 
2969 void ScDocument::TakeNote( const ScAddress& rPos, ScPostIt*& rpNote )
2970 {
2971     if( ValidTab( rPos.Tab() ) && pTab[ rPos.Tab() ] )
2972         pTab[ rPos.Tab() ]->TakeNote( rPos.Col(), rPos.Row(), rpNote );
2973     else
2974         DELETEZ( rpNote );
2975 }
2976 
2977 
2978 ScPostIt* ScDocument::ReleaseNote( const ScAddress& rPos )
2979 {
2980     ScTable* pTable = ValidTab( rPos.Tab() ) ? pTab[ rPos.Tab() ] : 0;
2981     return pTable ? pTable->ReleaseNote( rPos.Col(), rPos.Row() ) : 0;
2982 }
2983 
2984 
2985 ScPostIt* ScDocument::GetOrCreateNote( const ScAddress& rPos )
2986 {
2987     ScPostIt* pNote = GetNote( rPos );
2988     if( !pNote )
2989     {
2990         pNote = new ScPostIt( *this, rPos, false );
2991         TakeNote( rPos, pNote );
2992     }
2993     return pNote;
2994 }
2995 
2996 
2997 void ScDocument::DeleteNote( const ScAddress& rPos )
2998 {
2999     if( ValidTab( rPos.Tab() ) && pTab[ rPos.Tab() ] )
3000         pTab[ rPos.Tab() ]->DeleteNote( rPos.Col(), rPos.Row() );
3001 }
3002 
3003 
3004 void ScDocument::InitializeNoteCaptions( SCTAB nTab, bool bForced )
3005 {
3006     if( ValidTab( nTab ) && pTab[ nTab ] )
3007         pTab[ nTab ]->InitializeNoteCaptions( bForced );
3008 }
3009 
3010 void ScDocument::InitializeAllNoteCaptions( bool bForced )
3011 {
3012     for( SCTAB nTab = 0; nTab < GetTableCount(); ++nTab )
3013         InitializeNoteCaptions( nTab, bForced );
3014 }
3015 
3016 void ScDocument::SetDirty()
3017 {
3018     sal_Bool bOldAutoCalc = GetAutoCalc();
3019     bAutoCalc = sal_False;      // keine Mehrfachberechnung
3020     {   // scope for bulk broadcast
3021         ScBulkBroadcast aBulkBroadcast( GetBASM());
3022         for (SCTAB i=0; i<=MAXTAB; i++)
3023             if (pTab[i]) pTab[i]->SetDirty();
3024     }
3025 
3026     //  Charts werden zwar auch ohne AutoCalc im Tracking auf Dirty gesetzt,
3027     //  wenn alle Formeln dirty sind, werden die Charts aber nicht mehr erwischt
3028     //  (#45205#) - darum alle Charts nochmal explizit
3029     if (pChartListenerCollection)
3030         pChartListenerCollection->SetDirty();
3031 
3032     SetAutoCalc( bOldAutoCalc );
3033 }
3034 
3035 
3036 void ScDocument::SetDirty( const ScRange& rRange )
3037 {
3038     sal_Bool bOldAutoCalc = GetAutoCalc();
3039     bAutoCalc = sal_False;      // keine Mehrfachberechnung
3040     {   // scope for bulk broadcast
3041         ScBulkBroadcast aBulkBroadcast( GetBASM());
3042         SCTAB nTab2 = rRange.aEnd.Tab();
3043         for (SCTAB i=rRange.aStart.Tab(); i<=nTab2; i++)
3044             if (pTab[i]) pTab[i]->SetDirty( rRange );
3045     }
3046     SetAutoCalc( bOldAutoCalc );
3047 }
3048 
3049 
3050 void ScDocument::SetTableOpDirty( const ScRange& rRange )
3051 {
3052     sal_Bool bOldAutoCalc = GetAutoCalc();
3053     bAutoCalc = sal_False;      // no multiple recalculation
3054     SCTAB nTab2 = rRange.aEnd.Tab();
3055     for (SCTAB i=rRange.aStart.Tab(); i<=nTab2; i++)
3056         if (pTab[i]) pTab[i]->SetTableOpDirty( rRange );
3057     SetAutoCalc( bOldAutoCalc );
3058 }
3059 
3060 
3061 void ScDocument::InterpretDirtyCells( const ScRangeList& rRanges )
3062 {
3063     sal_uLong nRangeCount = rRanges.Count();
3064     for (sal_uLong nPos=0; nPos<nRangeCount; nPos++)
3065     {
3066         ScCellIterator aIter( this, *rRanges.GetObject(nPos) );
3067         ScBaseCell* pCell = aIter.GetFirst();
3068         while (pCell)
3069         {
3070             if (pCell->GetCellType() == CELLTYPE_FORMULA)
3071             {
3072                 if ( static_cast<ScFormulaCell*>(pCell)->GetDirty() && GetAutoCalc() )
3073                     static_cast<ScFormulaCell*>(pCell)->Interpret();
3074             }
3075             pCell = aIter.GetNext();
3076         }
3077     }
3078 }
3079 
3080 
3081 void ScDocument::AddTableOpFormulaCell( ScFormulaCell* pCell )
3082 {
3083     ScInterpreterTableOpParams* p = aTableOpList.Last();
3084     if ( p && p->bCollectNotifications )
3085     {
3086         if ( p->bRefresh )
3087         {   // refresh pointers only
3088             p->aNotifiedFormulaCells.push_back( pCell );
3089         }
3090         else
3091         {   // init both, address and pointer
3092             p->aNotifiedFormulaCells.push_back( pCell );
3093             p->aNotifiedFormulaPos.push_back( pCell->aPos );
3094         }
3095     }
3096 }
3097 
3098 
3099 void ScDocument::CalcAll()
3100 {
3101     ClearLookupCaches();    // Ensure we don't deliver zombie data.
3102     sal_Bool bOldAutoCalc = GetAutoCalc();
3103     SetAutoCalc( sal_True );
3104     SCTAB i;
3105     for (i=0; i<=MAXTAB; i++)
3106         if (pTab[i]) pTab[i]->SetDirtyVar();
3107     for (i=0; i<=MAXTAB; i++)
3108         if (pTab[i]) pTab[i]->CalcAll();
3109     ClearFormulaTree();
3110     SetAutoCalc( bOldAutoCalc );
3111 }
3112 
3113 
3114 void ScDocument::CompileAll()
3115 {
3116     if ( pCondFormList )
3117         pCondFormList->CompileAll();
3118 
3119     for (SCTAB i=0; i<=MAXTAB; i++)
3120         if (pTab[i]) pTab[i]->CompileAll();
3121     SetDirty();
3122 }
3123 
3124 
3125 void ScDocument::CompileXML()
3126 {
3127     sal_Bool bOldAutoCalc = GetAutoCalc();
3128     SetAutoCalc( sal_False );
3129     ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(
3130                 STR_PROGRESS_CALCULATING ), GetXMLImportedFormulaCount() );
3131 
3132     // #b6355215# set AutoNameCache to speed up automatic name lookup
3133     DBG_ASSERT( !pAutoNameCache, "AutoNameCache already set" );
3134     pAutoNameCache = new ScAutoNameCache( this );
3135 
3136     for (SCTAB i=0; i<=MAXTAB; i++)
3137         if (pTab[i]) pTab[i]->CompileXML( aProgress );
3138 
3139     DELETEZ( pAutoNameCache );  // valid only during CompileXML, where cell contents don't change
3140 
3141     if ( pCondFormList )
3142         pCondFormList->CompileXML();
3143     if ( pValidationList )
3144         pValidationList->CompileXML();
3145 
3146     SetDirty();
3147     SetAutoCalc( bOldAutoCalc );
3148 }
3149 
3150 
3151 void ScDocument::CalcAfterLoad()
3152 {
3153     SCTAB i;
3154 
3155     if (bIsClip)    // Excel-Dateien werden aus dem Clipboard in ein Clip-Doc geladen
3156         return;     // dann wird erst beim Einfuegen in das richtige Doc berechnet
3157 
3158     bCalcingAfterLoad = sal_True;
3159     for ( i = 0; i <= MAXTAB; i++)
3160         if (pTab[i]) pTab[i]->CalcAfterLoad();
3161     for (i=0; i<=MAXTAB; i++)
3162         if (pTab[i]) pTab[i]->SetDirtyAfterLoad();
3163     bCalcingAfterLoad = sal_False;
3164 
3165     SetDetectiveDirty(sal_False);   // noch keine wirklichen Aenderungen
3166 
3167     // #i112436# If formula cells are already dirty, they don't broadcast further changes.
3168     // So the source ranges of charts must be interpreted even if they are not visible,
3169     // similar to ScMyShapeResizer::CreateChartListener for loading own files (i104899).
3170     if (pChartListenerCollection)
3171     {
3172         sal_uInt16 nChartCount = pChartListenerCollection->GetCount();
3173         for ( sal_uInt16 nIndex = 0; nIndex < nChartCount; nIndex++ )
3174         {
3175             ScChartListener* pChartListener = static_cast<ScChartListener*>(pChartListenerCollection->At(nIndex));
3176             InterpretDirtyCells(*pChartListener->GetRangeList());
3177         }
3178     }
3179 }
3180 
3181 
3182 sal_uInt16 ScDocument::GetErrCode( const ScAddress& rPos ) const
3183 {
3184     SCTAB nTab = rPos.Tab();
3185     if ( pTab[nTab] )
3186         return pTab[nTab]->GetErrCode( rPos );
3187     return 0;
3188 }
3189 
3190 
3191 void ScDocument::ResetChanged( const ScRange& rRange )
3192 {
3193     SCTAB nStartTab = rRange.aStart.Tab();
3194     SCTAB nEndTab = rRange.aEnd.Tab();
3195     for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
3196         if (pTab[nTab])
3197             pTab[nTab]->ResetChanged( rRange );
3198 }
3199 
3200 //
3201 //  Spaltenbreiten / Zeilenhoehen   --------------------------------------
3202 //
3203 
3204 
3205 void ScDocument::SetColWidth( SCCOL nCol, SCTAB nTab, sal_uInt16 nNewWidth )
3206 {
3207     if ( ValidTab(nTab) && pTab[nTab] )
3208         pTab[nTab]->SetColWidth( nCol, nNewWidth );
3209 }
3210 
3211 void ScDocument::SetColWidthOnly( SCCOL nCol, SCTAB nTab, sal_uInt16 nNewWidth )
3212 {
3213     if ( ValidTab(nTab) && pTab[nTab] )
3214         pTab[nTab]->SetColWidthOnly( nCol, nNewWidth );
3215 }
3216 
3217 void ScDocument::SetRowHeight( SCROW nRow, SCTAB nTab, sal_uInt16 nNewHeight )
3218 {
3219     if ( ValidTab(nTab) && pTab[nTab] )
3220         pTab[nTab]->SetRowHeight( nRow, nNewHeight );
3221 }
3222 
3223 
3224 void ScDocument::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
3225 {
3226     if ( ValidTab(nTab) && pTab[nTab] )
3227         pTab[nTab]->SetRowHeightRange
3228             ( nStartRow, nEndRow, nNewHeight, 1.0, 1.0 );
3229 }
3230 
3231 void ScDocument::SetRowHeightOnly( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
3232 {
3233     if ( ValidTab(nTab) && pTab[nTab] )
3234         pTab[nTab]->SetRowHeightOnly( nStartRow, nEndRow, nNewHeight );
3235 }
3236 
3237 void ScDocument::SetManualHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_Bool bManual )
3238 {
3239     if ( ValidTab(nTab) && pTab[nTab] )
3240         pTab[nTab]->SetManualHeight( nStartRow, nEndRow, bManual );
3241 }
3242 
3243 
3244 sal_uInt16 ScDocument::GetColWidth( SCCOL nCol, SCTAB nTab ) const
3245 {
3246     if ( ValidTab(nTab) && pTab[nTab] )
3247         return pTab[nTab]->GetColWidth( nCol );
3248     DBG_ERROR("Falsche Tabellennummer");
3249     return 0;
3250 }
3251 
3252 
3253 sal_uInt16 ScDocument::GetOriginalWidth( SCCOL nCol, SCTAB nTab ) const
3254 {
3255     if ( ValidTab(nTab) && pTab[nTab] )
3256         return pTab[nTab]->GetOriginalWidth( nCol );
3257     DBG_ERROR("Falsche Tabellennummer");
3258     return 0;
3259 }
3260 
3261 
3262 sal_uInt16 ScDocument::GetCommonWidth( SCCOL nEndCol, SCTAB nTab ) const
3263 {
3264     if ( ValidTab(nTab) && pTab[nTab] )
3265         return pTab[nTab]->GetCommonWidth( nEndCol );
3266     DBG_ERROR("Wrong table number");
3267     return 0;
3268 }
3269 
3270 
3271 sal_uInt16 ScDocument::GetOriginalHeight( SCROW nRow, SCTAB nTab ) const
3272 {
3273     if ( ValidTab(nTab) && pTab[nTab] )
3274         return pTab[nTab]->GetOriginalHeight( nRow );
3275     DBG_ERROR("Wrong table number");
3276     return 0;
3277 }
3278 
3279 
3280 sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, bool bHiddenAsZero ) const
3281 {
3282     if ( ValidTab(nTab) && pTab[nTab] )
3283         return pTab[nTab]->GetRowHeight( nRow, NULL, NULL, bHiddenAsZero );
3284     DBG_ERROR("Wrong sheet number");
3285     return 0;
3286 }
3287 
3288 
3289 sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, SCROW* pStartRow, SCROW* pEndRow, bool bHiddenAsZero ) const
3290 {
3291     if ( ValidTab(nTab) && pTab[nTab] )
3292         return pTab[nTab]->GetRowHeight( nRow, pStartRow, pEndRow, bHiddenAsZero );
3293     DBG_ERROR("Wrong sheet number");
3294     return 0;
3295 }
3296 
3297 
3298 sal_uLong ScDocument::GetRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
3299 {
3300     if (nStartRow == nEndRow)
3301         return GetRowHeight( nStartRow, nTab);  // faster for a single row
3302 
3303     // check bounds because this method replaces former for(i=start;i<=end;++i) loops
3304     if (nStartRow > nEndRow)
3305         return 0;
3306 
3307     if ( ValidTab(nTab) && pTab[nTab] )
3308         return pTab[nTab]->GetRowHeight( nStartRow, nEndRow);
3309 
3310     DBG_ERROR("wrong sheet number");
3311     return 0;
3312 }
3313 
3314 SCROW ScDocument::GetRowForHeight( SCTAB nTab, sal_uLong nHeight ) const
3315 {
3316     return pTab[nTab]->GetRowForHeight(nHeight);
3317 }
3318 
3319 sal_uLong ScDocument::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow,
3320         SCTAB nTab, double fScale ) const
3321 {
3322     // faster for a single row
3323     if (nStartRow == nEndRow)
3324         return (sal_uLong) (GetRowHeight( nStartRow, nTab) * fScale);
3325 
3326     // check bounds because this method replaces former for(i=start;i<=end;++i) loops
3327     if (nStartRow > nEndRow)
3328         return 0;
3329 
3330     if ( ValidTab(nTab) && pTab[nTab] )
3331         return pTab[nTab]->GetScaledRowHeight( nStartRow, nEndRow, fScale);
3332 
3333     DBG_ERROR("wrong sheet number");
3334     return 0;
3335 }
3336 
3337 SCROW ScDocument::GetHiddenRowCount( SCROW nRow, SCTAB nTab ) const
3338 {
3339     if ( ValidTab(nTab) && pTab[nTab] )
3340         return pTab[nTab]->GetHiddenRowCount( nRow );
3341     DBG_ERROR("Falsche Tabellennummer");
3342     return 0;
3343 }
3344 
3345 
3346 sal_uLong ScDocument::GetColOffset( SCCOL nCol, SCTAB nTab ) const
3347 {
3348     if ( ValidTab(nTab) && pTab[nTab] )
3349         return pTab[nTab]->GetColOffset( nCol );
3350     DBG_ERROR("Falsche Tabellennummer");
3351     return 0;
3352 }
3353 
3354 
3355 sal_uLong ScDocument::GetRowOffset( SCROW nRow, SCTAB nTab ) const
3356 {
3357     if ( ValidTab(nTab) && pTab[nTab] )
3358         return pTab[nTab]->GetRowOffset( nRow );
3359     DBG_ERROR("Falsche Tabellennummer");
3360     return 0;
3361 }
3362 
3363 
3364 sal_uInt16 ScDocument::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, OutputDevice* pDev,
3365                                         double nPPTX, double nPPTY,
3366                                         const Fraction& rZoomX, const Fraction& rZoomY,
3367                                         sal_Bool bFormula, const ScMarkData* pMarkData,
3368                                         sal_Bool bSimpleTextImport )
3369 {
3370     if ( ValidTab(nTab) && pTab[nTab] )
3371         return pTab[nTab]->GetOptimalColWidth( nCol, pDev, nPPTX, nPPTY,
3372             rZoomX, rZoomY, bFormula, pMarkData, bSimpleTextImport );
3373     DBG_ERROR("Falsche Tabellennummer");
3374     return 0;
3375 }
3376 
3377 
3378 long ScDocument::GetNeededSize( SCCOL nCol, SCROW nRow, SCTAB nTab,
3379                                     OutputDevice* pDev,
3380                                     double nPPTX, double nPPTY,
3381                                     const Fraction& rZoomX, const Fraction& rZoomY,
3382                                     sal_Bool bWidth, sal_Bool bTotalSize )
3383 {
3384     if ( ValidTab(nTab) && pTab[nTab] )
3385         return pTab[nTab]->GetNeededSize
3386                 ( nCol, nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, bTotalSize );
3387     DBG_ERROR("Falsche Tabellennummer");
3388     return 0;
3389 }
3390 
3391 
3392 sal_Bool ScDocument::SetOptimalHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nExtra,
3393                                     OutputDevice* pDev,
3394                                     double nPPTX, double nPPTY,
3395                                     const Fraction& rZoomX, const Fraction& rZoomY,
3396                                     sal_Bool bShrink )
3397 {
3398 //! MarkToMulti();
3399     if ( ValidTab(nTab) && pTab[nTab] )
3400         return pTab[nTab]->SetOptimalHeight( nStartRow, nEndRow, nExtra,
3401                                                 pDev, nPPTX, nPPTY, rZoomX, rZoomY, bShrink );
3402     DBG_ERROR("Falsche Tabellennummer");
3403     return sal_False;
3404 }
3405 
3406 
3407 void ScDocument::UpdateAllRowHeights( OutputDevice* pDev, double nPPTX, double nPPTY,
3408                                     const Fraction& rZoomX, const Fraction& rZoomY, const ScMarkData* pTabMark )
3409 {
3410     // one progress across all (selected) sheets
3411 
3412     sal_uLong nCellCount = 0;
3413     for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
3414         if ( pTab[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
3415             nCellCount += pTab[nTab]->GetWeightedCount();
3416 
3417     ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), nCellCount );
3418 
3419     sal_uLong nProgressStart = 0;
3420     for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
3421         if ( pTab[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
3422         {
3423             pTab[nTab]->SetOptimalHeight( 0, MAXROW, 0,
3424                         pDev, nPPTX, nPPTY, rZoomX, rZoomY, sal_False, &aProgress, nProgressStart );
3425             nProgressStart += pTab[nTab]->GetWeightedCount();
3426         }
3427 }
3428 
3429 
3430 //
3431 //  Spalten-/Zeilen-Flags   ----------------------------------------------
3432 //
3433 
3434 void ScDocument::ShowCol(SCCOL nCol, SCTAB nTab, sal_Bool bShow)
3435 {
3436     if ( ValidTab(nTab) && pTab[nTab] )
3437         pTab[nTab]->ShowCol( nCol, bShow );
3438 }
3439 
3440 
3441 void ScDocument::ShowRow(SCROW nRow, SCTAB nTab, sal_Bool bShow)
3442 {
3443     if ( ValidTab(nTab) && pTab[nTab] )
3444         pTab[nTab]->ShowRow( nRow, bShow );
3445 }
3446 
3447 
3448 void ScDocument::ShowRows(SCROW nRow1, SCROW nRow2, SCTAB nTab, sal_Bool bShow)
3449 {
3450     if ( ValidTab(nTab) && pTab[nTab] )
3451         pTab[nTab]->ShowRows( nRow1, nRow2, bShow );
3452 }
3453 
3454 
3455 void ScDocument::SetColFlags( SCCOL nCol, SCTAB nTab, sal_uInt8 nNewFlags )
3456 {
3457     if ( ValidTab(nTab) && pTab[nTab] )
3458         pTab[nTab]->SetColFlags( nCol, nNewFlags );
3459 }
3460 
3461 
3462 void ScDocument::SetRowFlags( SCROW nRow, SCTAB nTab, sal_uInt8 nNewFlags )
3463 {
3464     if ( ValidTab(nTab) && pTab[nTab] )
3465         pTab[nTab]->SetRowFlags( nRow, nNewFlags );
3466 }
3467 
3468 
3469 void ScDocument::SetRowFlags( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt8 nNewFlags )
3470 {
3471     if ( ValidTab(nTab) && pTab[nTab] )
3472         pTab[nTab]->SetRowFlags( nStartRow, nEndRow, nNewFlags );
3473 }
3474 
3475 
3476 sal_uInt8 ScDocument::GetColFlags( SCCOL nCol, SCTAB nTab ) const
3477 {
3478     if ( ValidTab(nTab) && pTab[nTab] )
3479         return pTab[nTab]->GetColFlags( nCol );
3480     DBG_ERROR("Falsche Tabellennummer");
3481     return 0;
3482 }
3483 
3484 sal_uInt8 ScDocument::GetRowFlags( SCROW nRow, SCTAB nTab ) const
3485 {
3486     if ( ValidTab(nTab) && pTab[nTab] )
3487         return pTab[nTab]->GetRowFlags( nRow );
3488     DBG_ERROR("Falsche Tabellennummer");
3489     return 0;
3490 }
3491 
3492 ScBitMaskCompressedArray< SCROW, sal_uInt8> & ScDocument::GetRowFlagsArrayModifiable(
3493         SCTAB nTab )
3494 {
3495     return const_cast< ScBitMaskCompressedArray< SCROW, sal_uInt8> & >(
3496             GetRowFlagsArray( nTab));
3497 }
3498 
3499 const ScBitMaskCompressedArray< SCROW, sal_uInt8> & ScDocument::GetRowFlagsArray(
3500         SCTAB nTab ) const
3501 {
3502     const ScBitMaskCompressedArray< SCROW, sal_uInt8> * pFlags;
3503     if ( ValidTab(nTab) && pTab[nTab] )
3504         pFlags = pTab[nTab]->GetRowFlagsArray();
3505     else
3506     {
3507         DBG_ERROR("wrong sheet number");
3508         pFlags = 0;
3509     }
3510     if (!pFlags)
3511     {
3512         DBG_ERROR("no row flags at sheet");
3513         static ScBitMaskCompressedArray< SCROW, sal_uInt8> aDummy( MAXROW, 0);
3514         pFlags = &aDummy;
3515     }
3516     return *pFlags;
3517 }
3518 
3519 void ScDocument::GetAllRowBreaks(set<SCROW>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
3520 {
3521     if (!ValidTab(nTab) || !pTab[nTab])
3522         return;
3523 
3524     pTab[nTab]->GetAllRowBreaks(rBreaks, bPage, bManual);
3525 }
3526 
3527 void ScDocument::GetAllColBreaks(set<SCCOL>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
3528 {
3529     if (!ValidTab(nTab) || !pTab[nTab])
3530         return;
3531 
3532     pTab[nTab]->GetAllColBreaks(rBreaks, bPage, bManual);
3533 }
3534 
3535 ScBreakType ScDocument::HasRowBreak(SCROW nRow, SCTAB nTab) const
3536 {
3537     ScBreakType nType = BREAK_NONE;
3538     if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
3539         return nType;
3540 
3541     if (pTab[nTab]->HasRowPageBreak(nRow))
3542         nType |= BREAK_PAGE;
3543 
3544     if (pTab[nTab]->HasRowManualBreak(nRow))
3545         nType |= BREAK_MANUAL;
3546 
3547     return nType;
3548 }
3549 
3550 ScBreakType ScDocument::HasColBreak(SCCOL nCol, SCTAB nTab) const
3551 {
3552     ScBreakType nType = BREAK_NONE;
3553     if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
3554         return nType;
3555 
3556     if (pTab[nTab]->HasColPageBreak(nCol))
3557         nType |= BREAK_PAGE;
3558 
3559     if (pTab[nTab]->HasColManualBreak(nCol))
3560         nType |= BREAK_MANUAL;
3561 
3562     return nType;
3563 }
3564 
3565 void ScDocument::SetRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
3566 {
3567     if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
3568         return;
3569 
3570     pTab[nTab]->SetRowBreak(nRow, bPage, bManual);
3571 }
3572 
3573 void ScDocument::SetColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
3574 {
3575     if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
3576         return;
3577 
3578     pTab[nTab]->SetColBreak(nCol, bPage, bManual);
3579 }
3580 
3581 void ScDocument::RemoveRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
3582 {
3583     if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
3584         return;
3585 
3586     pTab[nTab]->RemoveRowBreak(nRow, bPage, bManual);
3587 }
3588 
3589 void ScDocument::RemoveColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
3590 {
3591     if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
3592         return;
3593 
3594     pTab[nTab]->RemoveColBreak(nCol, bPage, bManual);
3595 }
3596 
3597 Sequence<TablePageBreakData> ScDocument::GetRowBreakData(SCTAB nTab) const
3598 {
3599     if (!ValidTab(nTab) || !pTab[nTab])
3600         return Sequence<TablePageBreakData>();
3601 
3602     return pTab[nTab]->GetRowBreakData();
3603 }
3604 
3605 bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow)
3606 {
3607     if (!ValidTab(nTab) || !pTab[nTab])
3608         return false;
3609 
3610     return pTab[nTab]->RowHidden(nRow, pFirstRow, pLastRow);
3611 }
3612 
3613 bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW& rLastRow)
3614 {
3615     if (!ValidTab(nTab) || !pTab[nTab])
3616     {
3617         rLastRow = nRow;
3618         return false;
3619     }
3620 
3621     return pTab[nTab]->RowHidden(nRow, rLastRow);
3622 }
3623 
3624 
3625 bool ScDocument::HasHiddenRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3626 {
3627     if (!ValidTab(nTab) || !pTab[nTab])
3628         return false;
3629 
3630     return pTab[nTab]->HasHiddenRows(nStartRow, nEndRow);
3631 }
3632 
3633 bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL& rLastCol)
3634 {
3635     if (!ValidTab(nTab) || !pTab[nTab])
3636     {
3637         rLastCol = nCol;
3638         return false;
3639     }
3640 
3641     return pTab[nTab]->ColHidden(nCol, rLastCol);
3642 }
3643 
3644 bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol)
3645 {
3646     if (!ValidTab(nTab) || !pTab[nTab])
3647     {
3648         if (pFirstCol)
3649             *pFirstCol = nCol;
3650         if (pLastCol)
3651             *pLastCol = nCol;
3652         return false;
3653     }
3654 
3655     return pTab[nTab]->ColHidden(nCol, pFirstCol, pLastCol);
3656 }
3657 
3658 void ScDocument::SetRowHidden(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHidden)
3659 {
3660     if (!ValidTab(nTab) || !pTab[nTab])
3661         return;
3662 
3663     pTab[nTab]->SetRowHidden(nStartRow, nEndRow, bHidden);
3664 }
3665 
3666 void ScDocument::SetColHidden(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bHidden)
3667 {
3668     if (!ValidTab(nTab) || !pTab[nTab])
3669         return;
3670 
3671     pTab[nTab]->SetColHidden(nStartCol, nEndCol, bHidden);
3672 }
3673 
3674 SCROW ScDocument::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3675 {
3676     if (!ValidTab(nTab) || !pTab[nTab])
3677         return ::std::numeric_limits<SCROW>::max();;
3678 
3679     return pTab[nTab]->FirstVisibleRow(nStartRow, nEndRow);
3680 }
3681 
3682 SCROW ScDocument::LastVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3683 {
3684     if (!ValidTab(nTab) || !pTab[nTab])
3685         return ::std::numeric_limits<SCROW>::max();;
3686 
3687     return pTab[nTab]->LastVisibleRow(nStartRow, nEndRow);
3688 }
3689 
3690 SCROW ScDocument::CountVisibleRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3691 {
3692     if (!ValidTab(nTab) || !pTab[nTab])
3693         return 0;
3694 
3695     return pTab[nTab]->CountVisibleRows(nStartRow, nEndRow);
3696 }
3697 
3698 bool ScDocument::RowFiltered(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow)
3699 {
3700     if (!ValidTab(nTab) || !pTab[nTab])
3701         return false;
3702 
3703     return pTab[nTab]->RowFiltered(nRow, pFirstRow, pLastRow);
3704 }
3705 
3706 bool ScDocument::HasFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3707 {
3708     if (!ValidTab(nTab) || !pTab[nTab])
3709         return false;
3710 
3711     return pTab[nTab]->HasFilteredRows(nStartRow, nEndRow);
3712 }
3713 
3714 bool ScDocument::ColFiltered(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol)
3715 {
3716     if (!ValidTab(nTab) || !pTab[nTab])
3717         return false;
3718 
3719     return pTab[nTab]->ColFiltered(nCol, pFirstCol, pLastCol);
3720 }
3721 
3722 void ScDocument::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bFiltered)
3723 {
3724     if (!ValidTab(nTab) || !pTab[nTab])
3725         return;
3726 
3727     pTab[nTab]->SetRowFiltered(nStartRow, nEndRow, bFiltered);
3728 }
3729 
3730 void ScDocument::SetColFiltered(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bFiltered)
3731 {
3732     if (!ValidTab(nTab) || !pTab[nTab])
3733         return;
3734 
3735     pTab[nTab]->SetColFiltered(nStartCol, nEndCol, bFiltered);
3736 }
3737 
3738 SCROW ScDocument::FirstNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3739 {
3740     if (!ValidTab(nTab) || !pTab[nTab])
3741         return ::std::numeric_limits<SCROW>::max();;
3742 
3743     return pTab[nTab]->FirstNonFilteredRow(nStartRow, nEndRow);
3744 }
3745 
3746 SCROW ScDocument::LastNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3747 {
3748     if (!ValidTab(nTab) || !pTab[nTab])
3749         return ::std::numeric_limits<SCROW>::max();;
3750 
3751     return pTab[nTab]->LastNonFilteredRow(nStartRow, nEndRow);
3752 }
3753 
3754 SCROW ScDocument::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3755 {
3756     if (!ValidTab(nTab) || !pTab[nTab])
3757         return 0;
3758 
3759     return pTab[nTab]->CountNonFilteredRows(nStartRow, nEndRow);
3760 }
3761 
3762 void ScDocument::SyncColRowFlags()
3763 {
3764     for (SCTAB i = 0; i <= nMaxTableNumber; ++i)
3765     {
3766         if (!ValidTab(i) || !pTab[i])
3767             continue;
3768 
3769         pTab[i]->SyncColRowFlags();
3770     }
3771 }
3772 
3773 SCROW ScDocument::GetLastFlaggedRow( SCTAB nTab ) const
3774 {
3775     if ( ValidTab(nTab) && pTab[nTab] )
3776         return pTab[nTab]->GetLastFlaggedRow();
3777     return 0;
3778 }
3779 
3780 
3781 SCCOL ScDocument::GetLastChangedCol( SCTAB nTab ) const
3782 {
3783     if ( ValidTab(nTab) && pTab[nTab] )
3784         return pTab[nTab]->GetLastChangedCol();
3785     return 0;
3786 }
3787 
3788 SCROW ScDocument::GetLastChangedRow( SCTAB nTab ) const
3789 {
3790     if ( ValidTab(nTab) && pTab[nTab] )
3791         return pTab[nTab]->GetLastChangedRow();
3792     return 0;
3793 }
3794 
3795 
3796 SCCOL ScDocument::GetNextDifferentChangedCol( SCTAB nTab, SCCOL nStart) const
3797 {
3798     if ( ValidTab(nTab) && pTab[nTab] )
3799     {
3800         sal_uInt8 nStartFlags = pTab[nTab]->GetColFlags(nStart);
3801         sal_uInt16 nStartWidth = pTab[nTab]->GetOriginalWidth(nStart);
3802         for (SCCOL nCol = nStart + 1; nCol <= MAXCOL; nCol++)
3803         {
3804             if (((nStartFlags & CR_MANUALBREAK) != (pTab[nTab]->GetColFlags(nCol) & CR_MANUALBREAK)) ||
3805                 (nStartWidth != pTab[nTab]->GetOriginalWidth(nCol)) ||
3806                 ((nStartFlags & CR_HIDDEN) != (pTab[nTab]->GetColFlags(nCol) & CR_HIDDEN)) )
3807                 return nCol;
3808         }
3809         return MAXCOL+1;
3810     }
3811     return 0;
3812 }
3813 
3814 SCROW ScDocument::GetNextDifferentChangedRow( SCTAB nTab, SCROW nStart, bool bCareManualSize) const
3815 {
3816     const ScBitMaskCompressedArray< SCROW, sal_uInt8> * pRowFlagsArray;
3817     if ( ValidTab(nTab) && pTab[nTab] && ((pRowFlagsArray = pTab[nTab]->GetRowFlagsArray()) != NULL) &&
3818             pTab[nTab]->mpRowHeights && pTab[nTab]->mpHiddenRows )
3819     {
3820         size_t nIndex;          // ignored
3821         SCROW nFlagsEndRow;
3822         SCROW nHiddenEndRow;
3823         SCROW nHeightEndRow;
3824         sal_uInt8 nFlags;
3825         bool bHidden;
3826         sal_uInt16 nHeight;
3827         sal_uInt8 nStartFlags = nFlags = pRowFlagsArray->GetValue( nStart, nIndex, nFlagsEndRow);
3828         bool bStartHidden = bHidden = pTab[nTab]->RowHidden( nStart, NULL, &nHiddenEndRow);
3829         sal_uInt16 nStartHeight = nHeight = pTab[nTab]->GetRowHeight( nStart, NULL, &nHeightEndRow, false);
3830         SCROW nRow;
3831         while ((nRow = std::min( nHiddenEndRow, std::min( nFlagsEndRow, nHeightEndRow)) + 1) <= MAXROW)
3832         {
3833             if (nFlagsEndRow < nRow)
3834                 nFlags = pRowFlagsArray->GetValue( nRow, nIndex, nFlagsEndRow);
3835             if (nHiddenEndRow < nRow)
3836                 bHidden = pTab[nTab]->RowHidden( nRow, NULL, &nHiddenEndRow);
3837             if (nHeightEndRow < nRow)
3838                 nHeight = pTab[nTab]->GetRowHeight( nRow, NULL, &nHeightEndRow, false);
3839             if (    ((nStartFlags & CR_MANUALBREAK) != (nFlags & CR_MANUALBREAK)) ||
3840                     ((nStartFlags & CR_MANUALSIZE) != (nFlags & CR_MANUALSIZE)) ||
3841                     (bStartHidden != bHidden) ||
3842                     (bCareManualSize && (nStartFlags & CR_MANUALSIZE) && (nStartHeight != nHeight)) ||
3843                     (!bCareManualSize && ((nStartHeight != nHeight))))
3844                 return nRow;
3845         }
3846         return MAXROW+1;
3847     }
3848     return 0;
3849 }
3850 
3851 sal_Bool ScDocument::GetColDefault( SCTAB nTab, SCCOL nCol, SCROW nLastRow, SCROW& nDefault)
3852 {
3853     sal_Bool bRet(sal_False);
3854     nDefault = 0;
3855     ScDocAttrIterator aDocAttrItr(this, nTab, nCol, 0, nCol, nLastRow);
3856     SCCOL nColumn;
3857     SCROW nStartRow;
3858     SCROW nEndRow;
3859     const ScPatternAttr* pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
3860     if (nEndRow < nLastRow)
3861     {
3862         ScDefaultAttrSet aSet;
3863         ScDefaultAttrSet::iterator aItr = aSet.end();
3864         while (pAttr)
3865         {
3866             ScDefaultAttr aAttr(pAttr);
3867             aItr = aSet.find(aAttr);
3868             if (aItr == aSet.end())
3869             {
3870                 aAttr.nCount = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
3871                 aAttr.nFirst = nStartRow;
3872                 aSet.insert(aAttr);
3873             }
3874             else
3875             {
3876                 aAttr.nCount = aItr->nCount + static_cast<SCSIZE>(nEndRow - nStartRow + 1);
3877                 aAttr.nFirst = aItr->nFirst;
3878                 aSet.erase(aItr);
3879                 aSet.insert(aAttr);
3880             }
3881             pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
3882         }
3883         ScDefaultAttrSet::iterator aDefaultItr = aSet.begin();
3884         aItr = aDefaultItr;
3885         aItr++;
3886         while (aItr != aSet.end())
3887         {
3888             // for entries with equal count, use the one with the lowest start row,
3889             // don't use the random order of pointer comparisons
3890             if ( aItr->nCount > aDefaultItr->nCount ||
3891                  ( aItr->nCount == aDefaultItr->nCount && aItr->nFirst < aDefaultItr->nFirst ) )
3892                 aDefaultItr = aItr;
3893             aItr++;
3894         }
3895         nDefault = aDefaultItr->nFirst;
3896         bRet = sal_True;
3897     }
3898     else
3899         bRet = sal_True;
3900     return bRet;
3901 }
3902 
3903 sal_Bool ScDocument::GetRowDefault( SCTAB /* nTab */, SCROW /* nRow */, SCCOL /* nLastCol */, SCCOL& /* nDefault */ )
3904 {
3905     sal_Bool bRet(sal_False);
3906     return bRet;
3907 }
3908 
3909 void ScDocument::StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
3910 {
3911     if ( ValidTab(nTab) && pTab[nTab] )
3912         pTab[nTab]->StripHidden( rX1, rY1, rX2, rY2 );
3913 }
3914 
3915 
3916 void ScDocument::ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
3917 {
3918     if ( ValidTab(nTab) && pTab[nTab] )
3919         pTab[nTab]->ExtendHidden( rX1, rY1, rX2, rY2 );
3920 }
3921 
3922 //
3923 //  Attribute   ----------------------------------------------------------
3924 //
3925 
3926 const SfxPoolItem* ScDocument::GetAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich ) const
3927 {
3928     if ( ValidTab(nTab)  && pTab[nTab] )
3929     {
3930         const SfxPoolItem* pTemp = pTab[nTab]->GetAttr( nCol, nRow, nWhich );
3931         if (pTemp)
3932             return pTemp;
3933         else
3934         {
3935             DBG_ERROR( "Attribut Null" );
3936         }
3937     }
3938     return &xPoolHelper->GetDocPool()->GetDefaultItem( nWhich );
3939 }
3940 
3941 
3942 const ScPatternAttr* ScDocument::GetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3943 {
3944     if ( ValidTab(nTab)  && pTab[nTab] )
3945         return pTab[nTab]->GetPattern( nCol, nRow );
3946     return NULL;
3947 }
3948 
3949 
3950 const ScPatternAttr* ScDocument::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
3951 {
3952     if ( ValidTab(nTab)  && pTab[nTab] )
3953         return pTab[nTab]->GetMostUsedPattern( nCol, nStartRow, nEndRow );
3954     return NULL;
3955 }
3956 
3957 
3958 void ScDocument::ApplyAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem& rAttr )
3959 {
3960     if ( ValidTab(nTab)  && pTab[nTab] )
3961         pTab[nTab]->ApplyAttr( nCol, nRow, rAttr );
3962 }
3963 
3964 
3965 void ScDocument::ApplyPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr )
3966 {
3967     if ( ValidTab(nTab)  && pTab[nTab] )
3968         pTab[nTab]->ApplyPattern( nCol, nRow, rAttr );
3969 }
3970 
3971 
3972 void ScDocument::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow,
3973                         SCCOL nEndCol, SCROW nEndRow,
3974                         const ScMarkData& rMark,
3975                         const ScPatternAttr& rAttr )
3976 {
3977     for (SCTAB i=0; i <= MAXTAB; i++)
3978         if (pTab[i])
3979             if (rMark.GetTableSelect(i))
3980                 pTab[i]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
3981 }
3982 
3983 
3984 void ScDocument::ApplyPatternAreaTab( SCCOL nStartCol, SCROW nStartRow,
3985                         SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScPatternAttr& rAttr )
3986 {
3987     if (VALIDTAB(nTab))
3988         if (pTab[nTab])
3989             pTab[nTab]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
3990 }
3991 
3992 void ScDocument::ApplyPooledPatternAreaTab( SCCOL nStartCol, SCROW nStartRow,
3993                         SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScPatternAttr& rPooledAttr, const ScPatternAttr& rAttr )
3994 {
3995     if (VALIDTAB(nTab))
3996         if (pTab[nTab])
3997             pTab[nTab]->ApplyPooledPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rPooledAttr, rAttr );
3998 }
3999 
4000 void ScDocument::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
4001         const ScMarkData& rMark, const ScPatternAttr& rPattern, short nNewType )
4002 {
4003     for (SCTAB i=0; i <= MAXTAB; i++)
4004         if (pTab[i])
4005             if (rMark.GetTableSelect(i))
4006                 pTab[i]->ApplyPatternIfNumberformatIncompatible( rRange, rPattern, nNewType );
4007 }
4008 
4009 
4010 void ScDocument::ApplyStyle( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScStyleSheet& rStyle)
4011 {
4012     if (VALIDTAB(nTab))
4013         if (pTab[nTab])
4014             pTab[nTab]->ApplyStyle( nCol, nRow, rStyle );
4015 }
4016 
4017 
4018 void ScDocument::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow,
4019                         SCCOL nEndCol, SCROW nEndRow,
4020                         const ScMarkData& rMark,
4021                         const ScStyleSheet& rStyle)
4022 {
4023     for (SCTAB i=0; i <= MAXTAB; i++)
4024         if (pTab[i])
4025             if (rMark.GetTableSelect(i))
4026                 pTab[i]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
4027 }
4028 
4029 
4030 void ScDocument::ApplyStyleAreaTab( SCCOL nStartCol, SCROW nStartRow,
4031                         SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScStyleSheet& rStyle)
4032 {
4033     if (VALIDTAB(nTab))
4034         if (pTab[nTab])
4035             pTab[nTab]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
4036 }
4037 
4038 
4039 void ScDocument::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
4040 {
4041     // ApplySelectionStyle needs multi mark
4042     if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
4043     {
4044         ScRange aRange;
4045         rMark.GetMarkArea( aRange );
4046         ApplyStyleArea( aRange.aStart.Col(), aRange.aStart.Row(),
4047                           aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rStyle );
4048     }
4049     else
4050     {
4051         for (SCTAB i=0; i<=MAXTAB; i++)
4052             if ( pTab[i] && rMark.GetTableSelect(i) )
4053                     pTab[i]->ApplySelectionStyle( rStyle, rMark );
4054     }
4055 }
4056 
4057 
4058 void ScDocument::ApplySelectionLineStyle( const ScMarkData& rMark,
4059                     const SvxBorderLine* pLine, sal_Bool bColorOnly )
4060 {
4061     if ( bColorOnly && !pLine )
4062         return;
4063 
4064     for (SCTAB i=0; i<=MAXTAB; i++)
4065         if (pTab[i])
4066             if (rMark.GetTableSelect(i))
4067                 pTab[i]->ApplySelectionLineStyle( rMark, pLine, bColorOnly );
4068 }
4069 
4070 
4071 const ScStyleSheet* ScDocument::GetStyle( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4072 {
4073     if ( VALIDTAB(nTab) && pTab[nTab] )
4074         return pTab[nTab]->GetStyle(nCol, nRow);
4075     else
4076         return NULL;
4077 }
4078 
4079 
4080 const ScStyleSheet* ScDocument::GetSelectionStyle( const ScMarkData& rMark ) const
4081 {
4082     sal_Bool    bEqual = sal_True;
4083     sal_Bool    bFound;
4084 
4085     const ScStyleSheet* pStyle = NULL;
4086     const ScStyleSheet* pNewStyle;
4087 
4088     if ( rMark.IsMultiMarked() )
4089         for (SCTAB i=0; i<=MAXTAB && bEqual; i++)
4090             if (pTab[i] && rMark.GetTableSelect(i))
4091             {
4092                 pNewStyle = pTab[i]->GetSelectionStyle( rMark, bFound );
4093                 if (bFound)
4094                 {
4095                     if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
4096                         bEqual = sal_False;                                             // unterschiedliche
4097                     pStyle = pNewStyle;
4098                 }
4099             }
4100     if ( rMark.IsMarked() )
4101     {
4102         ScRange aRange;
4103         rMark.GetMarkArea( aRange );
4104         for (SCTAB i=aRange.aStart.Tab(); i<=aRange.aEnd.Tab() && bEqual; i++)
4105             if (pTab[i] && rMark.GetTableSelect(i))
4106             {
4107                 pNewStyle = pTab[i]->GetAreaStyle( bFound,
4108                                         aRange.aStart.Col(), aRange.aStart.Row(),
4109                                         aRange.aEnd.Col(),   aRange.aEnd.Row()   );
4110                 if (bFound)
4111                 {
4112                     if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
4113                         bEqual = sal_False;                                             // unterschiedliche
4114                     pStyle = pNewStyle;
4115                 }
4116             }
4117     }
4118 
4119     return bEqual ? pStyle : NULL;
4120 }
4121 
4122 
4123 void ScDocument::StyleSheetChanged( const SfxStyleSheetBase* pStyleSheet, sal_Bool bRemoved,
4124                                     OutputDevice* pDev,
4125                                     double nPPTX, double nPPTY,
4126                                     const Fraction& rZoomX, const Fraction& rZoomY )
4127 {
4128     for (SCTAB i=0; i <= MAXTAB; i++)
4129         if (pTab[i])
4130             pTab[i]->StyleSheetChanged
4131                 ( pStyleSheet, bRemoved, pDev, nPPTX, nPPTY, rZoomX, rZoomY );
4132 
4133     if ( pStyleSheet && pStyleSheet->GetName() == ScGlobal::GetRscString(STR_STYLENAME_STANDARD) )
4134     {
4135         //  update attributes for all note objects
4136         ScDetectiveFunc::UpdateAllComments( *this );
4137     }
4138 }
4139 
4140 
4141 sal_Bool ScDocument::IsStyleSheetUsed( const ScStyleSheet& rStyle, sal_Bool bGatherAllStyles ) const
4142 {
4143     if ( bStyleSheetUsageInvalid || rStyle.GetUsage() == ScStyleSheet::UNKNOWN )
4144     {
4145         if ( bGatherAllStyles )
4146         {
4147             SfxStyleSheetIterator aIter( xPoolHelper->GetStylePool(),
4148                     SFX_STYLE_FAMILY_PARA );
4149             for ( const SfxStyleSheetBase* pStyle = aIter.First(); pStyle;
4150                                            pStyle = aIter.Next() )
4151             {
4152                 const ScStyleSheet* pScStyle = PTR_CAST( ScStyleSheet, pStyle );
4153                 if ( pScStyle )
4154                     pScStyle->SetUsage( ScStyleSheet::NOTUSED );
4155             }
4156         }
4157 
4158         sal_Bool bIsUsed = sal_False;
4159 
4160         for ( SCTAB i=0; i<=MAXTAB; i++ )
4161         {
4162             if ( pTab[i] )
4163             {
4164                 if ( pTab[i]->IsStyleSheetUsed( rStyle, bGatherAllStyles ) )
4165                 {
4166                     if ( !bGatherAllStyles )
4167                         return sal_True;
4168                     bIsUsed = sal_True;
4169                 }
4170             }
4171         }
4172 
4173         if ( bGatherAllStyles )
4174             bStyleSheetUsageInvalid = sal_False;
4175 
4176         return bIsUsed;
4177     }
4178 
4179     return rStyle.GetUsage() == ScStyleSheet::USED;
4180 }
4181 
4182 
4183 sal_Bool ScDocument::ApplyFlagsTab( SCCOL nStartCol, SCROW nStartRow,
4184                         SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, sal_Int16 nFlags )
4185 {
4186     if (VALIDTAB(nTab))
4187         if (pTab[nTab])
4188             return pTab[nTab]->ApplyFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
4189 
4190     DBG_ERROR("ApplyFlags: falsche Tabelle");
4191     return sal_False;
4192 }
4193 
4194 
4195 sal_Bool ScDocument::RemoveFlagsTab( SCCOL nStartCol, SCROW nStartRow,
4196                         SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, sal_Int16 nFlags )
4197 {
4198     if (VALIDTAB(nTab))
4199         if (pTab[nTab])
4200             return pTab[nTab]->RemoveFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
4201 
4202     DBG_ERROR("RemoveFlags: falsche Tabelle");
4203     return sal_False;
4204 }
4205 
4206 
4207 void ScDocument::SetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr,
4208                                 sal_Bool bPutToPool )
4209 {
4210     if (VALIDTAB(nTab))
4211         if (pTab[nTab])
4212             pTab[nTab]->SetPattern( nCol, nRow, rAttr, bPutToPool );
4213 }
4214 
4215 
4216 void ScDocument::SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr,
4217                                 sal_Bool bPutToPool )
4218 {
4219     SCTAB nTab = rPos.Tab();
4220     if (pTab[nTab])
4221         pTab[nTab]->SetPattern( rPos, rAttr, bPutToPool );
4222 }
4223 
4224 
4225 ScPatternAttr* ScDocument::CreateSelectionPattern( const ScMarkData& rMark, sal_Bool bDeep )
4226 {
4227     ScMergePatternState aState;
4228 
4229     if ( rMark.IsMultiMarked() )                                // multi selection
4230     {
4231         for (SCTAB i=0; i<=MAXTAB; i++)
4232             if (pTab[i] && rMark.GetTableSelect(i))
4233                 pTab[i]->MergeSelectionPattern( aState, rMark, bDeep );
4234     }
4235     if ( rMark.IsMarked() )                                     // simle selection
4236     {
4237         ScRange aRange;
4238         rMark.GetMarkArea(aRange);
4239         for (SCTAB i=0; i<=MAXTAB; i++)
4240             if (pTab[i] && rMark.GetTableSelect(i))
4241                 pTab[i]->MergePatternArea( aState,
4242                                 aRange.aStart.Col(), aRange.aStart.Row(),
4243                                 aRange.aEnd.Col(), aRange.aEnd.Row(), bDeep );
4244     }
4245 
4246     DBG_ASSERT( aState.pItemSet, "SelectionPattern Null" );
4247     if (aState.pItemSet)
4248         return new ScPatternAttr( aState.pItemSet );
4249     else
4250         return new ScPatternAttr( GetPool() );      // empty
4251 }
4252 
4253 
4254 const ScPatternAttr* ScDocument::GetSelectionPattern( const ScMarkData& rMark, sal_Bool bDeep )
4255 {
4256     delete pSelectionAttr;
4257     pSelectionAttr = CreateSelectionPattern( rMark, bDeep );
4258     return pSelectionAttr;
4259 }
4260 
4261 
4262 void ScDocument::GetSelectionFrame( const ScMarkData& rMark,
4263                                     SvxBoxItem&     rLineOuter,
4264                                     SvxBoxInfoItem& rLineInner )
4265 {
4266     rLineOuter.SetLine(NULL, BOX_LINE_TOP);
4267     rLineOuter.SetLine(NULL, BOX_LINE_BOTTOM);
4268     rLineOuter.SetLine(NULL, BOX_LINE_LEFT);
4269     rLineOuter.SetLine(NULL, BOX_LINE_RIGHT);
4270     rLineOuter.SetDistance(0);
4271 
4272     rLineInner.SetLine(NULL, BOXINFO_LINE_HORI);
4273     rLineInner.SetLine(NULL, BOXINFO_LINE_VERT);
4274     rLineInner.SetTable(sal_True);
4275     rLineInner.SetDist(sal_True);
4276     rLineInner.SetMinDist(sal_False);
4277 
4278     ScLineFlags aFlags;
4279 
4280     if (rMark.IsMarked())
4281     {
4282         ScRange aRange;
4283         rMark.GetMarkArea(aRange);
4284         rLineInner.EnableHor( aRange.aStart.Row() != aRange.aEnd.Row() );
4285         rLineInner.EnableVer( aRange.aStart.Col() != aRange.aEnd.Col() );
4286         for (SCTAB i=0; i<=MAXTAB; i++)
4287             if (pTab[i] && rMark.GetTableSelect(i))
4288                 pTab[i]->MergeBlockFrame( &rLineOuter, &rLineInner, aFlags,
4289                                           aRange.aStart.Col(), aRange.aStart.Row(),
4290                                           aRange.aEnd.Col(),   aRange.aEnd.Row() );
4291     }
4292 
4293         //  Don't care Status auswerten
4294 
4295     rLineInner.SetValid( VALID_LEFT,   ( aFlags.nLeft != SC_LINE_DONTCARE ) );
4296     rLineInner.SetValid( VALID_RIGHT,  ( aFlags.nRight != SC_LINE_DONTCARE ) );
4297     rLineInner.SetValid( VALID_TOP,    ( aFlags.nTop != SC_LINE_DONTCARE ) );
4298     rLineInner.SetValid( VALID_BOTTOM, ( aFlags.nBottom != SC_LINE_DONTCARE ) );
4299     rLineInner.SetValid( VALID_HORI,   ( aFlags.nHori != SC_LINE_DONTCARE ) );
4300     rLineInner.SetValid( VALID_VERT,   ( aFlags.nVert != SC_LINE_DONTCARE ) );
4301 }
4302 
4303 
4304 bool ScDocument::HasAttrib( SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
4305                             SCCOL nCol2, SCROW nRow2, SCTAB nTab2, sal_uInt16 nMask )
4306 {
4307     if ( nMask & HASATTR_ROTATE )
4308     {
4309         //  Attribut im Dokument ueberhaupt verwendet?
4310         //  (wie in fillinfo)
4311 
4312         ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4313 
4314         sal_Bool bAnyItem = sal_False;
4315         sal_uInt32 nRotCount = pPool->GetItemCount2( ATTR_ROTATE_VALUE );
4316         for (sal_uInt32 nItem=0; nItem<nRotCount; nItem++)
4317         {
4318             const SfxPoolItem* pItem = pPool->GetItem2( ATTR_ROTATE_VALUE, nItem );
4319             if ( pItem )
4320             {
4321                 // 90 or 270 degrees is former SvxOrientationItem - only look for other values
4322                 // (see ScPatternAttr::GetCellOrientation)
4323                 sal_Int32 nAngle = static_cast<const SfxInt32Item*>(pItem)->GetValue();
4324                 if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
4325                 {
4326                     bAnyItem = sal_True;
4327                     break;
4328                 }
4329             }
4330         }
4331         if (!bAnyItem)
4332             nMask &= ~HASATTR_ROTATE;
4333     }
4334 
4335     if ( nMask & HASATTR_RTL )
4336     {
4337         //  first check if right-to left is in the pool at all
4338         //  (the same item is used in cell and page format)
4339 
4340         ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4341 
4342         sal_Bool bHasRtl = sal_False;
4343         sal_uInt32 nDirCount = pPool->GetItemCount2( ATTR_WRITINGDIR );
4344         for (sal_uInt32 nItem=0; nItem<nDirCount; nItem++)
4345         {
4346             const SfxPoolItem* pItem = pPool->GetItem2( ATTR_WRITINGDIR, nItem );
4347             if ( pItem && ((const SvxFrameDirectionItem*)pItem)->GetValue() == FRMDIR_HORI_RIGHT_TOP )
4348             {
4349                 bHasRtl = sal_True;
4350                 break;
4351             }
4352         }
4353         if (!bHasRtl)
4354             nMask &= ~HASATTR_RTL;
4355     }
4356 
4357     if (!nMask)
4358         return false;
4359 
4360     bool bFound = false;
4361     for (SCTAB i=nTab1; i<=nTab2 && !bFound; i++)
4362         if (pTab[i])
4363         {
4364             if ( nMask & HASATTR_RTL )
4365             {
4366                 if ( GetEditTextDirection(i) == EE_HTEXTDIR_R2L )       // sheet default
4367                     bFound = true;
4368             }
4369             if ( nMask & HASATTR_RIGHTORCENTER )
4370             {
4371                 //  On a RTL sheet, don't start to look for the default left value
4372                 //  (which is then logically right), instead always assume sal_True.
4373                 //  That way, ScAttrArray::HasAttrib doesn't have to handle RTL sheets.
4374 
4375                 if ( IsLayoutRTL(i) )
4376                     bFound = true;
4377             }
4378 
4379             if ( !bFound )
4380                 bFound = pTab[i]->HasAttrib( nCol1, nRow1, nCol2, nRow2, nMask );
4381         }
4382 
4383     return bFound;
4384 }
4385 
4386 bool ScDocument::HasAttrib( const ScRange& rRange, sal_uInt16 nMask )
4387 {
4388     return HasAttrib( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
4389                       rRange.aEnd.Col(),   rRange.aEnd.Row(),   rRange.aEnd.Tab(),
4390                       nMask );
4391 }
4392 
4393 void ScDocument::FindMaxRotCol( SCTAB nTab, RowInfo* pRowInfo, SCSIZE nArrCount,
4394                                 SCCOL nX1, SCCOL nX2 ) const
4395 {
4396     if ( ValidTab(nTab)  && pTab[nTab] )
4397         pTab[nTab]->FindMaxRotCol( pRowInfo, nArrCount, nX1, nX2 );
4398     else
4399     {
4400         DBG_ERRORFILE("FindMaxRotCol: falsche Tabelle");
4401     }
4402 }
4403 
4404 void ScDocument::GetBorderLines( SCCOL nCol, SCROW nRow, SCTAB nTab,
4405                         const SvxBorderLine** ppLeft, const SvxBorderLine** ppTop,
4406                         const SvxBorderLine** ppRight, const SvxBorderLine** ppBottom ) const
4407 {
4408     //! Seitengrenzen fuer Druck beruecksichtigen !!!!!
4409 
4410     const SvxBoxItem* pThisAttr = (const SvxBoxItem*) GetEffItem( nCol, nRow, nTab, ATTR_BORDER );
4411     DBG_ASSERT(pThisAttr,"wo ist das Attribut?");
4412 
4413     const SvxBorderLine* pLeftLine   = pThisAttr->GetLeft();
4414     const SvxBorderLine* pTopLine    = pThisAttr->GetTop();
4415     const SvxBorderLine* pRightLine  = pThisAttr->GetRight();
4416     const SvxBorderLine* pBottomLine = pThisAttr->GetBottom();
4417 
4418     if ( nCol > 0 )
4419     {
4420         const SvxBorderLine* pOther = ((const SvxBoxItem*)
4421                                 GetEffItem( nCol-1, nRow, nTab, ATTR_BORDER ))->GetRight();
4422         if ( ScHasPriority( pOther, pLeftLine ) )
4423             pLeftLine = pOther;
4424     }
4425     if ( nRow > 0 )
4426     {
4427         const SvxBorderLine* pOther = ((const SvxBoxItem*)
4428                                 GetEffItem( nCol, nRow-1, nTab, ATTR_BORDER ))->GetBottom();
4429         if ( ScHasPriority( pOther, pTopLine ) )
4430             pTopLine = pOther;
4431     }
4432     if ( nCol < MAXCOL )
4433     {
4434         const SvxBorderLine* pOther = ((const SvxBoxItem*)
4435                                 GetEffItem( nCol+1, nRow, nTab, ATTR_BORDER ))->GetLeft();
4436         if ( ScHasPriority( pOther, pRightLine ) )
4437             pRightLine = pOther;
4438     }
4439     if ( nRow < MAXROW )
4440     {
4441         const SvxBorderLine* pOther = ((const SvxBoxItem*)
4442                                 GetEffItem( nCol, nRow+1, nTab, ATTR_BORDER ))->GetTop();
4443         if ( ScHasPriority( pOther, pBottomLine ) )
4444             pBottomLine = pOther;
4445     }
4446 
4447     if (ppLeft)
4448         *ppLeft = pLeftLine;
4449     if (ppTop)
4450         *ppTop = pTopLine;
4451     if (ppRight)
4452         *ppRight = pRightLine;
4453     if (ppBottom)
4454         *ppBottom = pBottomLine;
4455 }
4456 
4457 sal_Bool ScDocument::IsBlockEmpty( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
4458                                         SCCOL nEndCol, SCROW nEndRow, bool bIgnoreNotes ) const
4459 {
4460     if (VALIDTAB(nTab))
4461         if (pTab[nTab])
4462             return pTab[nTab]->IsBlockEmpty( nStartCol, nStartRow, nEndCol, nEndRow, bIgnoreNotes );
4463 
4464     DBG_ERROR("Falsche Tabellennummer");
4465     return sal_False;
4466 }
4467 
4468 
4469 void ScDocument::LockTable(SCTAB nTab)
4470 {
4471     if ( ValidTab(nTab)  && pTab[nTab] )
4472         pTab[nTab]->LockTable();
4473     else
4474     {
4475         DBG_ERROR("Falsche Tabellennummer");
4476     }
4477 }
4478 
4479 
4480 void ScDocument::UnlockTable(SCTAB nTab)
4481 {
4482     if ( ValidTab(nTab)  && pTab[nTab] )
4483         pTab[nTab]->UnlockTable();
4484     else
4485     {
4486         DBG_ERROR("Falsche Tabellennummer");
4487     }
4488 }
4489 
4490 
4491 sal_Bool ScDocument::IsBlockEditable( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
4492                                         SCCOL nEndCol, SCROW nEndRow,
4493                                         sal_Bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
4494 {
4495     // import into read-only document is possible
4496     if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
4497     {
4498         if ( pOnlyNotBecauseOfMatrix )
4499             *pOnlyNotBecauseOfMatrix = sal_False;
4500         return sal_False;
4501     }
4502 
4503     if (VALIDTAB(nTab))
4504         if (pTab[nTab])
4505             return pTab[nTab]->IsBlockEditable( nStartCol, nStartRow, nEndCol,
4506                 nEndRow, pOnlyNotBecauseOfMatrix );
4507 
4508     DBG_ERROR("Falsche Tabellennummer");
4509     if ( pOnlyNotBecauseOfMatrix )
4510         *pOnlyNotBecauseOfMatrix = sal_False;
4511     return sal_False;
4512 }
4513 
4514 
4515 sal_Bool ScDocument::IsSelectionEditable( const ScMarkData& rMark,
4516             sal_Bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
4517 {
4518     // import into read-only document is possible
4519     if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
4520     {
4521         if ( pOnlyNotBecauseOfMatrix )
4522             *pOnlyNotBecauseOfMatrix = sal_False;
4523         return sal_False;
4524     }
4525 
4526     ScRange aRange;
4527     rMark.GetMarkArea(aRange);
4528 
4529     sal_Bool bOk = sal_True;
4530     sal_Bool bMatrix = ( pOnlyNotBecauseOfMatrix != NULL );
4531     for ( SCTAB i=0; i<=MAXTAB && (bOk || bMatrix); i++ )
4532     {
4533         if ( pTab[i] && rMark.GetTableSelect(i) )
4534         {
4535             if (rMark.IsMarked())
4536             {
4537                 if ( !pTab[i]->IsBlockEditable( aRange.aStart.Col(),
4538                         aRange.aStart.Row(), aRange.aEnd.Col(),
4539                         aRange.aEnd.Row(), pOnlyNotBecauseOfMatrix ) )
4540                 {
4541                     bOk = sal_False;
4542                     if ( pOnlyNotBecauseOfMatrix )
4543                         bMatrix = *pOnlyNotBecauseOfMatrix;
4544                 }
4545             }
4546             if (rMark.IsMultiMarked())
4547             {
4548                 if ( !pTab[i]->IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix ) )
4549                 {
4550                     bOk = sal_False;
4551                     if ( pOnlyNotBecauseOfMatrix )
4552                         bMatrix = *pOnlyNotBecauseOfMatrix;
4553                 }
4554             }
4555         }
4556     }
4557 
4558     if ( pOnlyNotBecauseOfMatrix )
4559         *pOnlyNotBecauseOfMatrix = ( !bOk && bMatrix );
4560 
4561     return bOk;
4562 }
4563 
4564 
4565 sal_Bool ScDocument::HasSelectedBlockMatrixFragment( SCCOL nStartCol, SCROW nStartRow,
4566                                 SCCOL nEndCol, SCROW nEndRow,
4567                                 const ScMarkData& rMark ) const
4568 {
4569     sal_Bool bOk = sal_True;
4570     for (SCTAB i=0; i<=MAXTAB && bOk; i++)
4571         if (pTab[i])
4572             if (rMark.GetTableSelect(i))
4573                 if (pTab[i]->HasBlockMatrixFragment( nStartCol, nStartRow, nEndCol, nEndRow ))
4574                     bOk = sal_False;
4575 
4576     return !bOk;
4577 }
4578 
4579 
4580 sal_Bool ScDocument::GetMatrixFormulaRange( const ScAddress& rCellPos, ScRange& rMatrix )
4581 {
4582     //  if rCell is part of a matrix formula, return its complete range
4583 
4584     sal_Bool bRet = sal_False;
4585     ScBaseCell* pCell = GetCell( rCellPos );
4586     if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
4587     {
4588         ScAddress aOrigin = rCellPos;
4589         if ( ((ScFormulaCell*)pCell)->GetMatrixOrigin( aOrigin ) )
4590         {
4591             if ( aOrigin != rCellPos )
4592                 pCell = GetCell( aOrigin );
4593             if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
4594             {
4595                 SCCOL nSizeX;
4596                 SCROW nSizeY;
4597                 ((ScFormulaCell*)pCell)->GetMatColsRows(nSizeX,nSizeY);
4598                 if ( !(nSizeX > 0 && nSizeY > 0) )
4599                 {
4600                     // GetMatrixEdge computes also dimensions of the matrix
4601                     // if not already done (may occur if document is loaded
4602                     // from old file format).
4603                     // Needs an "invalid" initialized address.
4604                     aOrigin.SetInvalid();
4605                     ((ScFormulaCell*)pCell)->GetMatrixEdge(aOrigin);
4606                     ((ScFormulaCell*)pCell)->GetMatColsRows(nSizeX,nSizeY);
4607                 }
4608                 if ( nSizeX > 0 && nSizeY > 0 )
4609                 {
4610                     ScAddress aEnd( aOrigin.Col() + nSizeX - 1,
4611                                     aOrigin.Row() + nSizeY - 1,
4612                                     aOrigin.Tab() );
4613 
4614                     rMatrix.aStart = aOrigin;
4615                     rMatrix.aEnd = aEnd;
4616                     bRet = sal_True;
4617                 }
4618             }
4619         }
4620     }
4621     return bRet;
4622 }
4623 
4624 
4625 sal_Bool ScDocument::ExtendOverlapped( SCCOL& rStartCol, SCROW& rStartRow,
4626                                 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
4627 {
4628     sal_Bool bFound = sal_False;
4629     if ( ValidColRow(rStartCol,rStartRow) && ValidColRow(nEndCol,nEndRow) && ValidTab(nTab) )
4630     {
4631         if (pTab[nTab])
4632         {
4633             SCCOL nCol;
4634             SCCOL nOldCol = rStartCol;
4635             SCROW nOldRow = rStartRow;
4636             for (nCol=nOldCol; nCol<=nEndCol; nCol++)
4637                 while (((ScMergeFlagAttr*)GetAttr(nCol,rStartRow,nTab,ATTR_MERGE_FLAG))->
4638                             IsVerOverlapped())
4639                     --rStartRow;
4640 
4641             //!     weiterreichen ?
4642 
4643             ScAttrArray* pAttrArray = pTab[nTab]->aCol[nOldCol].pAttrArray;
4644             SCSIZE nIndex;
4645             pAttrArray->Search( nOldRow, nIndex );
4646             SCROW nAttrPos = nOldRow;
4647             while (nAttrPos<=nEndRow)
4648             {
4649                 DBG_ASSERT( nIndex < pAttrArray->nCount, "Falscher Index im AttrArray" );
4650 
4651                 if (((ScMergeFlagAttr&)pAttrArray->pData[nIndex].pPattern->
4652                         GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped())
4653                 {
4654                     SCROW nLoopEndRow = Min( nEndRow, pAttrArray->pData[nIndex].nRow );
4655                     for (SCROW nAttrRow = nAttrPos; nAttrRow <= nLoopEndRow; nAttrRow++)
4656                     {
4657                         SCCOL nTempCol = nOldCol;
4658                         do
4659                             --nTempCol;
4660                         while (((ScMergeFlagAttr*)GetAttr(nTempCol,nAttrRow,nTab,ATTR_MERGE_FLAG))
4661                                 ->IsHorOverlapped());
4662                         if (nTempCol < rStartCol)
4663                             rStartCol = nTempCol;
4664                     }
4665                 }
4666                 nAttrPos = pAttrArray->pData[nIndex].nRow + 1;
4667                 ++nIndex;
4668             }
4669         }
4670     }
4671     else
4672     {
4673         DBG_ERROR("ExtendOverlapped: falscher Bereich");
4674     }
4675 
4676     return bFound;
4677 }
4678 
4679 
4680 sal_Bool ScDocument::ExtendMergeSel( SCCOL nStartCol, SCROW nStartRow,
4681                               SCCOL& rEndCol, SCROW& rEndRow,
4682                               const ScMarkData& rMark, sal_Bool bRefresh, sal_Bool bAttrs )
4683 {
4684     // use all selected sheets from rMark
4685 
4686     sal_Bool bFound = sal_False;
4687     SCCOL nOldEndCol = rEndCol;
4688     SCROW nOldEndRow = rEndRow;
4689 
4690     for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
4691         if ( pTab[nTab] && rMark.GetTableSelect(nTab) )
4692         {
4693             SCCOL nThisEndCol = nOldEndCol;
4694             SCROW nThisEndRow = nOldEndRow;
4695             if ( ExtendMerge( nStartCol, nStartRow, nThisEndCol, nThisEndRow, nTab, bRefresh, bAttrs ) )
4696                 bFound = sal_True;
4697             if ( nThisEndCol > rEndCol )
4698                 rEndCol = nThisEndCol;
4699             if ( nThisEndRow > rEndRow )
4700                 rEndRow = nThisEndRow;
4701         }
4702 
4703     return bFound;
4704 }
4705 
4706 
4707 sal_Bool ScDocument::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
4708                               SCCOL& rEndCol,  SCROW& rEndRow,
4709                               SCTAB nTab, sal_Bool bRefresh, sal_Bool bAttrs )
4710 {
4711     sal_Bool bFound = sal_False;
4712     if ( ValidColRow(nStartCol,nStartRow) && ValidColRow(rEndCol,rEndRow) && ValidTab(nTab) )
4713     {
4714         if (pTab[nTab])
4715             bFound = pTab[nTab]->ExtendMerge( nStartCol, nStartRow, rEndCol, rEndRow, bRefresh, bAttrs );
4716 
4717         if (bRefresh)
4718             RefreshAutoFilter( nStartCol, nStartRow, rEndCol, rEndRow, nTab );
4719     }
4720     else
4721     {
4722         DBG_ERROR("ExtendMerge: falscher Bereich");
4723     }
4724 
4725     return bFound;
4726 }
4727 
4728 
4729 sal_Bool ScDocument::ExtendMerge( ScRange& rRange, sal_Bool bRefresh, sal_Bool bAttrs )
4730 {
4731     sal_Bool bFound = sal_False;
4732     SCTAB nStartTab = rRange.aStart.Tab();
4733     SCTAB nEndTab   = rRange.aEnd.Tab();
4734     SCCOL nEndCol   = rRange.aEnd.Col();
4735     SCROW nEndRow   = rRange.aEnd.Row();
4736 
4737     PutInOrder( nStartTab, nEndTab );
4738     for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++ )
4739     {
4740         SCCOL nExtendCol = rRange.aEnd.Col();
4741         SCROW nExtendRow = rRange.aEnd.Row();
4742         if (ExtendMerge( rRange.aStart.Col(), rRange.aStart.Row(),
4743                          nExtendCol,          nExtendRow,
4744                          nTab, bRefresh, bAttrs ) )
4745         {
4746             bFound = sal_True;
4747             if (nExtendCol > nEndCol) nEndCol = nExtendCol;
4748             if (nExtendRow > nEndRow) nEndRow = nExtendRow;
4749         }
4750     }
4751 
4752     rRange.aEnd.SetCol(nEndCol);
4753     rRange.aEnd.SetRow(nEndRow);
4754 
4755     return bFound;
4756 }
4757 
4758 sal_Bool ScDocument::ExtendTotalMerge( ScRange& rRange )
4759 {
4760     //  Bereich genau dann auf zusammengefasste Zellen erweitern, wenn
4761     //  dadurch keine neuen nicht-ueberdeckten Zellen getroffen werden
4762 
4763     sal_Bool bRet = sal_False;
4764     ScRange aExt = rRange;
4765     if (ExtendMerge(aExt))
4766     {
4767         if ( aExt.aEnd.Row() > rRange.aEnd.Row() )
4768         {
4769             ScRange aTest = aExt;
4770             aTest.aStart.SetRow( rRange.aEnd.Row() + 1 );
4771             if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
4772                 aExt.aEnd.SetRow(rRange.aEnd.Row());
4773         }
4774         if ( aExt.aEnd.Col() > rRange.aEnd.Col() )
4775         {
4776             ScRange aTest = aExt;
4777             aTest.aStart.SetCol( rRange.aEnd.Col() + 1 );
4778             if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
4779                 aExt.aEnd.SetCol(rRange.aEnd.Col());
4780         }
4781 
4782         bRet = ( aExt.aEnd != rRange.aEnd );
4783         rRange = aExt;
4784     }
4785     return bRet;
4786 }
4787 
4788 sal_Bool ScDocument::ExtendOverlapped( ScRange& rRange )
4789 {
4790     sal_Bool bFound = sal_False;
4791     SCTAB nStartTab = rRange.aStart.Tab();
4792     SCTAB nEndTab   = rRange.aEnd.Tab();
4793     SCCOL nStartCol = rRange.aStart.Col();
4794     SCROW nStartRow = rRange.aStart.Row();
4795 
4796     PutInOrder( nStartTab, nEndTab );
4797     for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++ )
4798     {
4799         SCCOL nExtendCol = rRange.aStart.Col();
4800         SCROW nExtendRow = rRange.aStart.Row();
4801         ExtendOverlapped( nExtendCol, nExtendRow,
4802                                 rRange.aEnd.Col(), rRange.aEnd.Row(), nTab );
4803         if (nExtendCol < nStartCol)
4804         {
4805             nStartCol = nExtendCol;
4806             bFound = sal_True;
4807         }
4808         if (nExtendRow < nStartRow)
4809         {
4810             nStartRow = nExtendRow;
4811             bFound = sal_True;
4812         }
4813     }
4814 
4815     rRange.aStart.SetCol(nStartCol);
4816     rRange.aStart.SetRow(nStartRow);
4817 
4818     return bFound;
4819 }
4820 
4821 sal_Bool ScDocument::RefreshAutoFilter( SCCOL nStartCol, SCROW nStartRow,
4822                                     SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
4823 {
4824     sal_uInt16 nCount = pDBCollection->GetCount();
4825     sal_uInt16 i;
4826     ScDBData* pData;
4827     SCTAB nDBTab;
4828     SCCOL nDBStartCol;
4829     SCROW nDBStartRow;
4830     SCCOL nDBEndCol;
4831     SCROW nDBEndRow;
4832 
4833     //      Autofilter loeschen
4834 
4835     sal_Bool bChange = RemoveFlagsTab( nStartCol,nStartRow, nEndCol,nEndRow, nTab, SC_MF_AUTO );
4836 
4837     //      Autofilter setzen
4838 
4839     for (i=0; i<nCount; i++)
4840     {
4841         pData = (*pDBCollection)[i];
4842         if (pData->HasAutoFilter())
4843         {
4844             pData->GetArea( nDBTab, nDBStartCol,nDBStartRow, nDBEndCol,nDBEndRow );
4845             if ( nDBTab==nTab && nDBStartRow<=nEndRow && nDBEndRow>=nStartRow &&
4846                                     nDBStartCol<=nEndCol && nDBEndCol>=nStartCol )
4847             {
4848                 if (ApplyFlagsTab( nDBStartCol,nDBStartRow, nDBEndCol,nDBStartRow,
4849                                     nDBTab, SC_MF_AUTO ))
4850                     bChange = sal_True;
4851             }
4852         }
4853     }
4854     return bChange;
4855 }
4856 
4857 
4858 sal_Bool ScDocument::IsHorOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4859 {
4860     const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
4861                                         GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
4862     if (pAttr)
4863         return pAttr->IsHorOverlapped();
4864     else
4865     {
4866         DBG_ERROR("Overlapped: Attr==0");
4867         return sal_False;
4868     }
4869 }
4870 
4871 
4872 sal_Bool ScDocument::IsVerOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4873 {
4874     const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
4875                                         GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
4876     if (pAttr)
4877         return pAttr->IsVerOverlapped();
4878     else
4879     {
4880         DBG_ERROR("Overlapped: Attr==0");
4881         return sal_False;
4882     }
4883 }
4884 
4885 
4886 void ScDocument::ApplySelectionFrame( const ScMarkData& rMark,
4887                                       const SvxBoxItem* pLineOuter,
4888                                       const SvxBoxInfoItem* pLineInner )
4889 {
4890     ScRangeList aRangeList;
4891     rMark.FillRangeListWithMarks( &aRangeList, sal_False );
4892     sal_uLong nRangeCount = aRangeList.Count();
4893     for (SCTAB i=0; i<=MAXTAB; i++)
4894     {
4895         if (pTab[i] && rMark.GetTableSelect(i))
4896         {
4897             for (sal_uLong j=0; j<nRangeCount; j++)
4898             {
4899                 ScRange aRange = *aRangeList.GetObject(j);
4900                 pTab[i]->ApplyBlockFrame( pLineOuter, pLineInner,
4901                     aRange.aStart.Col(), aRange.aStart.Row(),
4902                     aRange.aEnd.Col(),   aRange.aEnd.Row() );
4903             }
4904         }
4905     }
4906 }
4907 
4908 
4909 void ScDocument::ApplyFrameAreaTab( const ScRange& rRange,
4910                                     const SvxBoxItem* pLineOuter,
4911                                     const SvxBoxInfoItem* pLineInner )
4912 {
4913     SCTAB nStartTab = rRange.aStart.Tab();
4914     SCTAB nEndTab = rRange.aStart.Tab();
4915     for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
4916         if (pTab[nTab])
4917             pTab[nTab]->ApplyBlockFrame( pLineOuter, pLineInner,
4918                                          rRange.aStart.Col(), rRange.aStart.Row(),
4919                                          rRange.aEnd.Col(),   rRange.aEnd.Row() );
4920 }
4921 
4922 
4923 void ScDocument::ApplySelectionPattern( const ScPatternAttr& rAttr, const ScMarkData& rMark )
4924 {
4925     const SfxItemSet* pSet = &rAttr.GetItemSet();
4926     sal_Bool bSet = sal_False;
4927     sal_uInt16 i;
4928     for (i=ATTR_PATTERN_START; i<=ATTR_PATTERN_END && !bSet; i++)
4929         if (pSet->GetItemState(i) == SFX_ITEM_SET)
4930             bSet = sal_True;
4931 
4932     if (bSet)
4933     {
4934         // ApplySelectionCache needs multi mark
4935         if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
4936         {
4937             ScRange aRange;
4938             rMark.GetMarkArea( aRange );
4939             ApplyPatternArea( aRange.aStart.Col(), aRange.aStart.Row(),
4940                               aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rAttr );
4941         }
4942         else
4943         {
4944             SfxItemPoolCache aCache( xPoolHelper->GetDocPool(), pSet );
4945             for (SCTAB nTab=0; nTab<=MAXTAB; nTab++)
4946                 if (pTab[nTab])
4947                     if (rMark.GetTableSelect(nTab))
4948                         pTab[nTab]->ApplySelectionCache( &aCache, rMark );
4949         }
4950     }
4951 }
4952 
4953 
4954 void ScDocument::ChangeSelectionIndent( sal_Bool bIncrement, const ScMarkData& rMark )
4955 {
4956     for (SCTAB i=0; i<=MAXTAB; i++)
4957         if (pTab[i] && rMark.GetTableSelect(i))
4958             pTab[i]->ChangeSelectionIndent( bIncrement, rMark );
4959 }
4960 
4961 
4962 void ScDocument::ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark )
4963 {
4964     for (SCTAB i=0; i<=MAXTAB; i++)
4965         if (pTab[i] && rMark.GetTableSelect(i))
4966             pTab[i]->ClearSelectionItems( pWhich, rMark );
4967 }
4968 
4969 
4970 void ScDocument::DeleteSelection( sal_uInt16 nDelFlag, const ScMarkData& rMark )
4971 {
4972     for (SCTAB i=0; i<=MAXTAB; i++)
4973         if (pTab[i] && rMark.GetTableSelect(i))
4974             pTab[i]->DeleteSelection( nDelFlag, rMark );
4975 }
4976 
4977 
4978 void ScDocument::DeleteSelectionTab( SCTAB nTab, sal_uInt16 nDelFlag, const ScMarkData& rMark )
4979 {
4980     if (ValidTab(nTab)  && pTab[nTab])
4981         pTab[nTab]->DeleteSelection( nDelFlag, rMark );
4982     else
4983     {
4984         DBG_ERROR("Falsche Tabelle");
4985     }
4986 }
4987 
4988 
4989 ScPatternAttr* ScDocument::GetDefPattern() const
4990 {
4991     return (ScPatternAttr*) &xPoolHelper->GetDocPool()->GetDefaultItem(ATTR_PATTERN);
4992 }
4993 
4994 
4995 ScDocumentPool* ScDocument::GetPool()
4996 {
4997     return xPoolHelper->GetDocPool();
4998 }
4999 
5000 
5001 
5002 ScStyleSheetPool* ScDocument::GetStyleSheetPool() const
5003 {
5004     return xPoolHelper->GetStylePool();
5005 }
5006 
5007 
5008 SCSIZE ScDocument::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
5009                             SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, ScDirection eDir )
5010 {
5011     PutInOrder(nStartCol, nEndCol);
5012     PutInOrder(nStartRow, nEndRow);
5013     PutInOrder(nStartTab, nEndTab);
5014     if (VALIDTAB(nStartTab))
5015     {
5016         if (pTab[nStartTab])
5017             return pTab[nStartTab]->GetEmptyLinesInBlock(nStartCol, nStartRow, nEndCol, nEndRow, eDir);
5018         else
5019             return 0;
5020     }
5021     else
5022         return 0;
5023 }
5024 
5025 
5026 void ScDocument::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY )
5027 {
5028     if (ValidTab(nTab) && pTab[nTab])
5029         pTab[nTab]->FindAreaPos( rCol, rRow, nMovX, nMovY );
5030 }
5031 
5032 
5033 void ScDocument::GetNextPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY,
5034                                 sal_Bool bMarked, sal_Bool bUnprotected, const ScMarkData& rMark )
5035 {
5036     DBG_ASSERT( !nMovX || !nMovY, "GetNextPos: nur X oder Y" );
5037 
5038     ScMarkData aCopyMark = rMark;
5039     aCopyMark.SetMarking(sal_False);
5040     aCopyMark.MarkToMulti();
5041 
5042     if (ValidTab(nTab) && pTab[nTab])
5043         pTab[nTab]->GetNextPos( rCol, rRow, nMovX, nMovY, bMarked, bUnprotected, aCopyMark );
5044 }
5045 
5046 //
5047 //  Datei-Operationen
5048 //
5049 
5050 
5051 void ScDocument::UpdStlShtPtrsFrmNms()
5052 {
5053     ScPatternAttr::pDoc = this;
5054 
5055     ScDocumentPool* pPool = xPoolHelper->GetDocPool();
5056 
5057     sal_uInt32 nCount = pPool->GetItemCount2(ATTR_PATTERN);
5058     ScPatternAttr* pPattern;
5059     for (sal_uInt32 i=0; i<nCount; i++)
5060     {
5061         pPattern = (ScPatternAttr*)pPool->GetItem2(ATTR_PATTERN, i);
5062         if (pPattern)
5063             pPattern->UpdateStyleSheet();
5064     }
5065     ((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).UpdateStyleSheet();
5066 }
5067 
5068 
5069 void ScDocument::StylesToNames()
5070 {
5071     ScPatternAttr::pDoc = this;
5072 
5073     ScDocumentPool* pPool = xPoolHelper->GetDocPool();
5074 
5075     sal_uInt32 nCount = pPool->GetItemCount2(ATTR_PATTERN);
5076     ScPatternAttr* pPattern;
5077     for (sal_uInt32 i=0; i<nCount; i++)
5078     {
5079         pPattern = (ScPatternAttr*)pPool->GetItem2(ATTR_PATTERN, i);
5080         if (pPattern)
5081             pPattern->StyleToName();
5082     }
5083     ((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).StyleToName();
5084 }
5085 
5086 
5087 sal_uLong ScDocument::GetCellCount() const
5088 {
5089     sal_uLong nCellCount = 0L;
5090 
5091     for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
5092         if ( pTab[nTab] )
5093             nCellCount += pTab[nTab]->GetCellCount();
5094 
5095     return nCellCount;
5096 }
5097 
5098 SCSIZE ScDocument::GetCellCount(SCTAB nTab, SCCOL nCol) const
5099 {
5100     if (!ValidTab(nTab) || !pTab[nTab])
5101         return 0;
5102 
5103     return pTab[nTab]->GetCellCount(nCol);
5104 }
5105 
5106 sal_uLong ScDocument::GetCodeCount() const
5107 {
5108     sal_uLong nCodeCount = 0;
5109 
5110     for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
5111         if ( pTab[nTab] )
5112             nCodeCount += pTab[nTab]->GetCodeCount();
5113 
5114     return nCodeCount;
5115 }
5116 
5117 
5118 sal_uLong ScDocument::GetWeightedCount() const
5119 {
5120     sal_uLong nCellCount = 0L;
5121 
5122     for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
5123         if ( pTab[nTab] )
5124             nCellCount += pTab[nTab]->GetWeightedCount();
5125 
5126     return nCellCount;
5127 }
5128 
5129 
5130 void ScDocument::PageStyleModified( SCTAB nTab, const String& rNewName )
5131 {
5132     if ( ValidTab(nTab)  && pTab[nTab] )
5133         pTab[nTab]->PageStyleModified( rNewName );
5134 }
5135 
5136 
5137 void ScDocument::SetPageStyle( SCTAB nTab, const String& rName )
5138 {
5139     if ( ValidTab(nTab)  && pTab[nTab] )
5140         pTab[nTab]->SetPageStyle( rName );
5141 }
5142 
5143 
5144 const String& ScDocument::GetPageStyle( SCTAB nTab ) const
5145 {
5146     if ( ValidTab(nTab)  && pTab[nTab] )
5147         return pTab[nTab]->GetPageStyle();
5148 
5149     return EMPTY_STRING;
5150 }
5151 
5152 
5153 void ScDocument::SetPageSize( SCTAB nTab, const Size& rSize )
5154 {
5155     if ( ValidTab(nTab)  && pTab[nTab] )
5156         pTab[nTab]->SetPageSize( rSize );
5157 }
5158 
5159 Size ScDocument::GetPageSize( SCTAB nTab ) const
5160 {
5161     if ( ValidTab(nTab)  && pTab[nTab] )
5162         return pTab[nTab]->GetPageSize();
5163 
5164     DBG_ERROR("falsche Tab");
5165     return Size();
5166 }
5167 
5168 
5169 void ScDocument::SetRepeatArea( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow )
5170 {
5171     if ( ValidTab(nTab)  && pTab[nTab] )
5172         pTab[nTab]->SetRepeatArea( nStartCol, nEndCol, nStartRow, nEndRow );
5173 }
5174 
5175 void ScDocument::InvalidatePageBreaks(SCTAB nTab)
5176 {
5177     if (ValidTab(nTab) && pTab[nTab])
5178         pTab[nTab]->InvalidatePageBreaks();
5179 }
5180 
5181 void ScDocument::UpdatePageBreaks( SCTAB nTab, const ScRange* pUserArea )
5182 {
5183     if ( ValidTab(nTab)  && pTab[nTab] )
5184         pTab[nTab]->UpdatePageBreaks( pUserArea );
5185 }
5186 
5187 void ScDocument::RemoveManualBreaks( SCTAB nTab )
5188 {
5189     if ( ValidTab(nTab)  && pTab[nTab] )
5190         pTab[nTab]->RemoveManualBreaks();
5191 }
5192 
5193 sal_Bool ScDocument::HasManualBreaks( SCTAB nTab ) const
5194 {
5195     if ( ValidTab(nTab)  && pTab[nTab] )
5196         return pTab[nTab]->HasManualBreaks();
5197 
5198     DBG_ERROR("falsche Tab");
5199     return sal_False;
5200 }
5201 
5202 
5203 void ScDocument::GetDocStat( ScDocStat& rDocStat )
5204 {
5205     rDocStat.nTableCount = GetTableCount();
5206     rDocStat.aDocName    = aDocName;
5207     rDocStat.nCellCount  = GetCellCount();
5208 }
5209 
5210 
5211 sal_Bool ScDocument::HasPrintRange()
5212 {
5213     sal_Bool bResult = sal_False;
5214 
5215     for ( SCTAB i=0; !bResult && i<nMaxTableNumber; i++ )
5216         if ( pTab[i] )
5217             bResult = pTab[i]->IsPrintEntireSheet() || (pTab[i]->GetPrintRangeCount() > 0);
5218 
5219     return bResult;
5220 }
5221 
5222 
5223 sal_Bool ScDocument::IsPrintEntireSheet( SCTAB nTab ) const
5224 {
5225     return (ValidTab(nTab) ) && pTab[nTab] && pTab[nTab]->IsPrintEntireSheet();
5226 }
5227 
5228 
5229 sal_uInt16 ScDocument::GetPrintRangeCount( SCTAB nTab )
5230 {
5231     if (ValidTab(nTab) && pTab[nTab])
5232         return pTab[nTab]->GetPrintRangeCount();
5233 
5234     return 0;
5235 }
5236 
5237 
5238 const ScRange* ScDocument::GetPrintRange( SCTAB nTab, sal_uInt16 nPos )
5239 {
5240     if (ValidTab(nTab) && pTab[nTab])
5241         return pTab[nTab]->GetPrintRange(nPos);
5242 
5243     return NULL;
5244 }
5245 
5246 
5247 const ScRange* ScDocument::GetRepeatColRange( SCTAB nTab )
5248 {
5249     if (ValidTab(nTab) && pTab[nTab])
5250         return pTab[nTab]->GetRepeatColRange();
5251 
5252     return NULL;
5253 }
5254 
5255 
5256 const ScRange* ScDocument::GetRepeatRowRange( SCTAB nTab )
5257 {
5258     if (ValidTab(nTab) && pTab[nTab])
5259         return pTab[nTab]->GetRepeatRowRange();
5260 
5261     return NULL;
5262 }
5263 
5264 
5265 void ScDocument::ClearPrintRanges( SCTAB nTab )
5266 {
5267     if (ValidTab(nTab) && pTab[nTab])
5268         pTab[nTab]->ClearPrintRanges();
5269 }
5270 
5271 
5272 void ScDocument::AddPrintRange( SCTAB nTab, const ScRange& rNew )
5273 {
5274     if (ValidTab(nTab) && pTab[nTab])
5275         pTab[nTab]->AddPrintRange( rNew );
5276 }
5277 
5278 
5279 //UNUSED2009-05 void ScDocument::SetPrintRange( SCTAB nTab, const ScRange& rNew )
5280 //UNUSED2009-05 {
5281 //UNUSED2009-05     if (ValidTab(nTab) && pTab[nTab])
5282 //UNUSED2009-05         pTab[nTab]->SetPrintRange( rNew );
5283 //UNUSED2009-05 }
5284 
5285 
5286 void ScDocument::SetPrintEntireSheet( SCTAB nTab )
5287 {
5288     if (ValidTab(nTab) && pTab[nTab])
5289         pTab[nTab]->SetPrintEntireSheet();
5290 }
5291 
5292 
5293 void ScDocument::SetRepeatColRange( SCTAB nTab, const ScRange* pNew )
5294 {
5295     if (ValidTab(nTab) && pTab[nTab])
5296         pTab[nTab]->SetRepeatColRange( pNew );
5297 }
5298 
5299 
5300 void ScDocument::SetRepeatRowRange( SCTAB nTab, const ScRange* pNew )
5301 {
5302     if (ValidTab(nTab) && pTab[nTab])
5303         pTab[nTab]->SetRepeatRowRange( pNew );
5304 }
5305 
5306 
5307 ScPrintRangeSaver* ScDocument::CreatePrintRangeSaver() const
5308 {
5309     SCTAB nCount = GetTableCount();
5310     ScPrintRangeSaver* pNew = new ScPrintRangeSaver( nCount );
5311     for (SCTAB i=0; i<nCount; i++)
5312         if (pTab[i])
5313             pTab[i]->FillPrintSaver( pNew->GetTabData(i) );
5314     return pNew;
5315 }
5316 
5317 
5318 void ScDocument::RestorePrintRanges( const ScPrintRangeSaver& rSaver )
5319 {
5320     SCTAB nCount = rSaver.GetTabCount();
5321     for (SCTAB i=0; i<nCount; i++)
5322         if (pTab[i])
5323             pTab[i]->RestorePrintRanges( rSaver.GetTabData(i) );
5324 }
5325 
5326 
5327 sal_Bool ScDocument::NeedPageResetAfterTab( SCTAB nTab ) const
5328 {
5329     //  Die Seitennummern-Zaehlung faengt bei einer Tabelle neu an, wenn eine
5330     //  andere Vorlage als bei der vorherigen gesetzt ist (nur Namen vergleichen)
5331     //  und eine Seitennummer angegeben ist (nicht 0)
5332 
5333     if ( nTab < MAXTAB && pTab[nTab] && pTab[nTab+1] )
5334     {
5335         String aNew = pTab[nTab+1]->GetPageStyle();
5336         if ( aNew != pTab[nTab]->GetPageStyle() )
5337         {
5338             SfxStyleSheetBase* pStyle = xPoolHelper->GetStylePool()->Find( aNew, SFX_STYLE_FAMILY_PAGE );
5339             if ( pStyle )
5340             {
5341                 const SfxItemSet& rSet = pStyle->GetItemSet();
5342                 sal_uInt16 nFirst = ((const SfxUInt16Item&)rSet.Get(ATTR_PAGE_FIRSTPAGENO)).GetValue();
5343                 if ( nFirst != 0 )
5344                     return sal_True;        // Seitennummer in neuer Vorlage angegeben
5345             }
5346         }
5347     }
5348 
5349     return sal_False;       // sonst nicht
5350 }
5351 
5352 SfxUndoManager* ScDocument::GetUndoManager()
5353 {
5354     if (!mpUndoManager)
5355     {
5356         // to support enhanced text edit for draw objects, use an SdrUndoManager
5357         mpUndoManager = new SdrUndoManager;
5358     }
5359 
5360     return mpUndoManager;
5361 }
5362 
5363 ScRowBreakIterator* ScDocument::GetRowBreakIterator(SCTAB nTab) const
5364 {
5365     if (ValidTab(nTab) && pTab[nTab])
5366         return new ScRowBreakIterator(pTab[nTab]->maRowPageBreaks);
5367     return NULL;
5368 }
5369 
5370 void ScDocument::EnableUndo( bool bVal )
5371 {
5372     GetUndoManager()->EnableUndo(bVal);
5373     if( pDrawLayer ) pDrawLayer->EnableUndo(bVal);
5374     mbUndoEnabled = bVal;
5375 }
5376 
5377 bool ScDocument::IsInVBAMode() const
5378 {
5379     bool bResult = false;
5380     if ( pShell )
5381     {
5382         com::sun::star::uno::Reference< com::sun::star::script::vba::XVBACompatibility > xVBA( pShell->GetBasicContainer(), com::sun::star::uno::UNO_QUERY );
5383         bResult = xVBA.is() && xVBA->getVBACompatibilityMode();
5384     }
5385     return bResult;
5386 }
5387