Update ooo320-m1
[ooovba.git] / sc / source / core / data / document.cxx
blobf2d8746066edaf26c51616329d26739e837346fb
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: document.cxx,v $
10 * $Revision: 1.90.36.8 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // INCLUDE ---------------------------------------------------------------
36 #define _ZFORLIST_DECLARE_TABLE
37 #include "scitems.hxx"
38 #include <svx/eeitem.hxx>
40 #include <svx/boxitem.hxx>
41 #include <svx/frmdiritem.hxx>
42 #include <svx/pageitem.hxx>
43 #include <svx/editeng.hxx>
44 #include <svx/svditer.hxx>
45 #include <svx/svdpage.hxx>
46 #include <svx/svdocapt.hxx>
47 #include <sfx2/app.hxx>
48 #include <sfx2/objsh.hxx>
49 #include <svtools/poolcach.hxx>
50 #include <svtools/saveopt.hxx>
51 #include <svtools/zforlist.hxx>
52 #include <unotools/charclass.hxx>
53 #include <unotools/transliterationwrapper.hxx>
54 #include <tools/tenccvt.hxx>
56 #include <com/sun/star/text/WritingMode2.hpp>
57 #include <com/sun/star/sheet/TablePageBreakData.hpp>
59 #include "document.hxx"
60 #include "table.hxx"
61 #include "attrib.hxx"
62 #include "attarray.hxx"
63 #include "markarr.hxx"
64 #include "patattr.hxx"
65 #include "rangenam.hxx"
66 #include "poolhelp.hxx"
67 #include "docpool.hxx"
68 #include "stlpool.hxx"
69 #include "stlsheet.hxx"
70 #include "globstr.hrc"
71 #include "rechead.hxx"
72 #include "dbcolect.hxx"
73 #include "pivot.hxx"
74 #include "chartlis.hxx"
75 #include "rangelst.hxx"
76 #include "markdata.hxx"
77 #include "drwlayer.hxx"
78 #include "conditio.hxx"
79 #include "validat.hxx"
80 #include "prnsave.hxx"
81 #include "chgtrack.hxx"
82 #include "sc.hrc"
83 #include "scresid.hxx"
84 #include "hints.hxx"
85 #include "detdata.hxx"
86 #include "cell.hxx"
87 #include "dpobject.hxx"
88 #include "detfunc.hxx" // for UpdateAllComments
89 #include "scmod.hxx"
90 #include "dociter.hxx"
91 #include "progress.hxx"
92 #include "autonamecache.hxx"
93 #include "bcaslot.hxx"
94 #include "postit.hxx"
95 #include "externalrefmgr.hxx"
96 #include "tabprotection.hxx"
97 #include "clipparam.hxx"
98 #include <basic/basmgr.hxx>
99 #include <com/sun/star/container/XContainer.hpp>
101 #include <map>
102 #include <limits>
104 using namespace ::com::sun::star;
106 namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
107 using ::com::sun::star::uno::Sequence;
108 using ::com::sun::star::sheet::TablePageBreakData;
109 using ::std::set;
111 struct ScDefaultAttr
113 const ScPatternAttr* pAttr;
114 SCROW nFirst;
115 SCSIZE nCount;
116 ScDefaultAttr(const ScPatternAttr* pPatAttr) : pAttr(pPatAttr), nFirst(0), nCount(0) {}
119 struct ScLessDefaultAttr
121 sal_Bool operator() (const ScDefaultAttr& rValue1, const ScDefaultAttr& rValue2) const
123 return rValue1.pAttr < rValue2.pAttr;
127 typedef std::set<ScDefaultAttr, ScLessDefaultAttr> ScDefaultAttrSet;
129 void ScDocument::MakeTable( SCTAB nTab,bool _bNeedsNameCheck )
131 if ( ValidTab(nTab) && !pTab[nTab] )
133 String aString = ScGlobal::GetRscString(STR_TABLE_DEF); //"Tabelle"
134 aString += String::CreateFromInt32(nTab+1);
135 if ( _bNeedsNameCheck )
136 CreateValidTabName( aString ); // keine doppelten
138 pTab[nTab] = new ScTable(this, nTab, aString);
139 ++nMaxTableNumber;
144 BOOL ScDocument::HasTable( SCTAB nTab ) const
146 if (VALIDTAB(nTab))
147 if (pTab[nTab])
148 return TRUE;
150 return FALSE;
154 BOOL ScDocument::GetName( SCTAB nTab, String& rName ) const
156 if (VALIDTAB(nTab))
157 if (pTab[nTab])
159 pTab[nTab]->GetName( rName );
160 return TRUE;
162 rName.Erase();
163 return FALSE;
166 BOOL ScDocument::SetCodeName( SCTAB nTab, String& rName )
168 if (VALIDTAB(nTab))
170 if (pTab[nTab])
172 pTab[nTab]->SetCodeName( rName );
173 return TRUE;
176 OSL_TRACE( "**** can't set code name %s", rtl::OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr() );
177 return FALSE;
180 BOOL ScDocument::GetCodeName( SCTAB nTab, String& rName ) const
182 if (VALIDTAB(nTab))
183 if (pTab[nTab])
185 pTab[nTab]->GetCodeName( rName );
186 return TRUE;
188 rName.Erase();
189 return FALSE;
193 BOOL ScDocument::GetTable( const String& rName, SCTAB& rTab ) const
195 String aUpperName = rName;
196 ScGlobal::pCharClass->toUpper(aUpperName);
198 for (SCTAB i=0; i<=MAXTAB; i++)
199 if (pTab[i])
201 if ( pTab[i]->GetUpperName() == aUpperName )
203 rTab = i;
204 return TRUE;
207 rTab = 0;
208 return FALSE;
212 BOOL ScDocument::ValidTabName( const String& rName ) const
214 xub_StrLen nLen = rName.Len();
215 if (!nLen)
216 return false;
218 #if 1
219 // Restrict sheet names to what Excel accepts.
220 /* TODO: We may want to remove this restriction for full ODFF compliance.
221 * Merely loading and calculating ODF documents using these characters in
222 * sheet names is not affected by this, but all sheet name editing and
223 * copying functionality is, maybe falling back to "Sheet4" or similar. */
224 for (xub_StrLen i = 0; i < nLen; ++i)
226 const sal_Unicode c = rName.GetChar(i);
227 switch (c)
229 case ':':
230 case '\\':
231 case '/':
232 case '?':
233 case '*':
234 case '[':
235 case ']':
236 // these characters are not allowed to match XL's convention.
237 return false;
238 case '\'':
239 if (i == 0 || i == nLen - 1)
240 // single quote is not allowed at the first or last
241 // character position.
242 return false;
243 break;
246 #endif
248 return true;
252 BOOL ScDocument::ValidNewTabName( const String& rName ) const
254 BOOL bValid = ValidTabName(rName);
255 for (SCTAB i=0; (i<=MAXTAB) && bValid; i++)
256 if (pTab[i])
258 String aOldName;
259 pTab[i]->GetName(aOldName);
260 bValid = !ScGlobal::GetpTransliteration()->isEqual( rName, aOldName );
262 return bValid;
266 void ScDocument::CreateValidTabName(String& rName) const
268 if ( !ValidTabName(rName) )
270 // neu erzeugen
272 const String aStrTable( ScResId(SCSTR_TABLE) );
273 BOOL bOk = FALSE;
275 // vorneweg testen, ob der Prefix als gueltig erkannt wird
276 // wenn nicht, nur doppelte vermeiden
277 BOOL bPrefix = ValidTabName( aStrTable );
278 DBG_ASSERT(bPrefix, "ungueltiger Tabellenname");
279 SCTAB nDummy;
281 SCTAB nLoops = 0; // "zur Sicherheit"
282 for ( SCTAB i = nMaxTableNumber+1; !bOk && nLoops <= MAXTAB; i++ )
284 rName = aStrTable;
285 rName += String::CreateFromInt32(i);
286 if (bPrefix)
287 bOk = ValidNewTabName( rName );
288 else
289 bOk = !GetTable( rName, nDummy );
290 ++nLoops;
293 DBG_ASSERT(bOk, "kein gueltiger Tabellenname gefunden");
294 if ( !bOk )
295 rName = aStrTable;
297 else
299 // uebergebenen Namen ueberpruefen
301 if ( !ValidNewTabName(rName) )
303 SCTAB i = 1;
304 String aName;
307 i++;
308 aName = rName;
309 aName += '_';
310 aName += String::CreateFromInt32(static_cast<sal_Int32>(i));
312 while (!ValidNewTabName(aName) && (i < MAXTAB+1));
313 rName = aName;
319 BOOL ScDocument::InsertTab( SCTAB nPos, const String& rName,
320 BOOL bExternalDocument )
322 SCTAB nTabCount = GetTableCount();
323 BOOL bValid = ValidTab(nTabCount);
324 if ( !bExternalDocument ) // sonst rName == "'Doc'!Tab", vorher pruefen
325 bValid = (bValid && ValidNewTabName(rName));
326 if (bValid)
328 if (nPos == SC_TAB_APPEND || nPos == nTabCount)
330 pTab[nTabCount] = new ScTable(this, nTabCount, rName);
331 pTab[nTabCount]->SetCodeName( rName );
332 ++nMaxTableNumber;
333 if ( bExternalDocument )
334 pTab[nTabCount]->SetVisible( FALSE );
336 else
338 if (VALIDTAB(nPos) && (nPos < nTabCount))
340 ScRange aRange( 0,0,nPos, MAXCOL,MAXROW,MAXTAB );
341 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
342 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
343 pRangeName->UpdateTabRef( nPos, 1 );
344 pDBCollection->UpdateReference(
345 URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
346 if (pDPCollection)
347 pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
348 if (pDetOpList)
349 pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,1 );
350 UpdateChartRef( URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
351 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,1 );
352 if ( pUnoBroadcaster )
353 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,1 ) );
355 SCTAB i;
356 for (i = 0; i <= MAXTAB; i++)
357 if (pTab[i])
358 pTab[i]->UpdateInsertTab(nPos);
360 for (i = nTabCount; i > nPos; i--)
362 pTab[i] = pTab[i - 1];
365 pTab[nPos] = new ScTable(this, nPos, rName);
366 pTab[nPos]->SetCodeName( rName );
367 ++nMaxTableNumber;
369 // UpdateBroadcastAreas must be called between UpdateInsertTab,
370 // which ends listening, and StartAllListeners, to not modify
371 // areas that are to be inserted by starting listeners.
372 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,1);
373 for (i = 0; i <= MAXTAB; i++)
374 if (pTab[i])
375 pTab[i]->UpdateCompile();
376 for (i = 0; i <= MAXTAB; i++)
377 if (pTab[i])
378 pTab[i]->StartAllListeners();
380 // update conditional formats after table is inserted
381 if ( pCondFormList )
382 pCondFormList->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
383 if ( pValidationList )
384 pValidationList->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
385 // #81844# sheet names of references are not valid until sheet is inserted
386 if ( pChartListenerCollection )
387 pChartListenerCollection->UpdateScheduledSeriesRanges();
389 // Update cells containing external references.
390 if (pExternalRefMgr.get())
391 pExternalRefMgr->updateRefInsertTable(nPos);
393 SetDirty();
394 bValid = TRUE;
396 else
397 bValid = FALSE;
400 return bValid;
404 BOOL ScDocument::DeleteTab( SCTAB nTab, ScDocument* pRefUndoDoc )
406 BOOL bValid = FALSE;
407 if (VALIDTAB(nTab))
409 if (pTab[nTab])
411 SCTAB nTabCount = GetTableCount();
412 if (nTabCount > 1)
414 BOOL bOldAutoCalc = GetAutoCalc();
415 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
416 ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTab );
417 DelBroadcastAreasInRange( aRange );
419 // #i8180# remove database ranges etc. that are on the deleted tab
420 // (restored in undo with ScRefUndoData)
422 xColNameRanges->DeleteOnTab( nTab );
423 xRowNameRanges->DeleteOnTab( nTab );
424 pDBCollection->DeleteOnTab( nTab );
425 if (pDPCollection)
426 pDPCollection->DeleteOnTab( nTab );
427 if (pDetOpList)
428 pDetOpList->DeleteOnTab( nTab );
429 DeleteAreaLinksOnTab( nTab );
431 // normal reference update
433 aRange.aEnd.SetTab( MAXTAB );
434 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
435 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
436 pRangeName->UpdateTabRef( nTab, 2 );
437 pDBCollection->UpdateReference(
438 URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1 );
439 if (pDPCollection)
440 pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
441 if (pDetOpList)
442 pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1 );
443 UpdateChartRef( URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1 );
444 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1 );
445 if ( pCondFormList )
446 pCondFormList->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
447 if ( pValidationList )
448 pValidationList->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
449 if ( pUnoBroadcaster )
450 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1 ) );
452 SCTAB i;
453 for (i=0; i<=MAXTAB; i++)
454 if (pTab[i])
455 pTab[i]->UpdateDeleteTab(nTab,FALSE,
456 pRefUndoDoc ? pRefUndoDoc->pTab[i] : 0);
457 delete pTab[nTab];
458 for (i=nTab + 1; i < nTabCount; i++)
460 pTab[i - 1] = pTab[i];
463 pTab[nTabCount - 1] = NULL;
464 --nMaxTableNumber;
465 // UpdateBroadcastAreas must be called between UpdateDeleteTab,
466 // which ends listening, and StartAllListeners, to not modify
467 // areas that are to be inserted by starting listeners.
468 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1);
469 for (i = 0; i <= MAXTAB; i++)
470 if (pTab[i])
471 pTab[i]->UpdateCompile();
472 // Excel-Filter loescht einige Tables waehrend des Ladens,
473 // Listener werden erst nach dem Laden aufgesetzt
474 if ( !bInsertingFromOtherDoc )
476 for (i = 0; i <= MAXTAB; i++)
477 if (pTab[i])
478 pTab[i]->StartAllListeners();
479 SetDirty();
481 // #81844# sheet names of references are not valid until sheet is deleted
482 pChartListenerCollection->UpdateScheduledSeriesRanges();
485 // Update cells containing external references.
486 if (pExternalRefMgr.get())
487 pExternalRefMgr->updateRefDeleteTable(nTab);
489 SetAutoCalc( bOldAutoCalc );
490 bValid = TRUE;
494 return bValid;
498 BOOL ScDocument::RenameTab( SCTAB nTab, const String& rName, BOOL /* bUpdateRef */,
499 BOOL bExternalDocument )
501 BOOL bValid = FALSE;
502 SCTAB i;
503 if VALIDTAB(nTab)
504 if (pTab[nTab])
506 if ( bExternalDocument )
507 bValid = TRUE; // zusammengesetzter Name
508 else
509 bValid = ValidTabName(rName);
510 for (i=0; (i<=MAXTAB) && bValid; i++)
511 if (pTab[i] && (i != nTab))
513 String aOldName;
514 pTab[i]->GetName(aOldName);
515 bValid = !ScGlobal::GetpTransliteration()->isEqual( rName, aOldName );
517 if (bValid)
519 // #i75258# update charts before renaming, so they can get their live data objects.
520 // Once the charts are live, the sheet can be renamed without problems.
521 if ( pChartListenerCollection )
522 pChartListenerCollection->UpdateChartsContainingTab( nTab );
523 pTab[nTab]->SetName(rName);
526 return bValid;
530 void ScDocument::SetVisible( SCTAB nTab, BOOL bVisible )
532 if (VALIDTAB(nTab))
533 if (pTab[nTab])
534 pTab[nTab]->SetVisible(bVisible);
538 BOOL ScDocument::IsVisible( SCTAB nTab ) const
540 if (VALIDTAB(nTab))
541 if (pTab[nTab])
542 return pTab[nTab]->IsVisible();
544 return FALSE;
548 BOOL ScDocument::IsStreamValid( SCTAB nTab ) const
550 if ( ValidTab(nTab) && pTab[nTab] )
551 return pTab[nTab]->IsStreamValid();
553 return FALSE;
557 void ScDocument::SetStreamValid( SCTAB nTab, BOOL bSet, BOOL bIgnoreLock )
559 if ( ValidTab(nTab) && pTab[nTab] )
560 pTab[nTab]->SetStreamValid( bSet, bIgnoreLock );
564 void ScDocument::LockStreamValid( bool bLock )
566 mbStreamValidLocked = bLock;
570 BOOL ScDocument::IsPendingRowHeights( SCTAB nTab ) const
572 if ( ValidTab(nTab) && pTab[nTab] )
573 return pTab[nTab]->IsPendingRowHeights();
575 return FALSE;
579 void ScDocument::SetPendingRowHeights( SCTAB nTab, BOOL bSet )
581 if ( ValidTab(nTab) && pTab[nTab] )
582 pTab[nTab]->SetPendingRowHeights( bSet );
586 void ScDocument::SetLayoutRTL( SCTAB nTab, BOOL bRTL )
588 if ( ValidTab(nTab) && pTab[nTab] )
590 if ( bImportingXML )
592 // #i57869# only set the LoadingRTL flag, the real setting (including mirroring)
593 // is applied in SetImportingXML(FALSE). This is so the shapes can be loaded in
594 // normal LTR mode.
596 pTab[nTab]->SetLoadingRTL( bRTL );
597 return;
600 pTab[nTab]->SetLayoutRTL( bRTL ); // only sets the flag
601 pTab[nTab]->SetDrawPageSize();
603 // mirror existing objects:
605 if (pDrawLayer)
607 SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
608 DBG_ASSERT(pPage,"Page ?");
609 if (pPage)
611 SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
612 SdrObject* pObject = aIter.Next();
613 while (pObject)
615 // objects with ScDrawObjData are re-positioned in SetPageSize,
616 // don't mirror again
617 ScDrawObjData* pData = ScDrawLayer::GetObjData( pObject );
618 if ( !pData )
619 pDrawLayer->MirrorRTL( pObject );
621 pObject->SetContextWritingMode( bRTL ? WritingMode2::RL_TB : WritingMode2::LR_TB );
623 pObject = aIter.Next();
631 BOOL ScDocument::IsLayoutRTL( SCTAB nTab ) const
633 if ( ValidTab(nTab) && pTab[nTab] )
634 return pTab[nTab]->IsLayoutRTL();
636 return FALSE;
640 BOOL ScDocument::IsNegativePage( SCTAB nTab ) const
642 // Negative page area is always used for RTL layout.
643 // The separate method is used to find all RTL handling of drawing objects.
644 return IsLayoutRTL( nTab );
648 /* ----------------------------------------------------------------------------
649 benutzten Bereich suchen:
651 GetCellArea - nur Daten
652 GetTableArea - Daten / Attribute
653 GetPrintArea - beruecksichtigt auch Zeichenobjekte,
654 streicht Attribute bis ganz rechts / unten
655 ---------------------------------------------------------------------------- */
658 BOOL ScDocument::GetCellArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
660 if (VALIDTAB(nTab))
661 if (pTab[nTab])
662 return pTab[nTab]->GetCellArea( rEndCol, rEndRow );
664 rEndCol = 0;
665 rEndRow = 0;
666 return FALSE;
670 BOOL ScDocument::GetTableArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
672 if (VALIDTAB(nTab))
673 if (pTab[nTab])
674 return pTab[nTab]->GetTableArea( rEndCol, rEndRow );
676 rEndCol = 0;
677 rEndRow = 0;
678 return FALSE;
681 bool ScDocument::ShrinkToDataArea(SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow) const
683 if (!ValidTab(nTab) || !pTab[nTab])
684 return false;
686 SCCOL nCol1, nCol2;
687 SCROW nRow1, nRow2;
688 pTab[nTab]->GetFirstDataPos(nCol1, nRow1);
689 pTab[nTab]->GetLastDataPos(nCol2, nRow2);
691 if (nCol1 > nCol2 || nRow1 > nRow2)
692 // invalid range.
693 return false;
695 // Make sure the area only shrinks, and doesn't grow.
696 if (rStartCol < nCol1)
697 rStartCol = nCol1;
698 if (nCol2 < rEndCol)
699 rEndCol = nCol2;
700 if (rStartRow < nRow1)
701 rStartRow = nRow1;
702 if (nRow2 < rEndRow)
703 rEndRow = nRow2;
705 return true; // success!
708 // zusammenhaengender Bereich
710 void ScDocument::GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
711 SCCOL& rEndCol, SCROW& rEndRow, BOOL bIncludeOld ) const
713 if (VALIDTAB(nTab))
714 if (pTab[nTab])
715 pTab[nTab]->GetDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bIncludeOld );
719 void ScDocument::LimitChartArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
720 SCCOL& rEndCol, SCROW& rEndRow )
722 if (VALIDTAB(nTab))
723 if (pTab[nTab])
724 pTab[nTab]->LimitChartArea( rStartCol, rStartRow, rEndCol, rEndRow );
728 void ScDocument::LimitChartIfAll( ScRangeListRef& rRangeList )
730 ScRangeListRef aNew = new ScRangeList;
731 if (rRangeList.Is())
733 ULONG nCount = rRangeList->Count();
734 for (ULONG i=0; i<nCount; i++)
736 ScRange aRange(*rRangeList->GetObject( i ));
737 if ( ( aRange.aStart.Col() == 0 && aRange.aEnd.Col() == MAXCOL ) ||
738 ( aRange.aStart.Row() == 0 && aRange.aEnd.Row() == MAXROW ) )
740 SCCOL nStartCol = aRange.aStart.Col();
741 SCROW nStartRow = aRange.aStart.Row();
742 SCCOL nEndCol = aRange.aEnd.Col();
743 SCROW nEndRow = aRange.aEnd.Row();
744 SCTAB nTab = aRange.aStart.Tab();
745 if (pTab[nTab])
746 pTab[nTab]->LimitChartArea(nStartCol, nStartRow, nEndCol, nEndRow);
747 aRange.aStart.SetCol( nStartCol );
748 aRange.aStart.SetRow( nStartRow );
749 aRange.aEnd.SetCol( nEndCol );
750 aRange.aEnd.SetRow( nEndRow );
752 aNew->Append(aRange);
755 else
757 DBG_ERROR("LimitChartIfAll: Ref==0");
759 rRangeList = aNew;
763 void lcl_GetFirstTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark )
765 // without ScMarkData, leave start/end unchanged
766 if ( pTabMark )
768 for (SCTAB nTab=0; nTab<=MAXTAB; ++nTab)
769 if (pTabMark->GetTableSelect(nTab))
771 // find first range of consecutive selected sheets
772 rTabRangeStart = nTab;
773 while ( nTab+1 <= MAXTAB && pTabMark->GetTableSelect(nTab+1) )
774 ++nTab;
775 rTabRangeEnd = nTab;
776 return;
781 bool lcl_GetNextTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark )
783 if ( pTabMark )
785 // find next range of consecutive selected sheets after rTabRangeEnd
786 for (SCTAB nTab=rTabRangeEnd+1; nTab<=MAXTAB; ++nTab)
787 if (pTabMark->GetTableSelect(nTab))
789 rTabRangeStart = nTab;
790 while ( nTab+1 <= MAXTAB && pTabMark->GetTableSelect(nTab+1) )
791 ++nTab;
792 rTabRangeEnd = nTab;
793 return true;
796 return false;
800 BOOL ScDocument::CanInsertRow( const ScRange& rRange ) const
802 SCCOL nStartCol = rRange.aStart.Col();
803 SCROW nStartRow = rRange.aStart.Row();
804 SCTAB nStartTab = rRange.aStart.Tab();
805 SCCOL nEndCol = rRange.aEnd.Col();
806 SCROW nEndRow = rRange.aEnd.Row();
807 SCTAB nEndTab = rRange.aEnd.Tab();
808 PutInOrder( nStartCol, nEndCol );
809 PutInOrder( nStartRow, nEndRow );
810 PutInOrder( nStartTab, nEndTab );
811 SCSIZE nSize = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
813 BOOL bTest = TRUE;
814 for (SCTAB i=nStartTab; i<=nEndTab && bTest; i++)
815 if (pTab[i])
816 bTest &= pTab[i]->TestInsertRow( nStartCol, nEndCol, nSize );
818 return bTest;
822 BOOL ScDocument::InsertRow( SCCOL nStartCol, SCTAB nStartTab,
823 SCCOL nEndCol, SCTAB nEndTab,
824 SCROW nStartRow, SCSIZE nSize, ScDocument* pRefUndoDoc,
825 const ScMarkData* pTabMark )
827 SCTAB i;
829 PutInOrder( nStartCol, nEndCol );
830 PutInOrder( nStartTab, nEndTab );
831 if ( pTabMark )
833 nStartTab = 0;
834 nEndTab = MAXTAB;
837 BOOL bTest = TRUE;
838 BOOL bRet = FALSE;
839 BOOL bOldAutoCalc = GetAutoCalc();
840 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
841 for ( i = nStartTab; i <= nEndTab && bTest; i++)
842 if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
843 bTest &= pTab[i]->TestInsertRow( nStartCol, nEndCol, nSize );
844 if (bTest)
846 // UpdateBroadcastAreas muss vor UpdateReference gerufen werden, damit nicht
847 // Eintraege verschoben werden, die erst bei UpdateReference neu erzeugt werden
849 // handle chunks of consecutive selected sheets together
850 SCTAB nTabRangeStart = nStartTab;
851 SCTAB nTabRangeEnd = nEndTab;
852 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
855 UpdateBroadcastAreas( URM_INSDEL, ScRange(
856 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
857 ScAddress( nEndCol, MAXROW, nTabRangeEnd )), 0, static_cast<SCsROW>(nSize), 0 );
859 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
861 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
864 UpdateReference( URM_INSDEL, nStartCol, nStartRow, nTabRangeStart,
865 nEndCol, MAXROW, nTabRangeEnd,
866 0, static_cast<SCsROW>(nSize), 0, pRefUndoDoc, FALSE ); // without drawing objects
868 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
870 for (i=nStartTab; i<=nEndTab; i++)
871 if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
872 pTab[i]->InsertRow( nStartCol, nEndCol, nStartRow, nSize );
874 // #82991# UpdateRef for drawing layer must be after inserting,
875 // when the new row heights are known.
876 for (i=nStartTab; i<=nEndTab; i++)
877 if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
878 pTab[i]->UpdateDrawRef( URM_INSDEL,
879 nStartCol, nStartRow, nStartTab, nEndCol, MAXROW, nEndTab,
880 0, static_cast<SCsROW>(nSize), 0 );
882 if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
883 { // durch Restaurierung von Referenzen auf geloeschte Bereiche ist
884 // ein neues Listening faellig, bisherige Listener wurden in
885 // FormulaCell UpdateReference abgehaengt
886 StartAllListeners();
888 else
889 { // Listeners have been removed in UpdateReference
890 for (i=0; i<=MAXTAB; i++)
891 if (pTab[i])
892 pTab[i]->StartNeededListeners();
893 // #69592# at least all cells using range names pointing relative
894 // to the moved range must recalculate
895 for (i=0; i<=MAXTAB; i++)
896 if (pTab[i])
897 pTab[i]->SetRelNameDirty();
899 bRet = TRUE;
901 SetAutoCalc( bOldAutoCalc );
902 if ( bRet )
903 pChartListenerCollection->UpdateDirtyCharts();
904 return bRet;
908 BOOL ScDocument::InsertRow( const ScRange& rRange, ScDocument* pRefUndoDoc )
910 return InsertRow( rRange.aStart.Col(), rRange.aStart.Tab(),
911 rRange.aEnd.Col(), rRange.aEnd.Tab(),
912 rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
913 pRefUndoDoc );
917 void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
918 SCCOL nEndCol, SCTAB nEndTab,
919 SCROW nStartRow, SCSIZE nSize,
920 ScDocument* pRefUndoDoc, BOOL* pUndoOutline,
921 const ScMarkData* pTabMark )
923 SCTAB i;
925 PutInOrder( nStartCol, nEndCol );
926 PutInOrder( nStartTab, nEndTab );
927 if ( pTabMark )
929 nStartTab = 0;
930 nEndTab = MAXTAB;
933 BOOL bOldAutoCalc = GetAutoCalc();
934 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
936 // handle chunks of consecutive selected sheets together
937 SCTAB nTabRangeStart = nStartTab;
938 SCTAB nTabRangeEnd = nEndTab;
939 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
942 if ( ValidRow(nStartRow+nSize) )
944 DelBroadcastAreasInRange( ScRange(
945 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
946 ScAddress( nEndCol, nStartRow+nSize-1, nTabRangeEnd ) ) );
947 UpdateBroadcastAreas( URM_INSDEL, ScRange(
948 ScAddress( nStartCol, nStartRow+nSize, nTabRangeStart ),
949 ScAddress( nEndCol, MAXROW, nTabRangeEnd )), 0, -(static_cast<SCsROW>(nSize)), 0 );
951 else
952 DelBroadcastAreasInRange( ScRange(
953 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
954 ScAddress( nEndCol, MAXROW, nTabRangeEnd ) ) );
956 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
958 if ( ValidRow(nStartRow+nSize) )
960 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
963 UpdateReference( URM_INSDEL, nStartCol, nStartRow+nSize, nTabRangeStart,
964 nEndCol, MAXROW, nTabRangeEnd,
965 0, -(static_cast<SCsROW>(nSize)), 0, pRefUndoDoc );
967 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
970 if (pUndoOutline)
971 *pUndoOutline = FALSE;
973 for ( i = nStartTab; i <= nEndTab; i++)
974 if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
975 pTab[i]->DeleteRow( nStartCol, nEndCol, nStartRow, nSize, pUndoOutline );
977 if ( ValidRow(nStartRow+nSize) )
978 { // Listeners have been removed in UpdateReference
979 for (i=0; i<=MAXTAB; i++)
980 if (pTab[i])
981 pTab[i]->StartNeededListeners();
982 // #69592# at least all cells using range names pointing relative to
983 // the moved range must recalculate
984 for (i=0; i<=MAXTAB; i++)
985 if (pTab[i])
986 pTab[i]->SetRelNameDirty();
989 SetAutoCalc( bOldAutoCalc );
990 pChartListenerCollection->UpdateDirtyCharts();
994 void ScDocument::DeleteRow( const ScRange& rRange, ScDocument* pRefUndoDoc, BOOL* pUndoOutline )
996 DeleteRow( rRange.aStart.Col(), rRange.aStart.Tab(),
997 rRange.aEnd.Col(), rRange.aEnd.Tab(),
998 rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
999 pRefUndoDoc, pUndoOutline );
1003 BOOL ScDocument::CanInsertCol( const ScRange& rRange ) const
1005 SCCOL nStartCol = rRange.aStart.Col();
1006 SCROW nStartRow = rRange.aStart.Row();
1007 SCTAB nStartTab = rRange.aStart.Tab();
1008 SCCOL nEndCol = rRange.aEnd.Col();
1009 SCROW nEndRow = rRange.aEnd.Row();
1010 SCTAB nEndTab = rRange.aEnd.Tab();
1011 PutInOrder( nStartCol, nEndCol );
1012 PutInOrder( nStartRow, nEndRow );
1013 PutInOrder( nStartTab, nEndTab );
1014 SCSIZE nSize = static_cast<SCSIZE>(nEndCol - nStartCol + 1);
1016 BOOL bTest = TRUE;
1017 for (SCTAB i=nStartTab; i<=nEndTab && bTest; i++)
1018 if (pTab[i])
1019 bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
1021 return bTest;
1025 BOOL ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
1026 SCROW nEndRow, SCTAB nEndTab,
1027 SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
1028 const ScMarkData* pTabMark )
1030 SCTAB i;
1032 PutInOrder( nStartRow, nEndRow );
1033 PutInOrder( nStartTab, nEndTab );
1034 if ( pTabMark )
1036 nStartTab = 0;
1037 nEndTab = MAXTAB;
1040 BOOL bTest = TRUE;
1041 BOOL bRet = FALSE;
1042 BOOL bOldAutoCalc = GetAutoCalc();
1043 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
1044 for ( i = nStartTab; i <= nEndTab && bTest; i++)
1045 if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1046 bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
1047 if (bTest)
1049 // handle chunks of consecutive selected sheets together
1050 SCTAB nTabRangeStart = nStartTab;
1051 SCTAB nTabRangeEnd = nEndTab;
1052 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
1055 UpdateBroadcastAreas( URM_INSDEL, ScRange(
1056 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1057 ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), static_cast<SCsCOL>(nSize), 0, 0 );
1059 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
1061 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
1064 UpdateReference( URM_INSDEL, nStartCol, nStartRow, nTabRangeStart,
1065 MAXCOL, nEndRow, nTabRangeEnd,
1066 static_cast<SCsCOL>(nSize), 0, 0, pRefUndoDoc );
1068 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
1070 for (i=nStartTab; i<=nEndTab; i++)
1071 if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1072 pTab[i]->InsertCol( nStartCol, nStartRow, nEndRow, nSize );
1074 if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
1075 { // durch Restaurierung von Referenzen auf geloeschte Bereiche ist
1076 // ein neues Listening faellig, bisherige Listener wurden in
1077 // FormulaCell UpdateReference abgehaengt
1078 StartAllListeners();
1080 else
1081 { // Listeners have been removed in UpdateReference
1082 for (i=0; i<=MAXTAB; i++)
1083 if (pTab[i])
1084 pTab[i]->StartNeededListeners();
1085 // #69592# at least all cells using range names pointing relative
1086 // to the moved range must recalculate
1087 for (i=0; i<=MAXTAB; i++)
1088 if (pTab[i])
1089 pTab[i]->SetRelNameDirty();
1091 bRet = TRUE;
1093 SetAutoCalc( bOldAutoCalc );
1094 if ( bRet )
1095 pChartListenerCollection->UpdateDirtyCharts();
1096 return bRet;
1100 BOOL ScDocument::InsertCol( const ScRange& rRange, ScDocument* pRefUndoDoc )
1102 return InsertCol( rRange.aStart.Row(), rRange.aStart.Tab(),
1103 rRange.aEnd.Row(), rRange.aEnd.Tab(),
1104 rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
1105 pRefUndoDoc );
1109 void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTAB nEndTab,
1110 SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
1111 BOOL* pUndoOutline, const ScMarkData* pTabMark )
1113 SCTAB i;
1115 PutInOrder( nStartRow, nEndRow );
1116 PutInOrder( nStartTab, nEndTab );
1117 if ( pTabMark )
1119 nStartTab = 0;
1120 nEndTab = MAXTAB;
1123 BOOL bOldAutoCalc = GetAutoCalc();
1124 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
1126 // handle chunks of consecutive selected sheets together
1127 SCTAB nTabRangeStart = nStartTab;
1128 SCTAB nTabRangeEnd = nEndTab;
1129 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
1132 if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1134 DelBroadcastAreasInRange( ScRange(
1135 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1136 ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize-1), nEndRow, nTabRangeEnd ) ) );
1137 UpdateBroadcastAreas( URM_INSDEL, ScRange(
1138 ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart ),
1139 ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), -static_cast<SCsCOL>(nSize), 0, 0 );
1141 else
1142 DelBroadcastAreasInRange( ScRange(
1143 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1144 ScAddress( MAXCOL, nEndRow, nTabRangeEnd ) ) );
1146 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
1148 if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1150 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
1153 UpdateReference( URM_INSDEL, sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart,
1154 MAXCOL, nEndRow, nTabRangeEnd,
1155 -static_cast<SCsCOL>(nSize), 0, 0, pRefUndoDoc );
1157 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
1160 if (pUndoOutline)
1161 *pUndoOutline = FALSE;
1163 for ( i = nStartTab; i <= nEndTab; i++)
1164 if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1165 pTab[i]->DeleteCol( nStartCol, nStartRow, nEndRow, nSize, pUndoOutline );
1167 if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1168 { // Listeners have been removed in UpdateReference
1169 for (i=0; i<=MAXTAB; i++)
1170 if (pTab[i])
1171 pTab[i]->StartNeededListeners();
1172 // #69592# at least all cells using range names pointing relative to
1173 // the moved range must recalculate
1174 for (i=0; i<=MAXTAB; i++)
1175 if (pTab[i])
1176 pTab[i]->SetRelNameDirty();
1179 SetAutoCalc( bOldAutoCalc );
1180 pChartListenerCollection->UpdateDirtyCharts();
1184 void ScDocument::DeleteCol( const ScRange& rRange, ScDocument* pRefUndoDoc, BOOL* pUndoOutline )
1186 DeleteCol( rRange.aStart.Row(), rRange.aStart.Tab(),
1187 rRange.aEnd.Row(), rRange.aEnd.Tab(),
1188 rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
1189 pRefUndoDoc, pUndoOutline );
1193 // fuer Area-Links: Zellen einuegen/loeschen, wenn sich der Bereich veraendert
1194 // (ohne Paint)
1197 void lcl_GetInsDelRanges( const ScRange& rOld, const ScRange& rNew,
1198 ScRange& rColRange, BOOL& rInsCol, BOOL& rDelCol,
1199 ScRange& rRowRange, BOOL& rInsRow, BOOL& rDelRow )
1201 DBG_ASSERT( rOld.aStart == rNew.aStart, "FitBlock: Anfang unterschiedlich" );
1203 rInsCol = rDelCol = rInsRow = rDelRow = FALSE;
1205 SCCOL nStartX = rOld.aStart.Col();
1206 SCROW nStartY = rOld.aStart.Row();
1207 SCCOL nOldEndX = rOld.aEnd.Col();
1208 SCROW nOldEndY = rOld.aEnd.Row();
1209 SCCOL nNewEndX = rNew.aEnd.Col();
1210 SCROW nNewEndY = rNew.aEnd.Row();
1211 SCTAB nTab = rOld.aStart.Tab();
1213 // wenn es mehr Zeilen werden, werden Spalten auf der alten Hoehe eingefuegt/geloescht
1214 BOOL bGrowY = ( nNewEndY > nOldEndY );
1215 SCROW nColEndY = bGrowY ? nOldEndY : nNewEndY;
1216 SCCOL nRowEndX = bGrowY ? nNewEndX : nOldEndX;
1218 // Spalten
1220 if ( nNewEndX > nOldEndX ) // Spalten einfuegen
1222 rColRange = ScRange( nOldEndX+1, nStartY, nTab, nNewEndX, nColEndY, nTab );
1223 rInsCol = TRUE;
1225 else if ( nNewEndX < nOldEndX ) // Spalten loeschen
1227 rColRange = ScRange( nNewEndX+1, nStartY, nTab, nOldEndX, nColEndY, nTab );
1228 rDelCol = TRUE;
1231 // Zeilen
1233 if ( nNewEndY > nOldEndY ) // Zeilen einfuegen
1235 rRowRange = ScRange( nStartX, nOldEndY+1, nTab, nRowEndX, nNewEndY, nTab );
1236 rInsRow = TRUE;
1238 else if ( nNewEndY < nOldEndY ) // Zeilen loeschen
1240 rRowRange = ScRange( nStartX, nNewEndY+1, nTab, nRowEndX, nOldEndY, nTab );
1241 rDelRow = TRUE;
1246 BOOL ScDocument::HasPartOfMerged( const ScRange& rRange )
1248 BOOL bPart = FALSE;
1249 SCTAB nTab = rRange.aStart.Tab();
1251 SCCOL nStartX = rRange.aStart.Col();
1252 SCROW nStartY = rRange.aStart.Row();
1253 SCCOL nEndX = rRange.aEnd.Col();
1254 SCROW nEndY = rRange.aEnd.Row();
1256 if (HasAttrib( nStartX, nStartY, nTab, nEndX, nEndY, nTab,
1257 HASATTR_MERGED | HASATTR_OVERLAPPED ))
1259 ExtendMerge( nStartX, nStartY, nEndX, nEndY, nTab );
1260 ExtendOverlapped( nStartX, nStartY, nEndX, nEndY, nTab );
1262 bPart = ( nStartX != rRange.aStart.Col() || nEndX != rRange.aEnd.Col() ||
1263 nStartY != rRange.aStart.Row() || nEndY != rRange.aEnd.Row() );
1265 return bPart;
1269 BOOL ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
1271 if ( rOld == rNew )
1272 return TRUE;
1274 BOOL bOk = TRUE;
1275 BOOL bInsCol,bDelCol,bInsRow,bDelRow;
1276 ScRange aColRange,aRowRange;
1277 lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
1279 if ( bInsCol && !CanInsertCol( aColRange ) ) // Zellen am Rand ?
1280 bOk = FALSE;
1281 if ( bInsRow && !CanInsertRow( aRowRange ) ) // Zellen am Rand ?
1282 bOk = FALSE;
1284 if ( bInsCol || bDelCol )
1286 aColRange.aEnd.SetCol(MAXCOL);
1287 if ( HasPartOfMerged(aColRange) )
1288 bOk = FALSE;
1290 if ( bInsRow || bDelRow )
1292 aRowRange.aEnd.SetRow(MAXROW);
1293 if ( HasPartOfMerged(aRowRange) )
1294 bOk = FALSE;
1297 return bOk;
1301 void ScDocument::FitBlock( const ScRange& rOld, const ScRange& rNew, BOOL bClear )
1303 if (bClear)
1304 DeleteAreaTab( rOld, IDF_ALL );
1306 BOOL bInsCol,bDelCol,bInsRow,bDelRow;
1307 ScRange aColRange,aRowRange;
1308 lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
1310 if ( bInsCol )
1311 InsertCol( aColRange ); // Spalten zuerst einfuegen
1312 if ( bInsRow )
1313 InsertRow( aRowRange );
1315 if ( bDelRow )
1316 DeleteRow( aRowRange ); // Zeilen zuerst loeschen
1317 if ( bDelCol )
1318 DeleteCol( aColRange );
1320 // Referenzen um eingefuegte Zeilen erweitern
1322 if ( bInsCol || bInsRow )
1324 ScRange aGrowSource = rOld;
1325 aGrowSource.aEnd.SetCol(Min( rOld.aEnd.Col(), rNew.aEnd.Col() ));
1326 aGrowSource.aEnd.SetRow(Min( rOld.aEnd.Row(), rNew.aEnd.Row() ));
1327 SCCOL nGrowX = bInsCol ? ( rNew.aEnd.Col() - rOld.aEnd.Col() ) : 0;
1328 SCROW nGrowY = bInsRow ? ( rNew.aEnd.Row() - rOld.aEnd.Row() ) : 0;
1329 UpdateGrow( aGrowSource, nGrowX, nGrowY );
1334 void ScDocument::DeleteArea(SCCOL nCol1, SCROW nRow1,
1335 SCCOL nCol2, SCROW nRow2,
1336 const ScMarkData& rMark, USHORT nDelFlag)
1338 PutInOrder( nCol1, nCol2 );
1339 PutInOrder( nRow1, nRow2 );
1340 BOOL bOldAutoCalc = GetAutoCalc();
1341 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
1342 for (SCTAB i = 0; i <= MAXTAB; i++)
1343 if (pTab[i])
1344 if ( rMark.GetTableSelect(i) || bIsUndo )
1345 pTab[i]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
1346 SetAutoCalc( bOldAutoCalc );
1350 void ScDocument::DeleteAreaTab(SCCOL nCol1, SCROW nRow1,
1351 SCCOL nCol2, SCROW nRow2,
1352 SCTAB nTab, USHORT nDelFlag)
1354 PutInOrder( nCol1, nCol2 );
1355 PutInOrder( nRow1, nRow2 );
1356 if ( VALIDTAB(nTab) && pTab[nTab] )
1358 BOOL bOldAutoCalc = GetAutoCalc();
1359 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
1360 pTab[nTab]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
1361 SetAutoCalc( bOldAutoCalc );
1366 void ScDocument::DeleteAreaTab( const ScRange& rRange, USHORT nDelFlag )
1368 for ( SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); nTab++ )
1369 DeleteAreaTab( rRange.aStart.Col(), rRange.aStart.Row(),
1370 rRange.aEnd.Col(), rRange.aEnd.Row(),
1371 nTab, nDelFlag );
1375 void ScDocument::InitUndoSelected( ScDocument* pSrcDoc, const ScMarkData& rTabSelection,
1376 BOOL bColInfo, BOOL bRowInfo )
1378 if (bIsUndo)
1380 Clear();
1382 xPoolHelper = pSrcDoc->xPoolHelper;
1384 String aString;
1385 for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
1386 if ( rTabSelection.GetTableSelect( nTab ) )
1388 pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1389 nMaxTableNumber = nTab + 1;
1392 else
1394 DBG_ERROR("InitUndo");
1399 void ScDocument::InitUndo( ScDocument* pSrcDoc, SCTAB nTab1, SCTAB nTab2,
1400 BOOL bColInfo, BOOL bRowInfo )
1402 if (bIsUndo)
1404 Clear();
1406 xPoolHelper = pSrcDoc->xPoolHelper;
1408 String aString;
1409 for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
1410 pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1412 nMaxTableNumber = nTab2 + 1;
1414 else
1416 DBG_ERROR("InitUndo");
1421 void ScDocument::AddUndoTab( SCTAB nTab1, SCTAB nTab2, BOOL bColInfo, BOOL bRowInfo )
1423 if (bIsUndo)
1425 String aString;
1426 for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
1427 if (!pTab[nTab])
1428 pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
1430 if ( nMaxTableNumber <= nTab2 )
1431 nMaxTableNumber = nTab2 + 1;
1433 else
1435 DBG_ERROR("InitUndo");
1440 void ScDocument::SetCutMode( BOOL bVal )
1442 if (bIsClip)
1443 GetClipParam().mbCutMode = bVal;
1444 else
1446 DBG_ERROR("SetCutMode without bIsClip");
1451 BOOL ScDocument::IsCutMode()
1453 if (bIsClip)
1454 return GetClipParam().mbCutMode;
1455 else
1457 DBG_ERROR("IsCutMode ohne bIsClip");
1458 return FALSE;
1463 void ScDocument::CopyToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1464 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1465 USHORT nFlags, BOOL bOnlyMarked, ScDocument* pDestDoc,
1466 const ScMarkData* pMarks, BOOL bColRowFlags )
1468 PutInOrder( nCol1, nCol2 );
1469 PutInOrder( nRow1, nRow2 );
1470 PutInOrder( nTab1, nTab2 );
1471 if( !pDestDoc->aDocName.Len() )
1472 pDestDoc->aDocName = aDocName;
1473 if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
1475 BOOL bOldAutoCalc = pDestDoc->GetAutoCalc();
1476 pDestDoc->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
1477 for (SCTAB i = nTab1; i <= nTab2; i++)
1479 if (pTab[i] && pDestDoc->pTab[i])
1480 pTab[i]->CopyToTable( nCol1, nRow1, nCol2, nRow2, nFlags,
1481 bOnlyMarked, pDestDoc->pTab[i], pMarks,
1482 FALSE, bColRowFlags );
1484 pDestDoc->SetAutoCalc( bOldAutoCalc );
1489 void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1490 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1491 USHORT nFlags, BOOL bOnlyMarked, ScDocument* pDestDoc,
1492 const ScMarkData* pMarks)
1494 PutInOrder( nCol1, nCol2 );
1495 PutInOrder( nRow1, nRow2 );
1496 PutInOrder( nTab1, nTab2 );
1497 if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
1499 BOOL bOldAutoCalc = pDestDoc->GetAutoCalc();
1500 pDestDoc->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
1501 if (nTab1 > 0)
1502 CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, FALSE, pDestDoc, pMarks );
1504 for (SCTAB i = nTab1; i <= nTab2; i++)
1506 if (pTab[i] && pDestDoc->pTab[i])
1507 pTab[i]->UndoToTable(nCol1, nRow1, nCol2, nRow2, nFlags,
1508 bOnlyMarked, pDestDoc->pTab[i], pMarks);
1511 if (nTab2 < MAXTAB)
1512 CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA, FALSE, pDestDoc, pMarks );
1513 pDestDoc->SetAutoCalc( bOldAutoCalc );
1518 void ScDocument::CopyToDocument(const ScRange& rRange,
1519 USHORT nFlags, BOOL bOnlyMarked, ScDocument* pDestDoc,
1520 const ScMarkData* pMarks, BOOL bColRowFlags)
1522 ScRange aNewRange = rRange;
1523 aNewRange.Justify();
1525 if( !pDestDoc->aDocName.Len() )
1526 pDestDoc->aDocName = aDocName;
1527 BOOL bOldAutoCalc = pDestDoc->GetAutoCalc();
1528 pDestDoc->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
1529 for (SCTAB i = aNewRange.aStart.Tab(); i <= aNewRange.aEnd.Tab(); i++)
1530 if (pTab[i] && pDestDoc->pTab[i])
1531 pTab[i]->CopyToTable(aNewRange.aStart.Col(), aNewRange.aStart.Row(),
1532 aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
1533 nFlags, bOnlyMarked, pDestDoc->pTab[i],
1534 pMarks, FALSE, bColRowFlags);
1535 pDestDoc->SetAutoCalc( bOldAutoCalc );
1539 void ScDocument::UndoToDocument(const ScRange& rRange,
1540 USHORT nFlags, BOOL bOnlyMarked, ScDocument* pDestDoc,
1541 const ScMarkData* pMarks)
1543 ScRange aNewRange = rRange;
1544 aNewRange.Justify();
1545 SCTAB nTab1 = aNewRange.aStart.Tab();
1546 SCTAB nTab2 = aNewRange.aEnd.Tab();
1548 BOOL bOldAutoCalc = pDestDoc->GetAutoCalc();
1549 pDestDoc->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
1550 if (nTab1 > 0)
1551 CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, FALSE, pDestDoc, pMarks );
1553 for (SCTAB i = nTab1; i <= nTab2; i++)
1555 if (pTab[i] && pDestDoc->pTab[i])
1556 pTab[i]->UndoToTable(aNewRange.aStart.Col(), aNewRange.aStart.Row(),
1557 aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
1558 nFlags, bOnlyMarked, pDestDoc->pTab[i], pMarks);
1561 if (nTab2 < MAXTAB)
1562 CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA, FALSE, pDestDoc, pMarks );
1563 pDestDoc->SetAutoCalc( bOldAutoCalc );
1566 void ScDocument::CopyToClip(const ScClipParam& rClipParam,
1567 ScDocument* pClipDoc, const ScMarkData* pMarks,
1568 bool bAllTabs, bool bKeepScenarioFlags, bool bIncludeObjects, bool bCloneNoteCaptions)
1570 DBG_ASSERT( bAllTabs || pMarks, "CopyToClip: ScMarkData fehlt" );
1572 if (bIsClip)
1573 return;
1575 if (!pClipDoc)
1577 DBG_ERROR("CopyToClip: no ClipDoc");
1578 pClipDoc = SC_MOD()->GetClipDoc();
1581 pClipDoc->aDocName = aDocName;
1582 pClipDoc->SetClipParam(rClipParam);
1583 pClipDoc->ResetClip(this, pMarks);
1585 ScRange aClipRange = rClipParam.getWholeRange();
1586 CopyRangeNamesToClip(pClipDoc, aClipRange, pMarks, bAllTabs);
1588 for (SCTAB i = 0; i <= MAXTAB; ++i)
1590 if (!pTab[i] || !pClipDoc->pTab[i])
1591 continue;
1593 if (pMarks && !pMarks->GetTableSelect(i))
1594 continue;
1596 pTab[i]->CopyToClip(rClipParam.maRanges, pClipDoc->pTab[i], bKeepScenarioFlags, bCloneNoteCaptions);
1598 if (pDrawLayer && bIncludeObjects)
1600 // also copy drawing objects
1601 Rectangle aObjRect = GetMMRect(
1602 aClipRange.aStart.Col(), aClipRange.aStart.Row(), aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i);
1603 pDrawLayer->CopyToClip(pClipDoc, i, aObjRect);
1607 // Make sure to mark overlapped cells.
1608 pClipDoc->ExtendMerge(aClipRange, true);
1611 void ScDocument::CopyTabToClip(SCCOL nCol1, SCROW nRow1,
1612 SCCOL nCol2, SCROW nRow2,
1613 SCTAB nTab, ScDocument* pClipDoc)
1615 if (!bIsClip)
1617 PutInOrder( nCol1, nCol2 );
1618 PutInOrder( nRow1, nRow2 );
1619 if (!pClipDoc)
1621 DBG_ERROR("CopyTabToClip: no ClipDoc");
1622 pClipDoc = SC_MOD()->GetClipDoc();
1625 ScClipParam& rClipParam = pClipDoc->GetClipParam();
1626 pClipDoc->aDocName = aDocName;
1627 rClipParam.maRanges.RemoveAll();
1628 rClipParam.maRanges.Append(ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0));
1629 pClipDoc->ResetClip( this, nTab );
1631 if (pTab[nTab] && pClipDoc->pTab[nTab])
1632 pTab[nTab]->CopyToClip(nCol1, nRow1, nCol2, nRow2, pClipDoc->pTab[nTab], FALSE, TRUE);
1634 pClipDoc->GetClipParam().mbCutMode = false;
1639 void ScDocument::TransposeClip( ScDocument* pTransClip, USHORT nFlags, BOOL bAsLink )
1641 DBG_ASSERT( bIsClip && pTransClip && pTransClip->bIsClip,
1642 "TransposeClip mit falschem Dokument" );
1644 // initialisieren
1645 // -> pTransClip muss vor dem Original-Dokument geloescht werden!
1647 pTransClip->ResetClip(this, (ScMarkData*)NULL); // alle
1649 // Bereiche uebernehmen
1651 pTransClip->pRangeName->FreeAll();
1652 for (USHORT i = 0; i < pRangeName->GetCount(); i++) //! DB-Bereiche Pivot-Bereiche auch !!!
1654 USHORT nIndex = ((ScRangeData*)((*pRangeName)[i]))->GetIndex();
1655 ScRangeData* pData = new ScRangeData(*((*pRangeName)[i]));
1656 if (!pTransClip->pRangeName->Insert(pData))
1657 delete pData;
1658 else
1659 pData->SetIndex(nIndex);
1662 // Daten
1664 ScRange aClipRange = GetClipParam().getWholeRange();
1665 if ( ValidRow(aClipRange.aEnd.Row()-aClipRange.aStart.Row()) )
1667 for (SCTAB i=0; i<=MAXTAB; i++)
1668 if (pTab[i])
1670 DBG_ASSERT( pTransClip->pTab[i], "TransposeClip: Tabelle nicht da" );
1671 pTab[i]->TransposeClip( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
1672 aClipRange.aEnd.Col(), aClipRange.aEnd.Row(),
1673 pTransClip->pTab[i], nFlags, bAsLink );
1675 if ( pDrawLayer && ( nFlags & IDF_OBJECTS ) )
1677 // Drawing objects are copied to the new area without transposing.
1678 // CopyFromClip is used to adjust the objects to the transposed block's
1679 // cell range area.
1680 // (pDrawLayer in the original clipboard document is set only if there
1681 // are drawing objects to copy)
1683 pTransClip->InitDrawLayer();
1684 Rectangle aSourceRect = GetMMRect( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
1685 aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i );
1686 Rectangle aDestRect = pTransClip->GetMMRect( 0, 0,
1687 static_cast<SCCOL>(aClipRange.aEnd.Row() - aClipRange.aStart.Row()),
1688 static_cast<SCROW>(aClipRange.aEnd.Col() - aClipRange.aStart.Col()), i );
1689 pTransClip->pDrawLayer->CopyFromClip( pDrawLayer, i, aSourceRect, ScAddress(0,0,i), aDestRect );
1693 pTransClip->SetClipParam(GetClipParam());
1694 pTransClip->GetClipParam().transpose();
1696 else
1698 DBG_ERROR("TransposeClip: zu gross");
1701 // Dies passiert erst beim Einfuegen...
1703 GetClipParam().mbCutMode = false;
1706 void ScDocument::CopyRangeNamesToClip(ScDocument* pClipDoc, const ScRange& rClipRange, const ScMarkData* pMarks, bool bAllTabs)
1708 std::set<USHORT> aUsedNames; // indexes of named ranges that are used in the copied cells
1709 for (SCTAB i = 0; i <= MAXTAB; ++i)
1710 if (pTab[i] && pClipDoc->pTab[i])
1711 if ( bAllTabs || !pMarks || pMarks->GetTableSelect(i) )
1712 pTab[i]->FindRangeNamesInUse(
1713 rClipRange.aStart.Col(), rClipRange.aStart.Row(),
1714 rClipRange.aEnd.Col(), rClipRange.aEnd.Row(), aUsedNames);
1716 pClipDoc->pRangeName->FreeAll();
1717 for (USHORT i = 0; i < pRangeName->GetCount(); i++) //! DB-Bereiche Pivot-Bereiche auch !!!
1719 USHORT nIndex = ((ScRangeData*)((*pRangeName)[i]))->GetIndex();
1720 bool bInUse = ( aUsedNames.find(nIndex) != aUsedNames.end() );
1721 if (bInUse)
1723 ScRangeData* pData = new ScRangeData(*((*pRangeName)[i]));
1724 if (!pClipDoc->pRangeName->Insert(pData))
1725 delete pData;
1726 else
1727 pData->SetIndex(nIndex);
1732 ScDocument::NumFmtMergeHandler::NumFmtMergeHandler(ScDocument* pDoc, ScDocument* pSrcDoc) :
1733 mpDoc(pDoc)
1735 mpDoc->MergeNumberFormatter(pSrcDoc);
1738 ScDocument::NumFmtMergeHandler::~NumFmtMergeHandler()
1740 mpDoc->pFormatExchangeList = NULL;
1743 void ScDocument::MergeNumberFormatter(ScDocument* pSrcDoc)
1745 SvNumberFormatter* pThisFormatter = xPoolHelper->GetFormTable();
1746 SvNumberFormatter* pOtherFormatter = pSrcDoc->xPoolHelper->GetFormTable();
1747 if (pOtherFormatter && pOtherFormatter != pThisFormatter)
1749 SvNumberFormatterIndexTable* pExchangeList =
1750 pThisFormatter->MergeFormatter(*(pOtherFormatter));
1751 if (pExchangeList->Count() > 0)
1752 pFormatExchangeList = pExchangeList;
1756 void ScDocument::CopyRangeNamesFromClip(ScDocument* pClipDoc, ScClipRangeNameData& rRangeNames)
1758 sal_uInt16 nClipRangeNameCount = pClipDoc->pRangeName->GetCount();
1759 ScClipRangeNameData aClipRangeNames;
1761 // array containing range names which might need update of indices
1762 aClipRangeNames.mpRangeNames.resize(nClipRangeNameCount, NULL);
1764 for (sal_uInt16 i = 0; i < nClipRangeNameCount; ++i) //! DB-Bereiche Pivot-Bereiche auch
1766 /* Copy only if the name doesn't exist in this document.
1767 If it exists we use the already existing name instead,
1768 another possibility could be to create new names if
1769 documents differ.
1770 A proper solution would ask the user how to proceed.
1771 The adjustment of the indices in the formulas is done later.
1773 ScRangeData* pClipRangeData = (*pClipDoc->pRangeName)[i];
1774 USHORT k;
1775 if ( pRangeName->SearchName( pClipRangeData->GetName(), k ) )
1777 aClipRangeNames.mpRangeNames[i] = NULL; // range name not inserted
1778 USHORT nOldIndex = pClipRangeData->GetIndex();
1779 USHORT nNewIndex = ((*pRangeName)[k])->GetIndex();
1780 aClipRangeNames.insert(nOldIndex, nNewIndex);
1781 if ( !aClipRangeNames.mbReplace )
1782 aClipRangeNames.mbReplace = ( nOldIndex != nNewIndex );
1784 else
1786 ScRangeData* pData = new ScRangeData( *pClipRangeData );
1787 pData->SetDocument(this);
1788 if ( pRangeName->FindIndex( pData->GetIndex() ) )
1789 pData->SetIndex(0); // need new index, done in Insert
1790 if ( pRangeName->Insert( pData ) )
1792 aClipRangeNames.mpRangeNames[i] = pData;
1793 USHORT nOldIndex = pClipRangeData->GetIndex();
1794 USHORT nNewIndex = pData->GetIndex();
1795 aClipRangeNames.insert(nOldIndex, nNewIndex);
1796 if ( !aClipRangeNames.mbReplace )
1797 aClipRangeNames.mbReplace = ( nOldIndex != nNewIndex );
1799 else
1800 { // must be an overflow
1801 delete pData;
1802 aClipRangeNames.mpRangeNames[i] = NULL;
1803 aClipRangeNames.insert(pClipRangeData->GetIndex(), 0);
1804 aClipRangeNames.mbReplace = true;
1808 rRangeNames = aClipRangeNames;
1811 void ScDocument::UpdateRangeNamesInFormulas(
1812 ScClipRangeNameData& rRangeNames, const ScRangeList& rDestRanges, const ScMarkData& rMark,
1813 SCCOL nXw, SCROW nYw)
1815 // nXw and nYw are the extra width and height of the destination range
1816 // extended due to presence of merged cell(s).
1818 if (!rRangeNames.mbReplace)
1819 return;
1821 // first update all inserted named formulas if they contain other
1822 // range names and used indices changed
1823 size_t nRangeNameCount = rRangeNames.mpRangeNames.size();
1824 for (size_t i = 0; i < nRangeNameCount; ++i) //! DB-Bereiche Pivot-Bereiche auch
1826 if ( rRangeNames.mpRangeNames[i] )
1827 rRangeNames.mpRangeNames[i]->ReplaceRangeNamesInUse(rRangeNames.maRangeMap);
1829 // then update the formulas, they might need just the updated range names
1830 for (ULONG nRange = 0; nRange < rDestRanges.Count(); ++nRange)
1832 const ScRange* pRange = rDestRanges.GetObject( nRange);
1833 SCCOL nCol1 = pRange->aStart.Col();
1834 SCROW nRow1 = pRange->aStart.Row();
1835 SCCOL nCol2 = pRange->aEnd.Col();
1836 SCROW nRow2 = pRange->aEnd.Row();
1838 SCCOL nC1 = nCol1;
1839 SCROW nR1 = nRow1;
1840 SCCOL nC2 = nC1 + nXw;
1841 if (nC2 > nCol2)
1842 nC2 = nCol2;
1843 SCROW nR2 = nR1 + nYw;
1844 if (nR2 > nRow2)
1845 nR2 = nRow2;
1850 for (SCTAB k = 0; k <= MAXTAB; k++)
1852 if ( pTab[k] && rMark.GetTableSelect(k) )
1853 pTab[k]->ReplaceRangeNamesInUse(nC1, nR1,
1854 nC2, nR2, rRangeNames.maRangeMap);
1856 nC1 = nC2 + 1;
1857 nC2 = Min((SCCOL)(nC1 + nXw), nCol2);
1858 } while (nC1 <= nCol2);
1859 nC1 = nCol1;
1860 nC2 = nC1 + nXw;
1861 if (nC2 > nCol2)
1862 nC2 = nCol2;
1863 nR1 = nR2 + 1;
1864 nR2 = Min((SCROW)(nR1 + nYw), nRow2);
1865 } while (nR1 <= nRow2);
1869 ScClipParam& ScDocument::GetClipParam()
1871 if (!mpClipParam.get())
1872 mpClipParam.reset(new ScClipParam);
1874 return *mpClipParam;
1877 void ScDocument::SetClipParam(const ScClipParam& rParam)
1879 mpClipParam.reset(new ScClipParam(rParam));
1882 BOOL ScDocument::IsClipboardSource() const
1884 ScDocument* pClipDoc = SC_MOD()->GetClipDoc();
1885 return pClipDoc && pClipDoc->xPoolHelper.isValid() &&
1886 xPoolHelper->GetDocPool() == pClipDoc->xPoolHelper->GetDocPool();
1890 void ScDocument::StartListeningFromClip( SCCOL nCol1, SCROW nRow1,
1891 SCCOL nCol2, SCROW nRow2,
1892 const ScMarkData& rMark, USHORT nInsFlag )
1894 if (nInsFlag & IDF_CONTENTS)
1896 for (SCTAB i = 0; i <= MAXTAB; i++)
1897 if (pTab[i])
1898 if (rMark.GetTableSelect(i))
1899 pTab[i]->StartListeningInArea( nCol1, nRow1, nCol2, nRow2 );
1904 void ScDocument::BroadcastFromClip( SCCOL nCol1, SCROW nRow1,
1905 SCCOL nCol2, SCROW nRow2,
1906 const ScMarkData& rMark, USHORT nInsFlag )
1908 if (nInsFlag & IDF_CONTENTS)
1910 ScBulkBroadcast aBulkBroadcast( GetBASM());
1911 for (SCTAB i = 0; i <= MAXTAB; i++)
1912 if (pTab[i])
1913 if (rMark.GetTableSelect(i))
1914 pTab[i]->BroadcastInArea( nCol1, nRow1, nCol2, nRow2 );
1919 void ScDocument::CopyBlockFromClip( SCCOL nCol1, SCROW nRow1,
1920 SCCOL nCol2, SCROW nRow2,
1921 const ScMarkData& rMark,
1922 SCsCOL nDx, SCsROW nDy,
1923 const ScCopyBlockFromClipParams* pCBFCP )
1925 ScTable** ppClipTab = pCBFCP->pClipDoc->pTab;
1926 SCTAB nTabEnd = pCBFCP->nTabEnd;
1927 SCTAB nClipTab = 0;
1928 for (SCTAB i = pCBFCP->nTabStart; i <= nTabEnd; i++)
1930 if (pTab[i] && rMark.GetTableSelect(i) )
1932 while (!ppClipTab[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
1934 pTab[i]->CopyFromClip( nCol1, nRow1, nCol2, nRow2, nDx, nDy,
1935 pCBFCP->nInsFlag, pCBFCP->bAsLink, pCBFCP->bSkipAttrForEmpty, ppClipTab[nClipTab] );
1937 if ( pCBFCP->pClipDoc->pDrawLayer && ( pCBFCP->nInsFlag & IDF_OBJECTS ) )
1939 // also copy drawing objects
1941 // drawing layer must be created before calling CopyFromClip
1942 // (ScDocShell::MakeDrawLayer also does InitItems etc.)
1943 DBG_ASSERT( pDrawLayer, "CopyBlockFromClip: No drawing layer" );
1944 if ( pDrawLayer )
1946 // For GetMMRect, the row heights in the target document must already be valid
1947 // (copied in an extra step before pasting, or updated after pasting cells, but
1948 // before pasting objects).
1950 Rectangle aSourceRect = pCBFCP->pClipDoc->GetMMRect(
1951 nCol1-nDx, nRow1-nDy, nCol2-nDx, nRow2-nDy, nClipTab );
1952 Rectangle aDestRect = GetMMRect( nCol1, nRow1, nCol2, nRow2, i );
1953 pDrawLayer->CopyFromClip( pCBFCP->pClipDoc->pDrawLayer, nClipTab, aSourceRect,
1954 ScAddress( nCol1, nRow1, i ), aDestRect );
1958 nClipTab = (nClipTab+1) % (MAXTAB+1);
1961 if ( pCBFCP->nInsFlag & IDF_CONTENTS )
1963 nClipTab = 0;
1964 for (SCTAB i = pCBFCP->nTabStart; i <= nTabEnd; i++)
1966 if (pTab[i] && rMark.GetTableSelect(i) )
1968 while (!ppClipTab[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
1969 SCsTAB nDz = ((SCsTAB)i) - nClipTab;
1971 // #89081# ranges of consecutive selected tables (in clipboard and dest. doc)
1972 // must be handled in one UpdateReference call
1973 SCTAB nFollow = 0;
1974 while ( i + nFollow < nTabEnd
1975 && rMark.GetTableSelect( i + nFollow + 1 )
1976 && nClipTab + nFollow < MAXTAB
1977 && ppClipTab[nClipTab + nFollow + 1] )
1978 ++nFollow;
1980 if ( pCBFCP->pClipDoc->GetClipParam().mbCutMode )
1982 BOOL bOldInserting = IsInsertingFromOtherDoc();
1983 SetInsertingFromOtherDoc( TRUE);
1984 UpdateReference( URM_MOVE,
1985 nCol1, nRow1, i, nCol2, nRow2, i+nFollow,
1986 nDx, nDy, nDz, pCBFCP->pRefUndoDoc );
1987 SetInsertingFromOtherDoc( bOldInserting);
1989 else
1990 UpdateReference( URM_COPY,
1991 nCol1, nRow1, i, nCol2, nRow2, i+nFollow,
1992 nDx, nDy, nDz, pCBFCP->pRefUndoDoc, FALSE );
1994 nClipTab = (nClipTab+nFollow+1) % (MAXTAB+1);
1995 i = sal::static_int_cast<SCTAB>( i + nFollow );
2002 void ScDocument::CopyNonFilteredFromClip( SCCOL nCol1, SCROW nRow1,
2003 SCCOL nCol2, SCROW nRow2,
2004 const ScMarkData& rMark,
2005 SCsCOL nDx, SCsROW /* nDy */,
2006 const ScCopyBlockFromClipParams* pCBFCP,
2007 SCROW & rClipStartRow )
2009 // call CopyBlockFromClip for ranges of consecutive non-filtered rows
2010 // nCol1/nRow1 etc. is in target doc
2012 // filtered state is taken from first used table in clipboard (as in GetClipArea)
2013 SCTAB nFlagTab = 0;
2014 ScTable** ppClipTab = pCBFCP->pClipDoc->pTab;
2015 while ( nFlagTab < MAXTAB && !ppClipTab[nFlagTab] )
2016 ++nFlagTab;
2018 SCROW nSourceRow = rClipStartRow;
2019 SCROW nSourceEnd = 0;
2020 if (pCBFCP->pClipDoc->GetClipParam().maRanges.Count())
2021 nSourceEnd = pCBFCP->pClipDoc->GetClipParam().maRanges.First()->aEnd.Row();
2022 SCROW nDestRow = nRow1;
2024 while ( nSourceRow <= nSourceEnd && nDestRow <= nRow2 )
2026 // skip filtered rows
2027 nSourceRow = pCBFCP->pClipDoc->FirstNonFilteredRow(nSourceRow, nSourceEnd, nFlagTab);
2029 if ( nSourceRow <= nSourceEnd )
2031 // look for more non-filtered rows following
2032 SCROW nLastRow = nSourceRow;
2033 pCBFCP->pClipDoc->RowFiltered(nSourceRow, nFlagTab, NULL, &nLastRow);
2034 SCROW nFollow = nLastRow - nSourceRow;
2036 if (nFollow > nSourceEnd - nSourceRow)
2037 nFollow = nSourceEnd - nSourceRow;
2038 if (nFollow > nRow2 - nDestRow)
2039 nFollow = nRow2 - nDestRow;
2041 SCsROW nNewDy = ((SCsROW)nDestRow) - nSourceRow;
2042 CopyBlockFromClip( nCol1, nDestRow, nCol2, nDestRow + nFollow, rMark, nDx, nNewDy, pCBFCP );
2044 nSourceRow += nFollow + 1;
2045 nDestRow += nFollow + 1;
2048 rClipStartRow = nSourceRow;
2052 void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMark,
2053 USHORT nInsFlag,
2054 ScDocument* pRefUndoDoc, ScDocument* pClipDoc, BOOL bResetCut,
2055 BOOL bAsLink, BOOL bIncludeFiltered, BOOL bSkipAttrForEmpty,
2056 const ScRangeList * pDestRanges )
2058 if (!bIsClip)
2060 if (!pClipDoc)
2062 DBG_ERROR("CopyFromClip: no ClipDoc");
2063 pClipDoc = SC_MOD()->GetClipDoc();
2065 if (pClipDoc->bIsClip && pClipDoc->GetTableCount())
2067 BOOL bOldAutoCalc = GetAutoCalc();
2068 SetAutoCalc( FALSE ); // avoid multiple recalculations
2070 NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
2072 ScClipRangeNameData aClipRangeNames;
2073 CopyRangeNamesFromClip(pClipDoc, aClipRangeNames);
2075 SCCOL nAllCol1 = rDestRange.aStart.Col();
2076 SCROW nAllRow1 = rDestRange.aStart.Row();
2077 SCCOL nAllCol2 = rDestRange.aEnd.Col();
2078 SCROW nAllRow2 = rDestRange.aEnd.Row();
2080 SCCOL nXw = 0;
2081 SCROW nYw = 0;
2082 ScRange aClipRange = pClipDoc->GetClipParam().getWholeRange();
2083 for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++) // find largest merge overlap
2084 if (pClipDoc->pTab[nTab]) // all sheets of the clipboard content
2086 SCCOL nThisEndX = aClipRange.aEnd.Col();
2087 SCROW nThisEndY = aClipRange.aEnd.Row();
2088 pClipDoc->ExtendMerge( aClipRange.aStart.Col(),
2089 aClipRange.aStart.Row(),
2090 nThisEndX, nThisEndY, nTab );
2091 // only extra value from ExtendMerge
2092 nThisEndX = sal::static_int_cast<SCCOL>( nThisEndX - aClipRange.aEnd.Col() );
2093 nThisEndY = sal::static_int_cast<SCROW>( nThisEndY - aClipRange.aEnd.Row() );
2094 if ( nThisEndX > nXw )
2095 nXw = nThisEndX;
2096 if ( nThisEndY > nYw )
2097 nYw = nThisEndY;
2100 SCCOL nDestAddX;
2101 SCROW nDestAddY;
2102 pClipDoc->GetClipArea( nDestAddX, nDestAddY, bIncludeFiltered );
2103 nXw = sal::static_int_cast<SCCOL>( nXw + nDestAddX );
2104 nYw = sal::static_int_cast<SCROW>( nYw + nDestAddY ); // ClipArea, plus ExtendMerge value
2106 /* Decide which contents to delete before copying. Delete all
2107 contents if nInsFlag contains any real content flag.
2108 #i102056# Notes are pasted from clipboard in a second pass,
2109 together with the special flag IDF_ADDNOTES that states to not
2110 overwrite/delete existing cells but to insert the notes into
2111 these cells. In this case, just delete old notes from the
2112 destination area. */
2113 USHORT nDelFlag = IDF_NONE;
2114 if ( (nInsFlag & (IDF_CONTENTS | IDF_ADDNOTES)) == (IDF_NOTE | IDF_ADDNOTES) )
2115 nDelFlag |= IDF_NOTE;
2116 else if ( nInsFlag & IDF_CONTENTS )
2117 nDelFlag |= IDF_CONTENTS;
2118 // With bSkipAttrForEmpty, don't remove attributes, copy
2119 // on top of existing attributes instead.
2120 if ( ( nInsFlag & IDF_ATTRIB ) && !bSkipAttrForEmpty )
2121 nDelFlag |= IDF_ATTRIB;
2123 ScCopyBlockFromClipParams aCBFCP;
2124 aCBFCP.pRefUndoDoc = pRefUndoDoc;
2125 aCBFCP.pClipDoc = pClipDoc;
2126 aCBFCP.nInsFlag = nInsFlag;
2127 aCBFCP.bAsLink = bAsLink;
2128 aCBFCP.bSkipAttrForEmpty = bSkipAttrForEmpty;
2129 aCBFCP.nTabStart = MAXTAB; // wird in der Schleife angepasst
2130 aCBFCP.nTabEnd = 0; // wird in der Schleife angepasst
2132 // Inc/DecRecalcLevel einmal aussen, damit nicht fuer jeden Block
2133 // die Draw-Seitengroesse neu berechnet werden muss
2134 //! nur wenn ganze Zeilen/Spalten kopiert werden?
2136 for (SCTAB j = 0; j <= MAXTAB; j++)
2137 if (pTab[j] && rMark.GetTableSelect(j))
2139 if ( j < aCBFCP.nTabStart )
2140 aCBFCP.nTabStart = j;
2141 aCBFCP.nTabEnd = j;
2142 pTab[j]->IncRecalcLevel();
2145 ScRangeList aLocalRangeList;
2146 if (!pDestRanges)
2148 aLocalRangeList.Append( rDestRange);
2149 pDestRanges = &aLocalRangeList;
2152 bInsertingFromOtherDoc = TRUE; // kein Broadcast/Listener aufbauen bei Insert
2154 // bei mindestens 64 Zeilen wird in ScColumn::CopyFromClip voralloziert
2155 BOOL bDoDouble = ( nYw < 64 && nAllRow2 - nAllRow1 > 64);
2156 BOOL bOldDouble = ScColumn::bDoubleAlloc;
2157 if (bDoDouble)
2158 ScColumn::bDoubleAlloc = TRUE;
2160 SCCOL nClipStartCol = aClipRange.aStart.Col();
2161 SCROW nClipStartRow = aClipRange.aStart.Row();
2162 // WaE: commented because unused: SCCOL nClipEndCol = pClipDoc->aClipRange.aEnd.Col();
2163 SCROW nClipEndRow = aClipRange.aEnd.Row();
2164 for (ULONG nRange = 0; nRange < pDestRanges->Count(); ++nRange)
2166 const ScRange* pRange = pDestRanges->GetObject( nRange);
2167 SCCOL nCol1 = pRange->aStart.Col();
2168 SCROW nRow1 = pRange->aStart.Row();
2169 SCCOL nCol2 = pRange->aEnd.Col();
2170 SCROW nRow2 = pRange->aEnd.Row();
2172 DeleteArea(nCol1, nRow1, nCol2, nRow2, rMark, nDelFlag);
2174 SCCOL nC1 = nCol1;
2175 SCROW nR1 = nRow1;
2176 SCCOL nC2 = nC1 + nXw;
2177 if (nC2 > nCol2)
2178 nC2 = nCol2;
2179 SCROW nR2 = nR1 + nYw;
2180 if (nR2 > nRow2)
2181 nR2 = nRow2;
2185 // Pasting is done column-wise, when pasting to a filtered
2186 // area this results in partitioning and we have to
2187 // remember and reset the start row for each column until
2188 // it can be advanced for the next chunk of unfiltered
2189 // rows.
2190 SCROW nSaveClipStartRow = nClipStartRow;
2193 nClipStartRow = nSaveClipStartRow;
2194 SCsCOL nDx = ((SCsCOL)nC1) - nClipStartCol;
2195 SCsROW nDy = ((SCsROW)nR1) - nClipStartRow;
2196 if ( bIncludeFiltered )
2198 CopyBlockFromClip( nC1, nR1, nC2, nR2, rMark, nDx,
2199 nDy, &aCBFCP );
2200 nClipStartRow += nR2 - nR1 + 1;
2202 else
2204 CopyNonFilteredFromClip( nC1, nR1, nC2, nR2, rMark,
2205 nDx, nDy, &aCBFCP, nClipStartRow );
2207 // Not needed for columns, but if it was this would be how to.
2208 //if (nClipStartCol > nClipEndCol)
2209 // nClipStartCol = pClipDoc->aClipRange.aStart.Col();
2210 nC1 = nC2 + 1;
2211 nC2 = Min((SCCOL)(nC1 + nXw), nCol2);
2212 } while (nC1 <= nCol2);
2213 if (nClipStartRow > nClipEndRow)
2214 nClipStartRow = aClipRange.aStart.Row();
2215 nC1 = nCol1;
2216 nC2 = nC1 + nXw;
2217 if (nC2 > nCol2)
2218 nC2 = nCol2;
2219 nR1 = nR2 + 1;
2220 nR2 = Min((SCROW)(nR1 + nYw), nRow2);
2221 } while (nR1 <= nRow2);
2224 ScColumn::bDoubleAlloc = bOldDouble;
2226 for (SCTAB k = 0; k <= MAXTAB; k++)
2227 if (pTab[k] && rMark.GetTableSelect(k))
2228 pTab[k]->DecRecalcLevel();
2230 bInsertingFromOtherDoc = FALSE;
2232 UpdateRangeNamesInFormulas(aClipRangeNames, *pDestRanges, rMark, nXw, nYw);
2234 // Listener aufbauen nachdem alles inserted wurde
2235 StartListeningFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
2236 // nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
2237 BroadcastFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
2238 if (bResetCut)
2239 pClipDoc->GetClipParam().mbCutMode = false;
2240 SetAutoCalc( bOldAutoCalc );
2245 static SCROW lcl_getLastNonFilteredRow(
2246 const ScBitMaskCompressedArray<SCROW, BYTE>& rFlags, SCROW nBegRow, SCROW nEndRow,
2247 SCROW nRowCount)
2249 SCROW nFilteredRow = rFlags.GetFirstForCondition(
2250 nBegRow, nEndRow, CR_FILTERED, CR_FILTERED);
2252 SCROW nRow = nFilteredRow - 1;
2253 if (nRow - nBegRow + 1 > nRowCount)
2254 // make sure the row range stays within the data size.
2255 nRow = nBegRow + nRowCount - 1;
2257 return nRow;
2260 void ScDocument::CopyMultiRangeFromClip(
2261 const ScAddress& rDestPos, const ScMarkData& rMark, sal_uInt16 nInsFlag, ScDocument* pClipDoc,
2262 bool bResetCut, bool bAsLink, bool /*bIncludeFiltered*/, bool bSkipAttrForEmpty)
2264 if (bIsClip)
2265 return;
2267 if (!pClipDoc->bIsClip || !pClipDoc->GetTableCount())
2268 // There is nothing in the clip doc to copy.
2269 return;
2271 BOOL bOldAutoCalc = GetAutoCalc();
2272 SetAutoCalc( FALSE ); // avoid multiple recalculations
2274 NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
2276 ScClipRangeNameData aClipRangeNames;
2277 CopyRangeNamesFromClip(pClipDoc, aClipRangeNames);
2279 SCCOL nCol1 = rDestPos.Col();
2280 SCROW nRow1 = rDestPos.Row();
2281 ScClipParam& rClipParam = pClipDoc->GetClipParam();
2283 ScCopyBlockFromClipParams aCBFCP;
2284 aCBFCP.pRefUndoDoc = NULL;
2285 aCBFCP.pClipDoc = pClipDoc;
2286 aCBFCP.nInsFlag = nInsFlag;
2287 aCBFCP.bAsLink = bAsLink;
2288 aCBFCP.bSkipAttrForEmpty = bSkipAttrForEmpty;
2289 aCBFCP.nTabStart = MAXTAB;
2290 aCBFCP.nTabEnd = 0;
2292 for (SCTAB j = 0; j <= MAXTAB; ++j)
2294 if (pTab[j] && rMark.GetTableSelect(j))
2296 if ( j < aCBFCP.nTabStart )
2297 aCBFCP.nTabStart = j;
2298 aCBFCP.nTabEnd = j;
2299 pTab[j]->IncRecalcLevel();
2303 ScRange aDestRange;
2304 rMark.GetMarkArea(aDestRange);
2305 SCROW nLastMarkedRow = aDestRange.aEnd.Row();
2307 bInsertingFromOtherDoc = TRUE; // kein Broadcast/Listener aufbauen bei Insert
2309 SCROW nBegRow = nRow1;
2310 sal_uInt16 nDelFlag = IDF_CONTENTS;
2311 const ScBitMaskCompressedArray<SCROW, BYTE>& rFlags = GetRowFlagsArray(aCBFCP.nTabStart);
2313 for (ScRange* p = rClipParam.maRanges.First(); p; p = rClipParam.maRanges.Next())
2315 // The begin row must not be filtered.
2317 SCROW nRowCount = p->aEnd.Row() - p->aStart.Row() + 1;
2319 SCsCOL nDx = static_cast<SCsCOL>(nCol1 - p->aStart.Col());
2320 SCsROW nDy = static_cast<SCsROW>(nBegRow - p->aStart.Row());
2321 SCCOL nCol2 = nCol1 + p->aEnd.Col() - p->aStart.Col();
2323 SCROW nEndRow = lcl_getLastNonFilteredRow(rFlags, nBegRow, nLastMarkedRow, nRowCount);
2325 if (!bSkipAttrForEmpty)
2326 DeleteArea(nCol1, nBegRow, nCol2, nEndRow, rMark, nDelFlag);
2328 CopyBlockFromClip(nCol1, nBegRow, nCol2, nEndRow, rMark, nDx, nDy, &aCBFCP);
2329 nRowCount -= nEndRow - nBegRow + 1;
2331 while (nRowCount > 0)
2333 // Get the first non-filtered row.
2334 SCROW nNonFilteredRow = rFlags.GetFirstForCondition(nEndRow+1, nLastMarkedRow, CR_FILTERED, 0);
2335 if (nNonFilteredRow > nLastMarkedRow)
2336 return;
2338 SCROW nRowsSkipped = nNonFilteredRow - nEndRow - 1;
2339 nDy += nRowsSkipped;
2341 nBegRow = nNonFilteredRow;
2342 nEndRow = lcl_getLastNonFilteredRow(rFlags, nBegRow, nLastMarkedRow, nRowCount);
2344 if (!bSkipAttrForEmpty)
2345 DeleteArea(nCol1, nBegRow, nCol2, nEndRow, rMark, nDelFlag);
2347 CopyBlockFromClip(nCol1, nBegRow, nCol2, nEndRow, rMark, nDx, nDy, &aCBFCP);
2348 nRowCount -= nEndRow - nBegRow + 1;
2351 if (rClipParam.meDirection == ScClipParam::Row)
2352 // Begin row for the next range being pasted.
2353 nBegRow = rFlags.GetFirstForCondition(nEndRow+1, nLastMarkedRow, CR_FILTERED, 0);
2354 else
2355 nBegRow = nRow1;
2357 if (rClipParam.meDirection == ScClipParam::Column)
2358 nCol1 += p->aEnd.Col() - p->aStart.Col() + 1;
2361 for (SCTAB i = 0; i <= MAXTAB; i++)
2362 if (pTab[i] && rMark.GetTableSelect(i))
2363 pTab[i]->DecRecalcLevel();
2365 bInsertingFromOtherDoc = FALSE;
2367 ScRangeList aRanges;
2368 aRanges.Append(aDestRange);
2369 SCCOL nCols = aDestRange.aEnd.Col() - aDestRange.aStart.Col() + 1;
2370 SCROW nRows = aDestRange.aEnd.Row() - aDestRange.aStart.Row() + 1;
2371 UpdateRangeNamesInFormulas(aClipRangeNames, aRanges, rMark, nCols-1, nRows-1);
2373 // Listener aufbauen nachdem alles inserted wurde
2374 StartListeningFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
2375 aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
2376 // nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
2377 BroadcastFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
2378 aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
2380 if (bResetCut)
2381 pClipDoc->GetClipParam().mbCutMode = false;
2382 SetAutoCalc( bOldAutoCalc );
2385 void ScDocument::SetClipArea( const ScRange& rArea, BOOL bCut )
2387 if (bIsClip)
2389 ScClipParam& rClipParam = GetClipParam();
2390 rClipParam.maRanges.RemoveAll();
2391 rClipParam.maRanges.Append(rArea);
2392 rClipParam.mbCutMode = bCut;
2394 else
2396 DBG_ERROR("SetClipArea: kein Clip");
2401 void ScDocument::GetClipArea(SCCOL& nClipX, SCROW& nClipY, BOOL bIncludeFiltered)
2403 if (!bIsClip)
2405 DBG_ERROR("GetClipArea: kein Clip");
2406 return;
2409 ScRangeList& rClipRanges = GetClipParam().maRanges;
2410 if (!rClipRanges.Count())
2411 // No clip range. Bail out.
2412 return;
2414 ScRangePtr p = rClipRanges.First();
2415 SCCOL nStartCol = p->aStart.Col();
2416 SCCOL nEndCol = p->aEnd.Col();
2417 SCROW nStartRow = p->aStart.Row();
2418 SCROW nEndRow = p->aEnd.Row();
2419 for (p = rClipRanges.Next(); p; p = rClipRanges.Next())
2421 if (p->aStart.Col() < nStartCol)
2422 nStartCol = p->aStart.Col();
2423 if (p->aStart.Row() < nStartRow)
2424 nStartRow = p->aStart.Row();
2425 if (p->aEnd.Col() > nEndCol)
2426 nEndCol = p->aEnd.Col();
2427 if (p->aEnd.Row() < nEndRow)
2428 nEndRow = p->aEnd.Row();
2431 nClipX = nEndCol - nStartCol;
2433 if ( bIncludeFiltered )
2434 nClipY = nEndRow - nStartRow;
2435 else
2437 // count non-filtered rows
2438 // count on first used table in clipboard
2439 SCTAB nCountTab = 0;
2440 while ( nCountTab < MAXTAB && !pTab[nCountTab] )
2441 ++nCountTab;
2443 SCROW nResult = CountNonFilteredRows(nStartRow, nEndRow, nCountTab);
2445 if ( nResult > 0 )
2446 nClipY = nResult - 1;
2447 else
2448 nClipY = 0; // always return at least 1 row
2453 void ScDocument::GetClipStart(SCCOL& nClipX, SCROW& nClipY)
2455 if (bIsClip)
2457 ScRangeList& rClipRanges = GetClipParam().maRanges;
2458 if (rClipRanges.Count())
2460 nClipX = rClipRanges.First()->aStart.Col();
2461 nClipY = rClipRanges.First()->aStart.Row();
2464 else
2466 DBG_ERROR("GetClipStart: kein Clip");
2471 BOOL ScDocument::HasClipFilteredRows()
2473 // count on first used table in clipboard
2474 SCTAB nCountTab = 0;
2475 while ( nCountTab < MAXTAB && !pTab[nCountTab] )
2476 ++nCountTab;
2478 ScRangeList& rClipRanges = GetClipParam().maRanges;
2479 if (!rClipRanges.Count())
2480 return false;
2482 for (ScRange* p = rClipRanges.First(); p; p = rClipRanges.Next())
2484 bool bAnswer = pTab[nCountTab]->HasFilteredRows(p->aStart.Row(), p->aEnd.Row());
2485 if (bAnswer)
2486 return true;
2488 return false;
2492 void ScDocument::MixDocument( const ScRange& rRange, USHORT nFunction, BOOL bSkipEmpty,
2493 ScDocument* pSrcDoc )
2495 SCTAB nTab1 = rRange.aStart.Tab();
2496 SCTAB nTab2 = rRange.aEnd.Tab();
2497 for (SCTAB i = nTab1; i <= nTab2; i++)
2498 if (pTab[i] && pSrcDoc->pTab[i])
2499 pTab[i]->MixData( rRange.aStart.Col(), rRange.aStart.Row(),
2500 rRange.aEnd.Col(), rRange.aEnd.Row(),
2501 nFunction, bSkipEmpty, pSrcDoc->pTab[i] );
2505 void ScDocument::FillTab( const ScRange& rSrcArea, const ScMarkData& rMark,
2506 USHORT nFlags, USHORT nFunction,
2507 BOOL bSkipEmpty, BOOL bAsLink )
2509 USHORT nDelFlags = nFlags;
2510 if (nDelFlags & IDF_CONTENTS)
2511 nDelFlags |= IDF_CONTENTS; // immer alle Inhalte oder keine loeschen!
2513 SCTAB nSrcTab = rSrcArea.aStart.Tab();
2515 if (ValidTab(nSrcTab) && pTab[nSrcTab])
2517 SCCOL nStartCol = rSrcArea.aStart.Col();
2518 SCROW nStartRow = rSrcArea.aStart.Row();
2519 SCCOL nEndCol = rSrcArea.aEnd.Col();
2520 SCROW nEndRow = rSrcArea.aEnd.Row();
2521 ScDocument* pMixDoc = NULL;
2522 BOOL bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
2524 BOOL bOldAutoCalc = GetAutoCalc();
2525 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
2527 SCTAB nCount = GetTableCount();
2528 for (SCTAB i=0; i<nCount; i++)
2529 if ( i!=nSrcTab && pTab[i] && rMark.GetTableSelect(i) )
2531 if (bDoMix)
2533 if (!pMixDoc)
2535 pMixDoc = new ScDocument( SCDOCMODE_UNDO );
2536 pMixDoc->InitUndo( this, i, i );
2538 else
2539 pMixDoc->AddUndoTab( i, i );
2540 pTab[i]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2541 IDF_CONTENTS, FALSE, pMixDoc->pTab[i] );
2543 pTab[i]->DeleteArea( nStartCol,nStartRow, nEndCol,nEndRow, nDelFlags);
2544 pTab[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2545 nFlags, FALSE, pTab[i], NULL, bAsLink );
2547 if (bDoMix)
2548 pTab[i]->MixData( nStartCol,nStartRow, nEndCol,nEndRow,
2549 nFunction, bSkipEmpty, pMixDoc->pTab[i] );
2552 delete pMixDoc;
2554 SetAutoCalc( bOldAutoCalc );
2556 else
2558 DBG_ERROR("falsche Tabelle");
2563 void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
2564 USHORT nFlags, USHORT nFunction,
2565 BOOL bSkipEmpty, BOOL bAsLink )
2567 USHORT nDelFlags = nFlags;
2568 if (nDelFlags & IDF_CONTENTS)
2569 nDelFlags |= IDF_CONTENTS; // immer alle Inhalte oder keine loeschen!
2571 if (ValidTab(nSrcTab) && pTab[nSrcTab])
2573 ScDocument* pMixDoc = NULL;
2574 BOOL bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
2576 BOOL bOldAutoCalc = GetAutoCalc();
2577 SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
2579 ScRange aArea;
2580 rMark.GetMultiMarkArea( aArea );
2581 SCCOL nStartCol = aArea.aStart.Col();
2582 SCROW nStartRow = aArea.aStart.Row();
2583 SCCOL nEndCol = aArea.aEnd.Col();
2584 SCROW nEndRow = aArea.aEnd.Row();
2586 SCTAB nCount = GetTableCount();
2587 for (SCTAB i=0; i<nCount; i++)
2588 if ( i!=nSrcTab && pTab[i] && rMark.GetTableSelect(i) )
2590 if (bDoMix)
2592 if (!pMixDoc)
2594 pMixDoc = new ScDocument( SCDOCMODE_UNDO );
2595 pMixDoc->InitUndo( this, i, i );
2597 else
2598 pMixDoc->AddUndoTab( i, i );
2599 pTab[i]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2600 IDF_CONTENTS, TRUE, pMixDoc->pTab[i], &rMark );
2603 pTab[i]->DeleteSelection( nDelFlags, rMark );
2604 pTab[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
2605 nFlags, TRUE, pTab[i], &rMark, bAsLink );
2607 if (bDoMix)
2608 pTab[i]->MixMarked( rMark, nFunction, bSkipEmpty, pMixDoc->pTab[i] );
2611 delete pMixDoc;
2613 SetAutoCalc( bOldAutoCalc );
2615 else
2617 DBG_ERROR("falsche Tabelle");
2622 void ScDocument::PutCell( SCCOL nCol, SCROW nRow, SCTAB nTab, ScBaseCell* pCell, BOOL bForceTab )
2624 if (VALIDTAB(nTab))
2626 if ( bForceTab && !pTab[nTab] )
2628 BOOL bExtras = !bIsUndo; // Spaltenbreiten, Zeilenhoehen, Flags
2630 pTab[nTab] = new ScTable(this, nTab,
2631 String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("temp")),
2632 bExtras, bExtras);
2633 ++nMaxTableNumber;
2636 if (pTab[nTab])
2637 pTab[nTab]->PutCell( nCol, nRow, pCell );
2642 void ScDocument::PutCell( const ScAddress& rPos, ScBaseCell* pCell, BOOL bForceTab )
2644 SCTAB nTab = rPos.Tab();
2645 if ( bForceTab && !pTab[nTab] )
2647 BOOL bExtras = !bIsUndo; // Spaltenbreiten, Zeilenhoehen, Flags
2649 pTab[nTab] = new ScTable(this, nTab,
2650 String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("temp")),
2651 bExtras, bExtras);
2652 ++nMaxTableNumber;
2655 if (pTab[nTab])
2656 pTab[nTab]->PutCell( rPos, pCell );
2660 BOOL ScDocument::SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rString,
2661 ScSetStringParam* pParam )
2663 if ( ValidTab(nTab) && pTab[nTab] )
2664 return pTab[nTab]->SetString( nCol, nRow, nTab, rString, pParam );
2665 else
2666 return FALSE;
2670 void ScDocument::SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal )
2672 if (VALIDTAB(nTab))
2673 if (pTab[nTab])
2674 pTab[nTab]->SetValue( nCol, nRow, rVal );
2678 void ScDocument::GetString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString )
2680 if ( VALIDTAB(nTab) && pTab[nTab] )
2681 pTab[nTab]->GetString( nCol, nRow, rString );
2682 else
2683 rString.Erase();
2687 void ScDocument::GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString )
2689 if ( VALIDTAB(nTab) && pTab[nTab] )
2690 pTab[nTab]->GetInputString( nCol, nRow, rString );
2691 else
2692 rString.Erase();
2696 void ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, double& rValue )
2698 if ( VALIDTAB(nTab) && pTab[nTab] )
2699 rValue = pTab[nTab]->GetValue( nCol, nRow );
2700 else
2701 rValue = 0.0;
2705 double ScDocument::GetValue( const ScAddress& rPos )
2707 SCTAB nTab = rPos.Tab();
2708 if ( pTab[nTab] )
2709 return pTab[nTab]->GetValue( rPos );
2710 return 0.0;
2714 void ScDocument::GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab,
2715 sal_uInt32& rFormat )
2717 if (VALIDTAB(nTab))
2718 if (pTab[nTab])
2720 rFormat = pTab[nTab]->GetNumberFormat( nCol, nRow );
2721 return ;
2723 rFormat = 0;
2726 sal_uInt32 ScDocument::GetNumberFormat( const ScRange& rRange ) const
2728 SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = rRange.aEnd.Tab();
2729 SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
2730 SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
2732 if (!ValidTab(nTab1) || !ValidTab(nTab2) || !pTab[nTab1] || !pTab[nTab2])
2733 return 0;
2735 sal_uInt32 nFormat = 0;
2736 bool bFirstItem = true;
2737 for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
2738 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
2740 sal_uInt32 nThisFormat = pTab[nTab]->GetNumberFormat(nCol, nRow1, nRow2);
2741 if (bFirstItem)
2743 nFormat = nThisFormat;
2744 bFirstItem = false;
2746 else if (nThisFormat != nFormat)
2747 return 0;
2750 return nFormat;
2753 sal_uInt32 ScDocument::GetNumberFormat( const ScAddress& rPos ) const
2755 SCTAB nTab = rPos.Tab();
2756 if ( pTab[nTab] )
2757 return pTab[nTab]->GetNumberFormat( rPos );
2758 return 0;
2762 void ScDocument::GetNumberFormatInfo( short& nType, ULONG& nIndex,
2763 const ScAddress& rPos, const ScBaseCell* pCell ) const
2765 SCTAB nTab = rPos.Tab();
2766 if ( pTab[nTab] )
2768 nIndex = pTab[nTab]->GetNumberFormat( rPos );
2769 if ( (nIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && pCell &&
2770 pCell->GetCellType() == CELLTYPE_FORMULA )
2771 static_cast<const ScFormulaCell*>(pCell)->GetFormatInfo( nType, nIndex );
2772 else
2773 nType = GetFormatTable()->GetType( nIndex );
2775 else
2777 nType = NUMBERFORMAT_UNDEFINED;
2778 nIndex = 0;
2783 void ScDocument::GetFormula( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rFormula,
2784 BOOL bAsciiExport ) const
2786 if ( VALIDTAB(nTab) && pTab[nTab] )
2787 pTab[nTab]->GetFormula( nCol, nRow, rFormula, bAsciiExport );
2788 else
2789 rFormula.Erase();
2793 CellType ScDocument::GetCellType( const ScAddress& rPos ) const
2795 SCTAB nTab = rPos.Tab();
2796 if ( pTab[nTab] )
2797 return pTab[nTab]->GetCellType( rPos );
2798 return CELLTYPE_NONE;
2802 void ScDocument::GetCellType( SCCOL nCol, SCROW nRow, SCTAB nTab,
2803 CellType& rCellType ) const
2805 if (ValidTab(nTab) && pTab[nTab])
2806 rCellType = pTab[nTab]->GetCellType( nCol, nRow );
2807 else
2808 rCellType = CELLTYPE_NONE;
2812 void ScDocument::GetCell( SCCOL nCol, SCROW nRow, SCTAB nTab,
2813 ScBaseCell*& rpCell ) const
2815 if (ValidTab(nTab) && pTab[nTab])
2816 rpCell = pTab[nTab]->GetCell( nCol, nRow );
2817 else
2819 DBG_ERROR("GetCell ohne Tabelle");
2820 rpCell = NULL;
2825 ScBaseCell* ScDocument::GetCell( const ScAddress& rPos ) const
2827 SCTAB nTab = rPos.Tab();
2828 if (ValidTab(nTab) && pTab[nTab])
2829 return pTab[nTab]->GetCell( rPos );
2831 DBG_ERROR("GetCell ohne Tabelle");
2832 return NULL;
2836 BOOL ScDocument::HasStringData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
2838 if ( VALIDTAB(nTab) && pTab[nTab] )
2839 return pTab[nTab]->HasStringData( nCol, nRow );
2840 else
2841 return FALSE;
2845 BOOL ScDocument::HasValueData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
2847 if ( VALIDTAB(nTab) && pTab[nTab] )
2848 return pTab[nTab]->HasValueData( nCol, nRow );
2849 else
2850 return FALSE;
2854 BOOL ScDocument::HasStringCells( const ScRange& rRange ) const
2856 // TRUE, wenn String- oder Editzellen im Bereich
2858 SCCOL nStartCol = rRange.aStart.Col();
2859 SCROW nStartRow = rRange.aStart.Row();
2860 SCTAB nStartTab = rRange.aStart.Tab();
2861 SCCOL nEndCol = rRange.aEnd.Col();
2862 SCROW nEndRow = rRange.aEnd.Row();
2863 SCTAB nEndTab = rRange.aEnd.Tab();
2865 for ( SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++ )
2866 if ( pTab[nTab] && pTab[nTab]->HasStringCells( nStartCol, nStartRow, nEndCol, nEndRow ) )
2867 return TRUE;
2869 return FALSE;
2873 BOOL ScDocument::HasSelectionData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
2875 sal_uInt32 nValidation = static_cast< const SfxUInt32Item* >( GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA ) )->GetValue();
2876 if( nValidation )
2878 const ScValidationData* pData = GetValidationEntry( nValidation );
2879 if( pData && pData->HasSelectionList() )
2880 return TRUE;
2882 return HasStringCells( ScRange( nCol, 0, nTab, nCol, MAXROW, nTab ) );
2886 ScPostIt* ScDocument::GetNote( const ScAddress& rPos )
2888 ScTable* pTable = ValidTab( rPos.Tab() ) ? pTab[ rPos.Tab() ] : 0;
2889 return pTable ? pTable->GetNote( rPos.Col(), rPos.Row() ) : 0;
2893 void ScDocument::TakeNote( const ScAddress& rPos, ScPostIt*& rpNote )
2895 if( ValidTab( rPos.Tab() ) && pTab[ rPos.Tab() ] )
2896 pTab[ rPos.Tab() ]->TakeNote( rPos.Col(), rPos.Row(), rpNote );
2897 else
2898 DELETEZ( rpNote );
2902 ScPostIt* ScDocument::ReleaseNote( const ScAddress& rPos )
2904 ScTable* pTable = ValidTab( rPos.Tab() ) ? pTab[ rPos.Tab() ] : 0;
2905 return pTable ? pTable->ReleaseNote( rPos.Col(), rPos.Row() ) : 0;
2909 ScPostIt* ScDocument::GetOrCreateNote( const ScAddress& rPos )
2911 ScPostIt* pNote = GetNote( rPos );
2912 if( !pNote )
2914 pNote = new ScPostIt( *this, rPos, false );
2915 TakeNote( rPos, pNote );
2917 return pNote;
2921 void ScDocument::DeleteNote( const ScAddress& rPos )
2923 if( ValidTab( rPos.Tab() ) && pTab[ rPos.Tab() ] )
2924 pTab[ rPos.Tab() ]->DeleteNote( rPos.Col(), rPos.Row() );
2928 void ScDocument::InitializeNoteCaptions( SCTAB nTab, bool bForced )
2930 if( ValidTab( nTab ) && pTab[ nTab ] )
2931 pTab[ nTab ]->InitializeNoteCaptions( bForced );
2934 void ScDocument::InitializeAllNoteCaptions( bool bForced )
2936 for( SCTAB nTab = 0; nTab < GetTableCount(); ++nTab )
2937 InitializeNoteCaptions( nTab, bForced );
2940 void ScDocument::SetDirty()
2942 BOOL bOldAutoCalc = GetAutoCalc();
2943 bAutoCalc = FALSE; // keine Mehrfachberechnung
2944 { // scope for bulk broadcast
2945 ScBulkBroadcast aBulkBroadcast( GetBASM());
2946 for (SCTAB i=0; i<=MAXTAB; i++)
2947 if (pTab[i]) pTab[i]->SetDirty();
2950 // Charts werden zwar auch ohne AutoCalc im Tracking auf Dirty gesetzt,
2951 // wenn alle Formeln dirty sind, werden die Charts aber nicht mehr erwischt
2952 // (#45205#) - darum alle Charts nochmal explizit
2953 if (pChartListenerCollection)
2954 pChartListenerCollection->SetDirty();
2956 SetAutoCalc( bOldAutoCalc );
2960 void ScDocument::SetDirty( const ScRange& rRange )
2962 BOOL bOldAutoCalc = GetAutoCalc();
2963 bAutoCalc = FALSE; // keine Mehrfachberechnung
2964 { // scope for bulk broadcast
2965 ScBulkBroadcast aBulkBroadcast( GetBASM());
2966 SCTAB nTab2 = rRange.aEnd.Tab();
2967 for (SCTAB i=rRange.aStart.Tab(); i<=nTab2; i++)
2968 if (pTab[i]) pTab[i]->SetDirty( rRange );
2970 SetAutoCalc( bOldAutoCalc );
2974 void ScDocument::SetTableOpDirty( const ScRange& rRange )
2976 BOOL bOldAutoCalc = GetAutoCalc();
2977 bAutoCalc = FALSE; // no multiple recalculation
2978 SCTAB nTab2 = rRange.aEnd.Tab();
2979 for (SCTAB i=rRange.aStart.Tab(); i<=nTab2; i++)
2980 if (pTab[i]) pTab[i]->SetTableOpDirty( rRange );
2981 SetAutoCalc( bOldAutoCalc );
2985 void ScDocument::InterpretDirtyCells( const ScRangeList& rRanges )
2987 ULONG nRangeCount = rRanges.Count();
2988 for (ULONG nPos=0; nPos<nRangeCount; nPos++)
2990 ScCellIterator aIter( this, *rRanges.GetObject(nPos) );
2991 ScBaseCell* pCell = aIter.GetFirst();
2992 while (pCell)
2994 if (pCell->GetCellType() == CELLTYPE_FORMULA)
2996 if ( static_cast<ScFormulaCell*>(pCell)->GetDirty() && GetAutoCalc() )
2997 static_cast<ScFormulaCell*>(pCell)->Interpret();
2999 pCell = aIter.GetNext();
3005 void ScDocument::AddTableOpFormulaCell( ScFormulaCell* pCell )
3007 ScInterpreterTableOpParams* p = aTableOpList.Last();
3008 if ( p && p->bCollectNotifications )
3010 if ( p->bRefresh )
3011 { // refresh pointers only
3012 p->aNotifiedFormulaCells.push_back( pCell );
3014 else
3015 { // init both, address and pointer
3016 p->aNotifiedFormulaCells.push_back( pCell );
3017 p->aNotifiedFormulaPos.push_back( pCell->aPos );
3023 void ScDocument::CalcAll()
3025 ClearLookupCaches(); // Ensure we don't deliver zombie data.
3026 BOOL bOldAutoCalc = GetAutoCalc();
3027 SetAutoCalc( TRUE );
3028 SCTAB i;
3029 for (i=0; i<=MAXTAB; i++)
3030 if (pTab[i]) pTab[i]->SetDirtyVar();
3031 for (i=0; i<=MAXTAB; i++)
3032 if (pTab[i]) pTab[i]->CalcAll();
3033 ClearFormulaTree();
3034 SetAutoCalc( bOldAutoCalc );
3038 void ScDocument::CompileAll()
3040 if ( pCondFormList )
3041 pCondFormList->CompileAll();
3043 for (SCTAB i=0; i<=MAXTAB; i++)
3044 if (pTab[i]) pTab[i]->CompileAll();
3045 SetDirty();
3049 void ScDocument::CompileXML()
3051 BOOL bOldAutoCalc = GetAutoCalc();
3052 SetAutoCalc( FALSE );
3053 ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(
3054 STR_PROGRESS_CALCULATING ), GetXMLImportedFormulaCount() );
3056 // #b6355215# set AutoNameCache to speed up automatic name lookup
3057 DBG_ASSERT( !pAutoNameCache, "AutoNameCache already set" );
3058 pAutoNameCache = new ScAutoNameCache( this );
3060 for (SCTAB i=0; i<=MAXTAB; i++)
3061 if (pTab[i]) pTab[i]->CompileXML( aProgress );
3063 DELETEZ( pAutoNameCache ); // valid only during CompileXML, where cell contents don't change
3065 if ( pCondFormList )
3066 pCondFormList->CompileXML();
3067 if ( pValidationList )
3068 pValidationList->CompileXML();
3070 SetDirty();
3071 SetAutoCalc( bOldAutoCalc );
3075 void ScDocument::CalcAfterLoad()
3077 SCTAB i;
3079 if (bIsClip) // Excel-Dateien werden aus dem Clipboard in ein Clip-Doc geladen
3080 return; // dann wird erst beim Einfuegen in das richtige Doc berechnet
3082 bCalcingAfterLoad = TRUE;
3083 for ( i = 0; i <= MAXTAB; i++)
3084 if (pTab[i]) pTab[i]->CalcAfterLoad();
3085 for (i=0; i<=MAXTAB; i++)
3086 if (pTab[i]) pTab[i]->SetDirtyAfterLoad();
3087 bCalcingAfterLoad = FALSE;
3089 SetDetectiveDirty(FALSE); // noch keine wirklichen Aenderungen
3093 USHORT ScDocument::GetErrCode( const ScAddress& rPos ) const
3095 SCTAB nTab = rPos.Tab();
3096 if ( pTab[nTab] )
3097 return pTab[nTab]->GetErrCode( rPos );
3098 return 0;
3102 void ScDocument::ResetChanged( const ScRange& rRange )
3104 SCTAB nStartTab = rRange.aStart.Tab();
3105 SCTAB nEndTab = rRange.aEnd.Tab();
3106 for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
3107 if (pTab[nTab])
3108 pTab[nTab]->ResetChanged( rRange );
3112 // Spaltenbreiten / Zeilenhoehen --------------------------------------
3116 void ScDocument::SetColWidth( SCCOL nCol, SCTAB nTab, USHORT nNewWidth )
3118 if ( ValidTab(nTab) && pTab[nTab] )
3119 pTab[nTab]->SetColWidth( nCol, nNewWidth );
3123 void ScDocument::SetRowHeight( SCROW nRow, SCTAB nTab, USHORT nNewHeight )
3125 if ( ValidTab(nTab) && pTab[nTab] )
3126 pTab[nTab]->SetRowHeight( nRow, nNewHeight );
3130 void ScDocument::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, USHORT nNewHeight )
3132 if ( ValidTab(nTab) && pTab[nTab] )
3133 pTab[nTab]->SetRowHeightRange
3134 ( nStartRow, nEndRow, nNewHeight, 1.0, 1.0 );
3138 void ScDocument::SetManualHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, BOOL bManual )
3140 if ( ValidTab(nTab) && pTab[nTab] )
3141 pTab[nTab]->SetManualHeight( nStartRow, nEndRow, bManual );
3145 USHORT ScDocument::GetColWidth( SCCOL nCol, SCTAB nTab ) const
3147 if ( ValidTab(nTab) && pTab[nTab] )
3148 return pTab[nTab]->GetColWidth( nCol );
3149 DBG_ERROR("Falsche Tabellennummer");
3150 return 0;
3154 USHORT ScDocument::GetOriginalWidth( SCCOL nCol, SCTAB nTab ) const
3156 if ( ValidTab(nTab) && pTab[nTab] )
3157 return pTab[nTab]->GetOriginalWidth( nCol );
3158 DBG_ERROR("Falsche Tabellennummer");
3159 return 0;
3163 USHORT ScDocument::GetCommonWidth( SCCOL nEndCol, SCTAB nTab ) const
3165 if ( ValidTab(nTab) && pTab[nTab] )
3166 return pTab[nTab]->GetCommonWidth( nEndCol );
3167 DBG_ERROR("Wrong table number");
3168 return 0;
3172 USHORT ScDocument::GetOriginalHeight( SCROW nRow, SCTAB nTab ) const
3174 if ( ValidTab(nTab) && pTab[nTab] )
3175 return pTab[nTab]->GetOriginalHeight( nRow );
3176 DBG_ERROR("Wrong table number");
3177 return 0;
3181 USHORT ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab ) const
3183 if ( ValidTab(nTab) && pTab[nTab] )
3184 return pTab[nTab]->GetRowHeight( nRow );
3185 DBG_ERROR("Falsche Tabellennummer");
3186 return 0;
3190 ULONG ScDocument::GetRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
3192 if (nStartRow == nEndRow)
3193 return GetRowHeight( nStartRow, nTab); // faster for a single row
3195 // check bounds because this method replaces former for(i=start;i<=end;++i) loops
3196 if (nStartRow > nEndRow)
3197 return 0;
3199 if ( ValidTab(nTab) && pTab[nTab] )
3200 return pTab[nTab]->GetRowHeight( nStartRow, nEndRow);
3202 DBG_ERROR("wrong sheet number");
3203 return 0;
3206 ULONG ScDocument::FastGetRowHeight( SCROW nStartRow, SCROW nEndRow,
3207 SCTAB nTab ) const
3209 return GetRowHeight(nStartRow, nEndRow, nTab);
3212 ULONG ScDocument::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow,
3213 SCTAB nTab, double fScale ) const
3215 // faster for a single row
3216 if (nStartRow == nEndRow)
3217 return (ULONG) (GetRowHeight( nStartRow, nTab) * fScale);
3219 // check bounds because this method replaces former for(i=start;i<=end;++i) loops
3220 if (nStartRow > nEndRow)
3221 return 0;
3223 if ( ValidTab(nTab) && pTab[nTab] )
3224 return pTab[nTab]->GetScaledRowHeight( nStartRow, nEndRow, fScale);
3226 DBG_ERROR("wrong sheet number");
3227 return 0;
3231 const ScSummableCompressedArray< SCROW, USHORT> & ScDocument::GetRowHeightArray(
3232 SCTAB nTab ) const
3234 const ScSummableCompressedArray< SCROW, USHORT> * pHeight;
3235 if ( ValidTab(nTab) && pTab[nTab] )
3236 pHeight = pTab[nTab]->GetRowHeightArray();
3237 else
3239 DBG_ERROR("wrong sheet number");
3240 pHeight = 0;
3242 if (!pHeight)
3244 DBG_ERROR("no row heights at sheet");
3245 static ScSummableCompressedArray< SCROW, USHORT> aDummy( MAXROW,
3246 ScGlobal::nStdRowHeight);
3247 pHeight = &aDummy;
3249 return *pHeight;
3253 SCROW ScDocument::GetHiddenRowCount( SCROW nRow, SCTAB nTab ) const
3255 if ( ValidTab(nTab) && pTab[nTab] )
3256 return pTab[nTab]->GetHiddenRowCount( nRow );
3257 DBG_ERROR("Falsche Tabellennummer");
3258 return 0;
3262 ULONG ScDocument::GetColOffset( SCCOL nCol, SCTAB nTab ) const
3264 if ( ValidTab(nTab) && pTab[nTab] )
3265 return pTab[nTab]->GetColOffset( nCol );
3266 DBG_ERROR("Falsche Tabellennummer");
3267 return 0;
3271 ULONG ScDocument::GetRowOffset( SCROW nRow, SCTAB nTab ) const
3273 if ( ValidTab(nTab) && pTab[nTab] )
3274 return pTab[nTab]->GetRowOffset( nRow );
3275 DBG_ERROR("Falsche Tabellennummer");
3276 return 0;
3280 USHORT ScDocument::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, OutputDevice* pDev,
3281 double nPPTX, double nPPTY,
3282 const Fraction& rZoomX, const Fraction& rZoomY,
3283 BOOL bFormula, const ScMarkData* pMarkData,
3284 BOOL bSimpleTextImport )
3286 if ( ValidTab(nTab) && pTab[nTab] )
3287 return pTab[nTab]->GetOptimalColWidth( nCol, pDev, nPPTX, nPPTY,
3288 rZoomX, rZoomY, bFormula, pMarkData, bSimpleTextImport );
3289 DBG_ERROR("Falsche Tabellennummer");
3290 return 0;
3294 long ScDocument::GetNeededSize( SCCOL nCol, SCROW nRow, SCTAB nTab,
3295 OutputDevice* pDev,
3296 double nPPTX, double nPPTY,
3297 const Fraction& rZoomX, const Fraction& rZoomY,
3298 BOOL bWidth, BOOL bTotalSize )
3300 if ( ValidTab(nTab) && pTab[nTab] )
3301 return pTab[nTab]->GetNeededSize
3302 ( nCol, nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, bTotalSize );
3303 DBG_ERROR("Falsche Tabellennummer");
3304 return 0;
3308 BOOL ScDocument::SetOptimalHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, USHORT nExtra,
3309 OutputDevice* pDev,
3310 double nPPTX, double nPPTY,
3311 const Fraction& rZoomX, const Fraction& rZoomY,
3312 BOOL bShrink )
3314 //! MarkToMulti();
3315 if ( ValidTab(nTab) && pTab[nTab] )
3316 return pTab[nTab]->SetOptimalHeight( nStartRow, nEndRow, nExtra,
3317 pDev, nPPTX, nPPTY, rZoomX, rZoomY, bShrink );
3318 DBG_ERROR("Falsche Tabellennummer");
3319 return FALSE;
3323 void ScDocument::UpdateAllRowHeights( OutputDevice* pDev, double nPPTX, double nPPTY,
3324 const Fraction& rZoomX, const Fraction& rZoomY, const ScMarkData* pTabMark )
3326 // one progress across all (selected) sheets
3328 ULONG nCellCount = 0;
3329 for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
3330 if ( pTab[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
3331 nCellCount += pTab[nTab]->GetWeightedCount();
3333 ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), nCellCount );
3335 ULONG nProgressStart = 0;
3336 for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
3337 if ( pTab[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
3339 pTab[nTab]->SetOptimalHeight( 0, MAXROW, 0,
3340 pDev, nPPTX, nPPTY, rZoomX, rZoomY, FALSE, &aProgress, nProgressStart );
3341 nProgressStart += pTab[nTab]->GetWeightedCount();
3347 // Spalten-/Zeilen-Flags ----------------------------------------------
3350 void ScDocument::ShowCol(SCCOL nCol, SCTAB nTab, BOOL bShow)
3352 if ( ValidTab(nTab) && pTab[nTab] )
3353 pTab[nTab]->ShowCol( nCol, bShow );
3357 void ScDocument::ShowRow(SCROW nRow, SCTAB nTab, BOOL bShow)
3359 if ( ValidTab(nTab) && pTab[nTab] )
3360 pTab[nTab]->ShowRow( nRow, bShow );
3364 void ScDocument::ShowRows(SCROW nRow1, SCROW nRow2, SCTAB nTab, BOOL bShow)
3366 if ( ValidTab(nTab) && pTab[nTab] )
3367 pTab[nTab]->ShowRows( nRow1, nRow2, bShow );
3371 void ScDocument::SetColFlags( SCCOL nCol, SCTAB nTab, BYTE nNewFlags )
3373 if ( ValidTab(nTab) && pTab[nTab] )
3374 pTab[nTab]->SetColFlags( nCol, nNewFlags );
3378 void ScDocument::SetRowFlags( SCROW nRow, SCTAB nTab, BYTE nNewFlags )
3380 if ( ValidTab(nTab) && pTab[nTab] )
3381 pTab[nTab]->SetRowFlags( nRow, nNewFlags );
3385 void ScDocument::SetRowFlags( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, BYTE nNewFlags )
3387 if ( ValidTab(nTab) && pTab[nTab] )
3388 pTab[nTab]->SetRowFlags( nStartRow, nEndRow, nNewFlags );
3392 BYTE ScDocument::GetColFlags( SCCOL nCol, SCTAB nTab ) const
3394 if ( ValidTab(nTab) && pTab[nTab] )
3395 return pTab[nTab]->GetColFlags( nCol );
3396 DBG_ERROR("Falsche Tabellennummer");
3397 return 0;
3400 BYTE ScDocument::GetRowFlags( SCROW nRow, SCTAB nTab ) const
3402 if ( ValidTab(nTab) && pTab[nTab] )
3403 return pTab[nTab]->GetRowFlags( nRow );
3404 DBG_ERROR("Falsche Tabellennummer");
3405 return 0;
3408 ScBitMaskCompressedArray< SCROW, BYTE> & ScDocument::GetRowFlagsArrayModifiable(
3409 SCTAB nTab )
3411 return const_cast< ScBitMaskCompressedArray< SCROW, BYTE> & >(
3412 GetRowFlagsArray( nTab));
3415 const ScBitMaskCompressedArray< SCROW, BYTE> & ScDocument::GetRowFlagsArray(
3416 SCTAB nTab ) const
3418 const ScBitMaskCompressedArray< SCROW, BYTE> * pFlags;
3419 if ( ValidTab(nTab) && pTab[nTab] )
3420 pFlags = pTab[nTab]->GetRowFlagsArray();
3421 else
3423 DBG_ERROR("wrong sheet number");
3424 pFlags = 0;
3426 if (!pFlags)
3428 DBG_ERROR("no row flags at sheet");
3429 static ScBitMaskCompressedArray< SCROW, BYTE> aDummy( MAXROW, 0);
3430 pFlags = &aDummy;
3432 return *pFlags;
3435 void ScDocument::GetAllRowBreaks(set<SCROW>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
3437 if (!ValidTab(nTab) || !pTab[nTab])
3438 return;
3440 pTab[nTab]->GetAllRowBreaks(rBreaks, bPage, bManual);
3443 void ScDocument::GetAllColBreaks(set<SCCOL>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
3445 if (!ValidTab(nTab) || !pTab[nTab])
3446 return;
3448 pTab[nTab]->GetAllColBreaks(rBreaks, bPage, bManual);
3451 ScBreakType ScDocument::HasRowBreak(SCROW nRow, SCTAB nTab) const
3453 ScBreakType nType = BREAK_NONE;
3454 if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
3455 return nType;
3457 if (pTab[nTab]->HasRowPageBreak(nRow))
3458 nType |= BREAK_PAGE;
3460 if (pTab[nTab]->HasRowManualBreak(nRow))
3461 nType |= BREAK_MANUAL;
3463 return nType;
3466 ScBreakType ScDocument::HasColBreak(SCCOL nCol, SCTAB nTab) const
3468 ScBreakType nType = BREAK_NONE;
3469 if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
3470 return nType;
3472 if (pTab[nTab]->HasColPageBreak(nCol))
3473 nType |= BREAK_PAGE;
3475 if (pTab[nTab]->HasColManualBreak(nCol))
3476 nType |= BREAK_MANUAL;
3478 return nType;
3481 void ScDocument::SetRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
3483 if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
3484 return;
3486 pTab[nTab]->SetRowBreak(nRow, bPage, bManual);
3489 void ScDocument::SetColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
3491 if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
3492 return;
3494 pTab[nTab]->SetColBreak(nCol, bPage, bManual);
3497 void ScDocument::RemoveRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
3499 if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
3500 return;
3502 pTab[nTab]->RemoveRowBreak(nRow, bPage, bManual);
3505 void ScDocument::RemoveColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
3507 if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
3508 return;
3510 pTab[nTab]->RemoveColBreak(nCol, bPage, bManual);
3513 Sequence<TablePageBreakData> ScDocument::GetRowBreakData(SCTAB nTab) const
3515 if (!ValidTab(nTab) || !pTab[nTab])
3516 return Sequence<TablePageBreakData>();
3518 return pTab[nTab]->GetRowBreakData();
3521 bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow)
3523 if (!ValidTab(nTab) || !pTab[nTab])
3524 return false;
3526 return pTab[nTab]->RowHidden(nRow, pFirstRow, pLastRow);
3529 bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW& rLastRow)
3531 if (!ValidTab(nTab) || !pTab[nTab])
3533 rLastRow = nRow;
3534 return false;
3537 return pTab[nTab]->RowHidden(nRow, rLastRow);
3541 bool ScDocument::HasHiddenRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3543 if (!ValidTab(nTab) || !pTab[nTab])
3544 return false;
3546 return pTab[nTab]->HasHiddenRows(nStartRow, nEndRow);
3549 bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL& rLastCol)
3551 if (!ValidTab(nTab) || !pTab[nTab])
3553 rLastCol = nCol;
3554 return false;
3557 return pTab[nTab]->ColHidden(nCol, rLastCol);
3560 bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol)
3562 if (!ValidTab(nTab) || !pTab[nTab])
3564 if (pFirstCol)
3565 *pFirstCol = nCol;
3566 if (pLastCol)
3567 *pLastCol = nCol;
3568 return false;
3571 return pTab[nTab]->ColHidden(nCol, pFirstCol, pLastCol);
3574 void ScDocument::SetRowHidden(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHidden)
3576 if (!ValidTab(nTab) || !pTab[nTab])
3577 return;
3579 pTab[nTab]->SetRowHidden(nStartRow, nEndRow, bHidden);
3582 void ScDocument::SetColHidden(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bHidden)
3584 if (!ValidTab(nTab) || !pTab[nTab])
3585 return;
3587 pTab[nTab]->SetColHidden(nStartCol, nEndCol, bHidden);
3590 SCROW ScDocument::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3592 if (!ValidTab(nTab) || !pTab[nTab])
3593 return ::std::numeric_limits<SCROW>::max();;
3595 return pTab[nTab]->FirstVisibleRow(nStartRow, nEndRow);
3598 SCROW ScDocument::LastVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3600 if (!ValidTab(nTab) || !pTab[nTab])
3601 return ::std::numeric_limits<SCROW>::max();;
3603 return pTab[nTab]->LastVisibleRow(nStartRow, nEndRow);
3606 SCROW ScDocument::CountVisibleRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3608 if (!ValidTab(nTab) || !pTab[nTab])
3609 return 0;
3611 return pTab[nTab]->CountVisibleRows(nStartRow, nEndRow);
3614 bool ScDocument::RowFiltered(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow)
3616 if (!ValidTab(nTab) || !pTab[nTab])
3617 return false;
3619 return pTab[nTab]->RowFiltered(nRow, pFirstRow, pLastRow);
3622 bool ScDocument::HasFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3624 if (!ValidTab(nTab) || !pTab[nTab])
3625 return false;
3627 return pTab[nTab]->HasFilteredRows(nStartRow, nEndRow);
3630 bool ScDocument::ColFiltered(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol)
3632 if (!ValidTab(nTab) || !pTab[nTab])
3633 return false;
3635 return pTab[nTab]->ColFiltered(nCol, pFirstCol, pLastCol);
3638 void ScDocument::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bFiltered)
3640 if (!ValidTab(nTab) || !pTab[nTab])
3641 return;
3643 pTab[nTab]->SetRowFiltered(nStartRow, nEndRow, bFiltered);
3646 void ScDocument::SetColFiltered(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bFiltered)
3648 if (!ValidTab(nTab) || !pTab[nTab])
3649 return;
3651 pTab[nTab]->SetColFiltered(nStartCol, nEndCol, bFiltered);
3654 SCROW ScDocument::FirstNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3656 if (!ValidTab(nTab) || !pTab[nTab])
3657 return ::std::numeric_limits<SCROW>::max();;
3659 return pTab[nTab]->FirstNonFilteredRow(nStartRow, nEndRow);
3662 SCROW ScDocument::LastNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3664 if (!ValidTab(nTab) || !pTab[nTab])
3665 return ::std::numeric_limits<SCROW>::max();;
3667 return pTab[nTab]->LastNonFilteredRow(nStartRow, nEndRow);
3670 SCROW ScDocument::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
3672 if (!ValidTab(nTab) || !pTab[nTab])
3673 return 0;
3675 return pTab[nTab]->CountNonFilteredRows(nStartRow, nEndRow);
3678 void ScDocument::SyncColRowFlags()
3680 for (SCTAB i = 0; i <= nMaxTableNumber; ++i)
3682 if (!ValidTab(i) || !pTab[i])
3683 continue;
3685 pTab[i]->SyncColRowFlags();
3689 SCROW ScDocument::GetLastFlaggedRow( SCTAB nTab ) const
3691 if ( ValidTab(nTab) && pTab[nTab] )
3692 return pTab[nTab]->GetLastFlaggedRow();
3693 return 0;
3697 SCCOL ScDocument::GetLastChangedCol( SCTAB nTab ) const
3699 if ( ValidTab(nTab) && pTab[nTab] )
3700 return pTab[nTab]->GetLastChangedCol();
3701 return 0;
3704 SCROW ScDocument::GetLastChangedRow( SCTAB nTab ) const
3706 if ( ValidTab(nTab) && pTab[nTab] )
3707 return pTab[nTab]->GetLastChangedRow();
3708 return 0;
3712 SCCOL ScDocument::GetNextDifferentChangedCol( SCTAB nTab, SCCOL nStart) const
3714 if ( ValidTab(nTab) && pTab[nTab] )
3716 BYTE nStartFlags = pTab[nTab]->GetColFlags(nStart);
3717 USHORT nStartWidth = pTab[nTab]->GetOriginalWidth(nStart);
3718 for (SCCOL nCol = nStart + 1; nCol <= MAXCOL; nCol++)
3720 if (((nStartFlags & CR_MANUALBREAK) != (pTab[nTab]->GetColFlags(nCol) & CR_MANUALBREAK)) ||
3721 (nStartWidth != pTab[nTab]->GetOriginalWidth(nCol)) ||
3722 ((nStartFlags & CR_HIDDEN) != (pTab[nTab]->GetColFlags(nCol) & CR_HIDDEN)) )
3723 return nCol;
3725 return MAXCOL+1;
3727 return 0;
3730 SCROW ScDocument::GetNextDifferentChangedRow( SCTAB nTab, SCROW nStart, bool bCareManualSize) const
3732 if ( ValidTab(nTab) && pTab[nTab] && pTab[nTab]->GetRowFlagsArray() && pTab[nTab]->GetRowHeightArray() )
3734 BYTE nStartFlags = pTab[nTab]->GetRowFlags(nStart);
3735 USHORT nStartHeight = pTab[nTab]->GetOriginalHeight(nStart);
3736 for (SCROW nRow = nStart + 1; nRow <= MAXROW; nRow++)
3738 size_t nIndex; // ignored
3739 SCROW nFlagsEndRow;
3740 SCROW nHeightEndRow;
3741 BYTE nFlags = pTab[nTab]->GetRowFlagsArray()->GetValue( nRow, nIndex, nFlagsEndRow );
3742 USHORT nHeight = pTab[nTab]->GetRowHeightArray()->GetValue( nRow, nIndex, nHeightEndRow );
3743 if (((nStartFlags & CR_MANUALBREAK) != (nFlags & CR_MANUALBREAK)) ||
3744 ((nStartFlags & CR_MANUALSIZE) != (nFlags & CR_MANUALSIZE)) ||
3745 (bCareManualSize && (nStartFlags & CR_MANUALSIZE) && (nStartHeight != nHeight)) ||
3746 (!bCareManualSize && ((nStartHeight != nHeight))))
3747 return nRow;
3749 nRow = std::min( nFlagsEndRow, nHeightEndRow );
3751 return MAXROW+1;
3753 return 0;
3756 BOOL ScDocument::GetColDefault( SCTAB nTab, SCCOL nCol, SCROW nLastRow, SCROW& nDefault)
3758 BOOL bRet(FALSE);
3759 nDefault = 0;
3760 ScDocAttrIterator aDocAttrItr(this, nTab, nCol, 0, nCol, nLastRow);
3761 SCCOL nColumn;
3762 SCROW nStartRow;
3763 SCROW nEndRow;
3764 const ScPatternAttr* pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
3765 if (nEndRow < nLastRow)
3767 ScDefaultAttrSet aSet;
3768 ScDefaultAttrSet::iterator aItr = aSet.end();
3769 while (pAttr)
3771 ScDefaultAttr aAttr(pAttr);
3772 aItr = aSet.find(aAttr);
3773 if (aItr == aSet.end())
3775 aAttr.nCount = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
3776 aAttr.nFirst = nStartRow;
3777 aSet.insert(aAttr);
3779 else
3781 aAttr.nCount = aItr->nCount + static_cast<SCSIZE>(nEndRow - nStartRow + 1);
3782 aAttr.nFirst = aItr->nFirst;
3783 aSet.erase(aItr);
3784 aSet.insert(aAttr);
3786 pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
3788 ScDefaultAttrSet::iterator aDefaultItr = aSet.begin();
3789 aItr = aDefaultItr;
3790 aItr++;
3791 while (aItr != aSet.end())
3793 // for entries with equal count, use the one with the lowest start row,
3794 // don't use the random order of pointer comparisons
3795 if ( aItr->nCount > aDefaultItr->nCount ||
3796 ( aItr->nCount == aDefaultItr->nCount && aItr->nFirst < aDefaultItr->nFirst ) )
3797 aDefaultItr = aItr;
3798 aItr++;
3800 nDefault = aDefaultItr->nFirst;
3801 bRet = TRUE;
3803 else
3804 bRet = TRUE;
3805 return bRet;
3808 BOOL ScDocument::GetRowDefault( SCTAB /* nTab */, SCROW /* nRow */, SCCOL /* nLastCol */, SCCOL& /* nDefault */ )
3810 BOOL bRet(FALSE);
3811 return bRet;
3814 void ScDocument::StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
3816 if ( ValidTab(nTab) && pTab[nTab] )
3817 pTab[nTab]->StripHidden( rX1, rY1, rX2, rY2 );
3821 void ScDocument::ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
3823 if ( ValidTab(nTab) && pTab[nTab] )
3824 pTab[nTab]->ExtendHidden( rX1, rY1, rX2, rY2 );
3828 // Attribute ----------------------------------------------------------
3831 const SfxPoolItem* ScDocument::GetAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, USHORT nWhich ) const
3833 if ( ValidTab(nTab) && pTab[nTab] )
3835 const SfxPoolItem* pTemp = pTab[nTab]->GetAttr( nCol, nRow, nWhich );
3836 if (pTemp)
3837 return pTemp;
3838 else
3840 DBG_ERROR( "Attribut Null" );
3843 return &xPoolHelper->GetDocPool()->GetDefaultItem( nWhich );
3847 const ScPatternAttr* ScDocument::GetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3849 if ( ValidTab(nTab) && pTab[nTab] )
3850 return pTab[nTab]->GetPattern( nCol, nRow );
3851 return NULL;
3855 const ScPatternAttr* ScDocument::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
3857 if ( ValidTab(nTab) && pTab[nTab] )
3858 return pTab[nTab]->GetMostUsedPattern( nCol, nStartRow, nEndRow );
3859 return NULL;
3863 void ScDocument::ApplyAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem& rAttr )
3865 if ( ValidTab(nTab) && pTab[nTab] )
3866 pTab[nTab]->ApplyAttr( nCol, nRow, rAttr );
3870 void ScDocument::ApplyPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr )
3872 if ( ValidTab(nTab) && pTab[nTab] )
3873 pTab[nTab]->ApplyPattern( nCol, nRow, rAttr );
3877 void ScDocument::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow,
3878 SCCOL nEndCol, SCROW nEndRow,
3879 const ScMarkData& rMark,
3880 const ScPatternAttr& rAttr,
3881 ScEditDataArray* pDataArray )
3883 for (SCTAB i=0; i <= MAXTAB; i++)
3884 if (pTab[i])
3885 if (rMark.GetTableSelect(i))
3886 pTab[i]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr, pDataArray );
3890 void ScDocument::ApplyPatternAreaTab( SCCOL nStartCol, SCROW nStartRow,
3891 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScPatternAttr& rAttr )
3893 if (VALIDTAB(nTab))
3894 if (pTab[nTab])
3895 pTab[nTab]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
3898 void ScDocument::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
3899 const ScMarkData& rMark, const ScPatternAttr& rPattern, short nNewType )
3901 for (SCTAB i=0; i <= MAXTAB; i++)
3902 if (pTab[i])
3903 if (rMark.GetTableSelect(i))
3904 pTab[i]->ApplyPatternIfNumberformatIncompatible( rRange, rPattern, nNewType );
3908 void ScDocument::ApplyStyle( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScStyleSheet& rStyle)
3910 if (VALIDTAB(nTab))
3911 if (pTab[nTab])
3912 pTab[nTab]->ApplyStyle( nCol, nRow, rStyle );
3916 void ScDocument::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow,
3917 SCCOL nEndCol, SCROW nEndRow,
3918 const ScMarkData& rMark,
3919 const ScStyleSheet& rStyle)
3921 for (SCTAB i=0; i <= MAXTAB; i++)
3922 if (pTab[i])
3923 if (rMark.GetTableSelect(i))
3924 pTab[i]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
3928 void ScDocument::ApplyStyleAreaTab( SCCOL nStartCol, SCROW nStartRow,
3929 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScStyleSheet& rStyle)
3931 if (VALIDTAB(nTab))
3932 if (pTab[nTab])
3933 pTab[nTab]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
3937 void ScDocument::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
3939 // ApplySelectionStyle needs multi mark
3940 if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
3942 ScRange aRange;
3943 rMark.GetMarkArea( aRange );
3944 ApplyStyleArea( aRange.aStart.Col(), aRange.aStart.Row(),
3945 aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rStyle );
3947 else
3949 for (SCTAB i=0; i<=MAXTAB; i++)
3950 if ( pTab[i] && rMark.GetTableSelect(i) )
3951 pTab[i]->ApplySelectionStyle( rStyle, rMark );
3956 void ScDocument::ApplySelectionLineStyle( const ScMarkData& rMark,
3957 const SvxBorderLine* pLine, BOOL bColorOnly )
3959 if ( bColorOnly && !pLine )
3960 return;
3962 for (SCTAB i=0; i<=MAXTAB; i++)
3963 if (pTab[i])
3964 if (rMark.GetTableSelect(i))
3965 pTab[i]->ApplySelectionLineStyle( rMark, pLine, bColorOnly );
3969 const ScStyleSheet* ScDocument::GetStyle( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3971 if ( VALIDTAB(nTab) && pTab[nTab] )
3972 return pTab[nTab]->GetStyle(nCol, nRow);
3973 else
3974 return NULL;
3978 const ScStyleSheet* ScDocument::GetSelectionStyle( const ScMarkData& rMark ) const
3980 BOOL bEqual = TRUE;
3981 BOOL bFound;
3983 const ScStyleSheet* pStyle = NULL;
3984 const ScStyleSheet* pNewStyle;
3986 if ( rMark.IsMultiMarked() )
3987 for (SCTAB i=0; i<=MAXTAB && bEqual; i++)
3988 if (pTab[i] && rMark.GetTableSelect(i))
3990 pNewStyle = pTab[i]->GetSelectionStyle( rMark, bFound );
3991 if (bFound)
3993 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
3994 bEqual = FALSE; // unterschiedliche
3995 pStyle = pNewStyle;
3998 if ( rMark.IsMarked() )
4000 ScRange aRange;
4001 rMark.GetMarkArea( aRange );
4002 for (SCTAB i=aRange.aStart.Tab(); i<=aRange.aEnd.Tab() && bEqual; i++)
4003 if (pTab[i] && rMark.GetTableSelect(i))
4005 pNewStyle = pTab[i]->GetAreaStyle( bFound,
4006 aRange.aStart.Col(), aRange.aStart.Row(),
4007 aRange.aEnd.Col(), aRange.aEnd.Row() );
4008 if (bFound)
4010 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
4011 bEqual = FALSE; // unterschiedliche
4012 pStyle = pNewStyle;
4017 return bEqual ? pStyle : NULL;
4021 void ScDocument::StyleSheetChanged( const SfxStyleSheetBase* pStyleSheet, BOOL bRemoved,
4022 OutputDevice* pDev,
4023 double nPPTX, double nPPTY,
4024 const Fraction& rZoomX, const Fraction& rZoomY )
4026 for (SCTAB i=0; i <= MAXTAB; i++)
4027 if (pTab[i])
4028 pTab[i]->StyleSheetChanged
4029 ( pStyleSheet, bRemoved, pDev, nPPTX, nPPTY, rZoomX, rZoomY );
4031 if ( pStyleSheet && pStyleSheet->GetName() == ScGlobal::GetRscString(STR_STYLENAME_STANDARD) )
4033 // update attributes for all note objects
4034 ScDetectiveFunc::UpdateAllComments( *this );
4039 BOOL ScDocument::IsStyleSheetUsed( const ScStyleSheet& rStyle, BOOL bGatherAllStyles ) const
4041 if ( bStyleSheetUsageInvalid || rStyle.GetUsage() == ScStyleSheet::UNKNOWN )
4043 if ( bGatherAllStyles )
4045 SfxStyleSheetIterator aIter( xPoolHelper->GetStylePool(),
4046 SFX_STYLE_FAMILY_PARA );
4047 for ( const SfxStyleSheetBase* pStyle = aIter.First(); pStyle;
4048 pStyle = aIter.Next() )
4050 const ScStyleSheet* pScStyle = PTR_CAST( ScStyleSheet, pStyle );
4051 if ( pScStyle )
4052 pScStyle->SetUsage( ScStyleSheet::NOTUSED );
4056 BOOL bIsUsed = FALSE;
4058 for ( SCTAB i=0; i<=MAXTAB; i++ )
4060 if ( pTab[i] )
4062 if ( pTab[i]->IsStyleSheetUsed( rStyle, bGatherAllStyles ) )
4064 if ( !bGatherAllStyles )
4065 return TRUE;
4066 bIsUsed = TRUE;
4071 if ( bGatherAllStyles )
4072 bStyleSheetUsageInvalid = FALSE;
4074 return bIsUsed;
4077 return rStyle.GetUsage() == ScStyleSheet::USED;
4081 BOOL ScDocument::ApplyFlagsTab( SCCOL nStartCol, SCROW nStartRow,
4082 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, INT16 nFlags )
4084 if (VALIDTAB(nTab))
4085 if (pTab[nTab])
4086 return pTab[nTab]->ApplyFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
4088 DBG_ERROR("ApplyFlags: falsche Tabelle");
4089 return FALSE;
4093 BOOL ScDocument::RemoveFlagsTab( SCCOL nStartCol, SCROW nStartRow,
4094 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, INT16 nFlags )
4096 if (VALIDTAB(nTab))
4097 if (pTab[nTab])
4098 return pTab[nTab]->RemoveFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
4100 DBG_ERROR("RemoveFlags: falsche Tabelle");
4101 return FALSE;
4105 void ScDocument::SetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr,
4106 BOOL bPutToPool )
4108 if (VALIDTAB(nTab))
4109 if (pTab[nTab])
4110 pTab[nTab]->SetPattern( nCol, nRow, rAttr, bPutToPool );
4114 void ScDocument::SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr,
4115 BOOL bPutToPool )
4117 SCTAB nTab = rPos.Tab();
4118 if (pTab[nTab])
4119 pTab[nTab]->SetPattern( rPos, rAttr, bPutToPool );
4123 ScPatternAttr* ScDocument::CreateSelectionPattern( const ScMarkData& rMark, BOOL bDeep )
4125 ScMergePatternState aState;
4127 if ( rMark.IsMultiMarked() ) // multi selection
4129 for (SCTAB i=0; i<=MAXTAB; i++)
4130 if (pTab[i] && rMark.GetTableSelect(i))
4131 pTab[i]->MergeSelectionPattern( aState, rMark, bDeep );
4133 if ( rMark.IsMarked() ) // simle selection
4135 ScRange aRange;
4136 rMark.GetMarkArea(aRange);
4137 for (SCTAB i=0; i<=MAXTAB; i++)
4138 if (pTab[i] && rMark.GetTableSelect(i))
4139 pTab[i]->MergePatternArea( aState,
4140 aRange.aStart.Col(), aRange.aStart.Row(),
4141 aRange.aEnd.Col(), aRange.aEnd.Row(), bDeep );
4144 DBG_ASSERT( aState.pItemSet, "SelectionPattern Null" );
4145 if (aState.pItemSet)
4146 return new ScPatternAttr( aState.pItemSet );
4147 else
4148 return new ScPatternAttr( GetPool() ); // empty
4152 const ScPatternAttr* ScDocument::GetSelectionPattern( const ScMarkData& rMark, BOOL bDeep )
4154 delete pSelectionAttr;
4155 pSelectionAttr = CreateSelectionPattern( rMark, bDeep );
4156 return pSelectionAttr;
4160 void ScDocument::GetSelectionFrame( const ScMarkData& rMark,
4161 SvxBoxItem& rLineOuter,
4162 SvxBoxInfoItem& rLineInner )
4164 rLineOuter.SetLine(NULL, BOX_LINE_TOP);
4165 rLineOuter.SetLine(NULL, BOX_LINE_BOTTOM);
4166 rLineOuter.SetLine(NULL, BOX_LINE_LEFT);
4167 rLineOuter.SetLine(NULL, BOX_LINE_RIGHT);
4168 rLineOuter.SetDistance(0);
4170 rLineInner.SetLine(NULL, BOXINFO_LINE_HORI);
4171 rLineInner.SetLine(NULL, BOXINFO_LINE_VERT);
4172 rLineInner.SetTable(TRUE);
4173 rLineInner.SetDist(TRUE);
4174 rLineInner.SetMinDist(FALSE);
4176 ScLineFlags aFlags;
4178 if (rMark.IsMarked())
4180 ScRange aRange;
4181 rMark.GetMarkArea(aRange);
4182 rLineInner.EnableHor( aRange.aStart.Row() != aRange.aEnd.Row() );
4183 rLineInner.EnableVer( aRange.aStart.Col() != aRange.aEnd.Col() );
4184 for (SCTAB i=0; i<=MAXTAB; i++)
4185 if (pTab[i] && rMark.GetTableSelect(i))
4186 pTab[i]->MergeBlockFrame( &rLineOuter, &rLineInner, aFlags,
4187 aRange.aStart.Col(), aRange.aStart.Row(),
4188 aRange.aEnd.Col(), aRange.aEnd.Row() );
4191 // Don't care Status auswerten
4193 rLineInner.SetValid( VALID_LEFT, ( aFlags.nLeft != SC_LINE_DONTCARE ) );
4194 rLineInner.SetValid( VALID_RIGHT, ( aFlags.nRight != SC_LINE_DONTCARE ) );
4195 rLineInner.SetValid( VALID_TOP, ( aFlags.nTop != SC_LINE_DONTCARE ) );
4196 rLineInner.SetValid( VALID_BOTTOM, ( aFlags.nBottom != SC_LINE_DONTCARE ) );
4197 rLineInner.SetValid( VALID_HORI, ( aFlags.nHori != SC_LINE_DONTCARE ) );
4198 rLineInner.SetValid( VALID_VERT, ( aFlags.nVert != SC_LINE_DONTCARE ) );
4202 BOOL ScDocument::HasAttrib( SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
4203 SCCOL nCol2, SCROW nRow2, SCTAB nTab2, USHORT nMask )
4205 if ( nMask & HASATTR_ROTATE )
4207 // Attribut im Dokument ueberhaupt verwendet?
4208 // (wie in fillinfo)
4210 ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4212 BOOL bAnyItem = FALSE;
4213 USHORT nRotCount = pPool->GetItemCount( ATTR_ROTATE_VALUE );
4214 for (USHORT nItem=0; nItem<nRotCount; nItem++)
4216 const SfxPoolItem* pItem = pPool->GetItem( ATTR_ROTATE_VALUE, nItem );
4217 if ( pItem )
4219 // 90 or 270 degrees is former SvxOrientationItem - only look for other values
4220 // (see ScPatternAttr::GetCellOrientation)
4221 INT32 nAngle = static_cast<const SfxInt32Item*>(pItem)->GetValue();
4222 if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
4224 bAnyItem = TRUE;
4225 break;
4229 if (!bAnyItem)
4230 nMask &= ~HASATTR_ROTATE;
4233 if ( nMask & HASATTR_RTL )
4235 // first check if right-to left is in the pool at all
4236 // (the same item is used in cell and page format)
4238 ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4240 BOOL bHasRtl = FALSE;
4241 USHORT nDirCount = pPool->GetItemCount( ATTR_WRITINGDIR );
4242 for (USHORT nItem=0; nItem<nDirCount; nItem++)
4244 const SfxPoolItem* pItem = pPool->GetItem( ATTR_WRITINGDIR, nItem );
4245 if ( pItem && ((const SvxFrameDirectionItem*)pItem)->GetValue() == FRMDIR_HORI_RIGHT_TOP )
4247 bHasRtl = TRUE;
4248 break;
4251 if (!bHasRtl)
4252 nMask &= ~HASATTR_RTL;
4255 if (!nMask)
4256 return FALSE;
4258 BOOL bFound = FALSE;
4259 for (SCTAB i=nTab1; i<=nTab2 && !bFound; i++)
4260 if (pTab[i])
4262 if ( nMask & HASATTR_RTL )
4264 if ( GetEditTextDirection(i) == EE_HTEXTDIR_R2L ) // sheet default
4265 bFound = TRUE;
4267 if ( nMask & HASATTR_RIGHTORCENTER )
4269 // On a RTL sheet, don't start to look for the default left value
4270 // (which is then logically right), instead always assume TRUE.
4271 // That way, ScAttrArray::HasAttrib doesn't have to handle RTL sheets.
4273 if ( IsLayoutRTL(i) )
4274 bFound = TRUE;
4277 if ( !bFound )
4278 bFound = pTab[i]->HasAttrib( nCol1, nRow1, nCol2, nRow2, nMask );
4281 return bFound;
4284 BOOL ScDocument::HasAttrib( const ScRange& rRange, USHORT nMask )
4286 return HasAttrib( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
4287 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(),
4288 nMask );
4291 void ScDocument::FindMaxRotCol( SCTAB nTab, RowInfo* pRowInfo, SCSIZE nArrCount,
4292 SCCOL nX1, SCCOL nX2 ) const
4294 if ( ValidTab(nTab) && pTab[nTab] )
4295 pTab[nTab]->FindMaxRotCol( pRowInfo, nArrCount, nX1, nX2 );
4296 else
4298 DBG_ERRORFILE("FindMaxRotCol: falsche Tabelle");
4302 void ScDocument::GetBorderLines( SCCOL nCol, SCROW nRow, SCTAB nTab,
4303 const SvxBorderLine** ppLeft, const SvxBorderLine** ppTop,
4304 const SvxBorderLine** ppRight, const SvxBorderLine** ppBottom ) const
4306 //! Seitengrenzen fuer Druck beruecksichtigen !!!!!
4308 const SvxBoxItem* pThisAttr = (const SvxBoxItem*) GetEffItem( nCol, nRow, nTab, ATTR_BORDER );
4309 DBG_ASSERT(pThisAttr,"wo ist das Attribut?");
4311 const SvxBorderLine* pLeftLine = pThisAttr->GetLeft();
4312 const SvxBorderLine* pTopLine = pThisAttr->GetTop();
4313 const SvxBorderLine* pRightLine = pThisAttr->GetRight();
4314 const SvxBorderLine* pBottomLine = pThisAttr->GetBottom();
4316 if ( nCol > 0 )
4318 const SvxBorderLine* pOther = ((const SvxBoxItem*)
4319 GetEffItem( nCol-1, nRow, nTab, ATTR_BORDER ))->GetRight();
4320 if ( ScHasPriority( pOther, pLeftLine ) )
4321 pLeftLine = pOther;
4323 if ( nRow > 0 )
4325 const SvxBorderLine* pOther = ((const SvxBoxItem*)
4326 GetEffItem( nCol, nRow-1, nTab, ATTR_BORDER ))->GetBottom();
4327 if ( ScHasPriority( pOther, pTopLine ) )
4328 pTopLine = pOther;
4330 if ( nCol < MAXCOL )
4332 const SvxBorderLine* pOther = ((const SvxBoxItem*)
4333 GetEffItem( nCol+1, nRow, nTab, ATTR_BORDER ))->GetLeft();
4334 if ( ScHasPriority( pOther, pRightLine ) )
4335 pRightLine = pOther;
4337 if ( nRow < MAXROW )
4339 const SvxBorderLine* pOther = ((const SvxBoxItem*)
4340 GetEffItem( nCol, nRow+1, nTab, ATTR_BORDER ))->GetTop();
4341 if ( ScHasPriority( pOther, pBottomLine ) )
4342 pBottomLine = pOther;
4345 if (ppLeft)
4346 *ppLeft = pLeftLine;
4347 if (ppTop)
4348 *ppTop = pTopLine;
4349 if (ppRight)
4350 *ppRight = pRightLine;
4351 if (ppBottom)
4352 *ppBottom = pBottomLine;
4355 BOOL ScDocument::IsBlockEmpty( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
4356 SCCOL nEndCol, SCROW nEndRow, bool bIgnoreNotes ) const
4358 if (VALIDTAB(nTab))
4359 if (pTab[nTab])
4360 return pTab[nTab]->IsBlockEmpty( nStartCol, nStartRow, nEndCol, nEndRow, bIgnoreNotes );
4362 DBG_ERROR("Falsche Tabellennummer");
4363 return FALSE;
4367 void ScDocument::LockTable(SCTAB nTab)
4369 if ( ValidTab(nTab) && pTab[nTab] )
4370 pTab[nTab]->LockTable();
4371 else
4373 DBG_ERROR("Falsche Tabellennummer");
4378 void ScDocument::UnlockTable(SCTAB nTab)
4380 if ( ValidTab(nTab) && pTab[nTab] )
4381 pTab[nTab]->UnlockTable();
4382 else
4384 DBG_ERROR("Falsche Tabellennummer");
4389 BOOL ScDocument::IsBlockEditable( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
4390 SCCOL nEndCol, SCROW nEndRow,
4391 BOOL* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
4393 // import into read-only document is possible
4394 if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
4396 if ( pOnlyNotBecauseOfMatrix )
4397 *pOnlyNotBecauseOfMatrix = FALSE;
4398 return FALSE;
4401 if (VALIDTAB(nTab))
4402 if (pTab[nTab])
4403 return pTab[nTab]->IsBlockEditable( nStartCol, nStartRow, nEndCol,
4404 nEndRow, pOnlyNotBecauseOfMatrix );
4406 DBG_ERROR("Falsche Tabellennummer");
4407 if ( pOnlyNotBecauseOfMatrix )
4408 *pOnlyNotBecauseOfMatrix = FALSE;
4409 return FALSE;
4413 BOOL ScDocument::IsSelectionEditable( const ScMarkData& rMark,
4414 BOOL* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
4416 // import into read-only document is possible
4417 if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
4419 if ( pOnlyNotBecauseOfMatrix )
4420 *pOnlyNotBecauseOfMatrix = FALSE;
4421 return FALSE;
4424 ScRange aRange;
4425 rMark.GetMarkArea(aRange);
4427 BOOL bOk = TRUE;
4428 BOOL bMatrix = ( pOnlyNotBecauseOfMatrix != NULL );
4429 for ( SCTAB i=0; i<=MAXTAB && (bOk || bMatrix); i++ )
4431 if ( pTab[i] && rMark.GetTableSelect(i) )
4433 if (rMark.IsMarked())
4435 if ( !pTab[i]->IsBlockEditable( aRange.aStart.Col(),
4436 aRange.aStart.Row(), aRange.aEnd.Col(),
4437 aRange.aEnd.Row(), pOnlyNotBecauseOfMatrix ) )
4439 bOk = FALSE;
4440 if ( pOnlyNotBecauseOfMatrix )
4441 bMatrix = *pOnlyNotBecauseOfMatrix;
4444 if (rMark.IsMultiMarked())
4446 if ( !pTab[i]->IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix ) )
4448 bOk = FALSE;
4449 if ( pOnlyNotBecauseOfMatrix )
4450 bMatrix = *pOnlyNotBecauseOfMatrix;
4456 if ( pOnlyNotBecauseOfMatrix )
4457 *pOnlyNotBecauseOfMatrix = ( !bOk && bMatrix );
4459 return bOk;
4463 BOOL ScDocument::HasSelectedBlockMatrixFragment( SCCOL nStartCol, SCROW nStartRow,
4464 SCCOL nEndCol, SCROW nEndRow,
4465 const ScMarkData& rMark ) const
4467 BOOL bOk = TRUE;
4468 for (SCTAB i=0; i<=MAXTAB && bOk; i++)
4469 if (pTab[i])
4470 if (rMark.GetTableSelect(i))
4471 if (pTab[i]->HasBlockMatrixFragment( nStartCol, nStartRow, nEndCol, nEndRow ))
4472 bOk = FALSE;
4474 return !bOk;
4478 BOOL ScDocument::GetMatrixFormulaRange( const ScAddress& rCellPos, ScRange& rMatrix )
4480 // if rCell is part of a matrix formula, return its complete range
4482 BOOL bRet = FALSE;
4483 ScBaseCell* pCell = GetCell( rCellPos );
4484 if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
4486 ScAddress aOrigin = rCellPos;
4487 if ( ((ScFormulaCell*)pCell)->GetMatrixOrigin( aOrigin ) )
4489 if ( aOrigin != rCellPos )
4490 pCell = GetCell( aOrigin );
4491 if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
4493 SCCOL nSizeX;
4494 SCROW nSizeY;
4495 ((ScFormulaCell*)pCell)->GetMatColsRows(nSizeX,nSizeY);
4496 if ( !(nSizeX > 0 && nSizeY > 0) )
4498 // GetMatrixEdge computes also dimensions of the matrix
4499 // if not already done (may occur if document is loaded
4500 // from old file format).
4501 // Needs an "invalid" initialized address.
4502 aOrigin.SetInvalid();
4503 ((ScFormulaCell*)pCell)->GetMatrixEdge(aOrigin);
4504 ((ScFormulaCell*)pCell)->GetMatColsRows(nSizeX,nSizeY);
4506 if ( nSizeX > 0 && nSizeY > 0 )
4508 ScAddress aEnd( aOrigin.Col() + nSizeX - 1,
4509 aOrigin.Row() + nSizeY - 1,
4510 aOrigin.Tab() );
4512 rMatrix.aStart = aOrigin;
4513 rMatrix.aEnd = aEnd;
4514 bRet = TRUE;
4519 return bRet;
4523 BOOL ScDocument::ExtendOverlapped( SCCOL& rStartCol, SCROW& rStartRow,
4524 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
4526 BOOL bFound = FALSE;
4527 if ( ValidColRow(rStartCol,rStartRow) && ValidColRow(nEndCol,nEndRow) && ValidTab(nTab) )
4529 if (pTab[nTab])
4531 SCCOL nCol;
4532 SCCOL nOldCol = rStartCol;
4533 SCROW nOldRow = rStartRow;
4534 for (nCol=nOldCol; nCol<=nEndCol; nCol++)
4535 while (((ScMergeFlagAttr*)GetAttr(nCol,rStartRow,nTab,ATTR_MERGE_FLAG))->
4536 IsVerOverlapped())
4537 --rStartRow;
4539 //! weiterreichen ?
4541 ScAttrArray* pAttrArray = pTab[nTab]->aCol[nOldCol].pAttrArray;
4542 SCSIZE nIndex;
4543 pAttrArray->Search( nOldRow, nIndex );
4544 SCROW nAttrPos = nOldRow;
4545 while (nAttrPos<=nEndRow)
4547 DBG_ASSERT( nIndex < pAttrArray->nCount, "Falscher Index im AttrArray" );
4549 if (((ScMergeFlagAttr&)pAttrArray->pData[nIndex].pPattern->
4550 GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped())
4552 SCROW nLoopEndRow = Min( nEndRow, pAttrArray->pData[nIndex].nRow );
4553 for (SCROW nAttrRow = nAttrPos; nAttrRow <= nLoopEndRow; nAttrRow++)
4555 SCCOL nTempCol = nOldCol;
4557 --nTempCol;
4558 while (((ScMergeFlagAttr*)GetAttr(nTempCol,nAttrRow,nTab,ATTR_MERGE_FLAG))
4559 ->IsHorOverlapped());
4560 if (nTempCol < rStartCol)
4561 rStartCol = nTempCol;
4564 nAttrPos = pAttrArray->pData[nIndex].nRow + 1;
4565 ++nIndex;
4569 else
4571 DBG_ERROR("ExtendOverlapped: falscher Bereich");
4574 return bFound;
4578 BOOL ScDocument::ExtendMergeSel( SCCOL nStartCol, SCROW nStartRow,
4579 SCCOL& rEndCol, SCROW& rEndRow,
4580 const ScMarkData& rMark, BOOL bRefresh, BOOL bAttrs )
4582 // use all selected sheets from rMark
4584 BOOL bFound = FALSE;
4585 SCCOL nOldEndCol = rEndCol;
4586 SCROW nOldEndRow = rEndRow;
4588 for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
4589 if ( pTab[nTab] && rMark.GetTableSelect(nTab) )
4591 SCCOL nThisEndCol = nOldEndCol;
4592 SCROW nThisEndRow = nOldEndRow;
4593 if ( ExtendMerge( nStartCol, nStartRow, nThisEndCol, nThisEndRow, nTab, bRefresh, bAttrs ) )
4594 bFound = TRUE;
4595 if ( nThisEndCol > rEndCol )
4596 rEndCol = nThisEndCol;
4597 if ( nThisEndRow > rEndRow )
4598 rEndRow = nThisEndRow;
4601 return bFound;
4605 BOOL ScDocument::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
4606 SCCOL& rEndCol, SCROW& rEndRow,
4607 SCTAB nTab, BOOL bRefresh, BOOL bAttrs )
4609 BOOL bFound = FALSE;
4610 if ( ValidColRow(nStartCol,nStartRow) && ValidColRow(rEndCol,rEndRow) && ValidTab(nTab) )
4612 if (pTab[nTab])
4613 bFound = pTab[nTab]->ExtendMerge( nStartCol, nStartRow, rEndCol, rEndRow, bRefresh, bAttrs );
4615 if (bRefresh)
4616 RefreshAutoFilter( nStartCol, nStartRow, rEndCol, rEndRow, nTab );
4618 else
4620 DBG_ERROR("ExtendMerge: falscher Bereich");
4623 return bFound;
4627 BOOL ScDocument::ExtendMerge( ScRange& rRange, BOOL bRefresh, BOOL bAttrs )
4629 BOOL bFound = FALSE;
4630 SCTAB nStartTab = rRange.aStart.Tab();
4631 SCTAB nEndTab = rRange.aEnd.Tab();
4632 SCCOL nEndCol = rRange.aEnd.Col();
4633 SCROW nEndRow = rRange.aEnd.Row();
4635 PutInOrder( nStartTab, nEndTab );
4636 for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++ )
4638 SCCOL nExtendCol = rRange.aEnd.Col();
4639 SCROW nExtendRow = rRange.aEnd.Row();
4640 if (ExtendMerge( rRange.aStart.Col(), rRange.aStart.Row(),
4641 nExtendCol, nExtendRow,
4642 nTab, bRefresh, bAttrs ) )
4644 bFound = TRUE;
4645 if (nExtendCol > nEndCol) nEndCol = nExtendCol;
4646 if (nExtendRow > nEndRow) nEndRow = nExtendRow;
4650 rRange.aEnd.SetCol(nEndCol);
4651 rRange.aEnd.SetRow(nEndRow);
4653 return bFound;
4656 BOOL ScDocument::ExtendTotalMerge( ScRange& rRange )
4658 // Bereich genau dann auf zusammengefasste Zellen erweitern, wenn
4659 // dadurch keine neuen nicht-ueberdeckten Zellen getroffen werden
4661 BOOL bRet = FALSE;
4662 ScRange aExt = rRange;
4663 if (ExtendMerge(aExt))
4665 if ( aExt.aEnd.Row() > rRange.aEnd.Row() )
4667 ScRange aTest = aExt;
4668 aTest.aStart.SetRow( rRange.aEnd.Row() + 1 );
4669 if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
4670 aExt.aEnd.SetRow(rRange.aEnd.Row());
4672 if ( aExt.aEnd.Col() > rRange.aEnd.Col() )
4674 ScRange aTest = aExt;
4675 aTest.aStart.SetCol( rRange.aEnd.Col() + 1 );
4676 if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
4677 aExt.aEnd.SetCol(rRange.aEnd.Col());
4680 bRet = ( aExt.aEnd != rRange.aEnd );
4681 rRange = aExt;
4683 return bRet;
4686 BOOL ScDocument::ExtendOverlapped( ScRange& rRange )
4688 BOOL bFound = FALSE;
4689 SCTAB nStartTab = rRange.aStart.Tab();
4690 SCTAB nEndTab = rRange.aEnd.Tab();
4691 SCCOL nStartCol = rRange.aStart.Col();
4692 SCROW nStartRow = rRange.aStart.Row();
4694 PutInOrder( nStartTab, nEndTab );
4695 for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++ )
4697 SCCOL nExtendCol = rRange.aStart.Col();
4698 SCROW nExtendRow = rRange.aStart.Row();
4699 ExtendOverlapped( nExtendCol, nExtendRow,
4700 rRange.aEnd.Col(), rRange.aEnd.Row(), nTab );
4701 if (nExtendCol < nStartCol)
4703 nStartCol = nExtendCol;
4704 bFound = TRUE;
4706 if (nExtendRow < nStartRow)
4708 nStartRow = nExtendRow;
4709 bFound = TRUE;
4713 rRange.aStart.SetCol(nStartCol);
4714 rRange.aStart.SetRow(nStartRow);
4716 return bFound;
4719 BOOL ScDocument::RefreshAutoFilter( SCCOL nStartCol, SCROW nStartRow,
4720 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
4722 USHORT nCount = pDBCollection->GetCount();
4723 USHORT i;
4724 ScDBData* pData;
4725 SCTAB nDBTab;
4726 SCCOL nDBStartCol;
4727 SCROW nDBStartRow;
4728 SCCOL nDBEndCol;
4729 SCROW nDBEndRow;
4731 // Autofilter loeschen
4733 BOOL bChange = RemoveFlagsTab( nStartCol,nStartRow, nEndCol,nEndRow, nTab, SC_MF_AUTO );
4735 // Autofilter setzen
4737 for (i=0; i<nCount; i++)
4739 pData = (*pDBCollection)[i];
4740 if (pData->HasAutoFilter())
4742 pData->GetArea( nDBTab, nDBStartCol,nDBStartRow, nDBEndCol,nDBEndRow );
4743 if ( nDBTab==nTab && nDBStartRow<=nEndRow && nDBEndRow>=nStartRow &&
4744 nDBStartCol<=nEndCol && nDBEndCol>=nStartCol )
4746 if (ApplyFlagsTab( nDBStartCol,nDBStartRow, nDBEndCol,nDBStartRow,
4747 nDBTab, SC_MF_AUTO ))
4748 bChange = TRUE;
4752 return bChange;
4755 void ScDocument::SkipOverlapped( SCCOL& rCol, SCROW& rRow, SCTAB nTab ) const
4757 while (IsHorOverlapped(rCol, rRow, nTab))
4758 --rCol;
4759 while (IsVerOverlapped(rCol, rRow, nTab))
4760 --rRow;
4763 BOOL ScDocument::IsHorOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4765 const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
4766 GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
4767 if (pAttr)
4768 return pAttr->IsHorOverlapped();
4769 else
4771 DBG_ERROR("Overlapped: Attr==0");
4772 return FALSE;
4777 BOOL ScDocument::IsVerOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4779 const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
4780 GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
4781 if (pAttr)
4782 return pAttr->IsVerOverlapped();
4783 else
4785 DBG_ERROR("Overlapped: Attr==0");
4786 return FALSE;
4791 void ScDocument::ApplySelectionFrame( const ScMarkData& rMark,
4792 const SvxBoxItem* pLineOuter,
4793 const SvxBoxInfoItem* pLineInner )
4795 ScRangeList aRangeList;
4796 rMark.FillRangeListWithMarks( &aRangeList, FALSE );
4797 ULONG nRangeCount = aRangeList.Count();
4798 for (SCTAB i=0; i<=MAXTAB; i++)
4800 if (pTab[i] && rMark.GetTableSelect(i))
4802 for (ULONG j=0; j<nRangeCount; j++)
4804 ScRange aRange = *aRangeList.GetObject(j);
4805 pTab[i]->ApplyBlockFrame( pLineOuter, pLineInner,
4806 aRange.aStart.Col(), aRange.aStart.Row(),
4807 aRange.aEnd.Col(), aRange.aEnd.Row() );
4814 void ScDocument::ApplyFrameAreaTab( const ScRange& rRange,
4815 const SvxBoxItem* pLineOuter,
4816 const SvxBoxInfoItem* pLineInner )
4818 SCTAB nStartTab = rRange.aStart.Tab();
4819 SCTAB nEndTab = rRange.aStart.Tab();
4820 for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
4821 if (pTab[nTab])
4822 pTab[nTab]->ApplyBlockFrame( pLineOuter, pLineInner,
4823 rRange.aStart.Col(), rRange.aStart.Row(),
4824 rRange.aEnd.Col(), rRange.aEnd.Row() );
4828 void ScDocument::ApplySelectionPattern( const ScPatternAttr& rAttr, const ScMarkData& rMark, ScEditDataArray* pDataArray )
4830 const SfxItemSet* pSet = &rAttr.GetItemSet();
4831 BOOL bSet = FALSE;
4832 USHORT i;
4833 for (i=ATTR_PATTERN_START; i<=ATTR_PATTERN_END && !bSet; i++)
4834 if (pSet->GetItemState(i) == SFX_ITEM_SET)
4835 bSet = TRUE;
4837 if (bSet)
4839 // ApplySelectionCache needs multi mark
4840 if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
4842 ScRange aRange;
4843 rMark.GetMarkArea( aRange );
4844 ApplyPatternArea( aRange.aStart.Col(), aRange.aStart.Row(),
4845 aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rAttr, pDataArray );
4847 else
4849 SfxItemPoolCache aCache( xPoolHelper->GetDocPool(), pSet );
4850 for (SCTAB nTab=0; nTab<=MAXTAB; nTab++)
4851 if (pTab[nTab])
4852 if (rMark.GetTableSelect(nTab))
4853 pTab[nTab]->ApplySelectionCache( &aCache, rMark, pDataArray );
4859 void ScDocument::ChangeSelectionIndent( BOOL bIncrement, const ScMarkData& rMark )
4861 for (SCTAB i=0; i<=MAXTAB; i++)
4862 if (pTab[i] && rMark.GetTableSelect(i))
4863 pTab[i]->ChangeSelectionIndent( bIncrement, rMark );
4867 void ScDocument::ClearSelectionItems( const USHORT* pWhich, const ScMarkData& rMark )
4869 for (SCTAB i=0; i<=MAXTAB; i++)
4870 if (pTab[i] && rMark.GetTableSelect(i))
4871 pTab[i]->ClearSelectionItems( pWhich, rMark );
4875 void ScDocument::DeleteSelection( USHORT nDelFlag, const ScMarkData& rMark )
4877 for (SCTAB i=0; i<=MAXTAB; i++)
4878 if (pTab[i] && rMark.GetTableSelect(i))
4879 pTab[i]->DeleteSelection( nDelFlag, rMark );
4883 void ScDocument::DeleteSelectionTab( SCTAB nTab, USHORT nDelFlag, const ScMarkData& rMark )
4885 if (ValidTab(nTab) && pTab[nTab])
4886 pTab[nTab]->DeleteSelection( nDelFlag, rMark );
4887 else
4889 DBG_ERROR("Falsche Tabelle");
4894 ScPatternAttr* ScDocument::GetDefPattern() const
4896 return (ScPatternAttr*) &xPoolHelper->GetDocPool()->GetDefaultItem(ATTR_PATTERN);
4900 ScDocumentPool* ScDocument::GetPool()
4902 return xPoolHelper->GetDocPool();
4907 ScStyleSheetPool* ScDocument::GetStyleSheetPool() const
4909 return xPoolHelper->GetStylePool();
4913 SCSIZE ScDocument::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
4914 SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, ScDirection eDir )
4916 PutInOrder(nStartCol, nEndCol);
4917 PutInOrder(nStartRow, nEndRow);
4918 PutInOrder(nStartTab, nEndTab);
4919 if (VALIDTAB(nStartTab))
4921 if (pTab[nStartTab])
4922 return pTab[nStartTab]->GetEmptyLinesInBlock(nStartCol, nStartRow, nEndCol, nEndRow, eDir);
4923 else
4924 return 0;
4926 else
4927 return 0;
4931 void ScDocument::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY )
4933 if (ValidTab(nTab) && pTab[nTab])
4934 pTab[nTab]->FindAreaPos( rCol, rRow, nMovX, nMovY );
4938 void ScDocument::GetNextPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY,
4939 BOOL bMarked, BOOL bUnprotected, const ScMarkData& rMark )
4941 DBG_ASSERT( !nMovX || !nMovY, "GetNextPos: nur X oder Y" );
4943 ScMarkData aCopyMark = rMark;
4944 aCopyMark.SetMarking(FALSE);
4945 aCopyMark.MarkToMulti();
4947 if (ValidTab(nTab) && pTab[nTab])
4948 pTab[nTab]->GetNextPos( rCol, rRow, nMovX, nMovY, bMarked, bUnprotected, aCopyMark );
4952 // Datei-Operationen
4956 void ScDocument::UpdStlShtPtrsFrmNms()
4958 ScPatternAttr::pDoc = this;
4960 ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4962 USHORT nCount = pPool->GetItemCount(ATTR_PATTERN);
4963 ScPatternAttr* pPattern;
4964 for (USHORT i=0; i<nCount; i++)
4966 pPattern = (ScPatternAttr*)pPool->GetItem(ATTR_PATTERN, i);
4967 if (pPattern)
4968 pPattern->UpdateStyleSheet();
4970 ((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).UpdateStyleSheet();
4974 void ScDocument::StylesToNames()
4976 ScPatternAttr::pDoc = this;
4978 ScDocumentPool* pPool = xPoolHelper->GetDocPool();
4980 USHORT nCount = pPool->GetItemCount(ATTR_PATTERN);
4981 ScPatternAttr* pPattern;
4982 for (USHORT i=0; i<nCount; i++)
4984 pPattern = (ScPatternAttr*)pPool->GetItem(ATTR_PATTERN, i);
4985 if (pPattern)
4986 pPattern->StyleToName();
4988 ((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).StyleToName();
4992 ULONG ScDocument::GetCellCount() const
4994 ULONG nCellCount = 0L;
4996 for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
4997 if ( pTab[nTab] )
4998 nCellCount += pTab[nTab]->GetCellCount();
5000 return nCellCount;
5004 ULONG ScDocument::GetCodeCount() const
5006 ULONG nCodeCount = 0;
5008 for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
5009 if ( pTab[nTab] )
5010 nCodeCount += pTab[nTab]->GetCodeCount();
5012 return nCodeCount;
5016 ULONG ScDocument::GetWeightedCount() const
5018 ULONG nCellCount = 0L;
5020 for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
5021 if ( pTab[nTab] )
5022 nCellCount += pTab[nTab]->GetWeightedCount();
5024 return nCellCount;
5028 void ScDocument::PageStyleModified( SCTAB nTab, const String& rNewName )
5030 if ( ValidTab(nTab) && pTab[nTab] )
5031 pTab[nTab]->PageStyleModified( rNewName );
5035 void ScDocument::SetPageStyle( SCTAB nTab, const String& rName )
5037 if ( ValidTab(nTab) && pTab[nTab] )
5038 pTab[nTab]->SetPageStyle( rName );
5042 const String& ScDocument::GetPageStyle( SCTAB nTab ) const
5044 if ( ValidTab(nTab) && pTab[nTab] )
5045 return pTab[nTab]->GetPageStyle();
5047 return EMPTY_STRING;
5051 void ScDocument::SetPageSize( SCTAB nTab, const Size& rSize )
5053 if ( ValidTab(nTab) && pTab[nTab] )
5054 pTab[nTab]->SetPageSize( rSize );
5057 Size ScDocument::GetPageSize( SCTAB nTab ) const
5059 if ( ValidTab(nTab) && pTab[nTab] )
5060 return pTab[nTab]->GetPageSize();
5062 DBG_ERROR("falsche Tab");
5063 return Size();
5067 void ScDocument::SetRepeatArea( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow )
5069 if ( ValidTab(nTab) && pTab[nTab] )
5070 pTab[nTab]->SetRepeatArea( nStartCol, nEndCol, nStartRow, nEndRow );
5073 void ScDocument::InvalidatePageBreaks(SCTAB nTab)
5075 if (ValidTab(nTab) && pTab[nTab])
5076 pTab[nTab]->InvalidatePageBreaks();
5079 void ScDocument::UpdatePageBreaks( SCTAB nTab, const ScRange* pUserArea )
5081 if ( ValidTab(nTab) && pTab[nTab] )
5082 pTab[nTab]->UpdatePageBreaks( pUserArea );
5085 void ScDocument::RemoveManualBreaks( SCTAB nTab )
5087 if ( ValidTab(nTab) && pTab[nTab] )
5088 pTab[nTab]->RemoveManualBreaks();
5091 BOOL ScDocument::HasManualBreaks( SCTAB nTab ) const
5093 if ( ValidTab(nTab) && pTab[nTab] )
5094 return pTab[nTab]->HasManualBreaks();
5096 DBG_ERROR("falsche Tab");
5097 return FALSE;
5101 void ScDocument::GetDocStat( ScDocStat& rDocStat )
5103 rDocStat.nTableCount = GetTableCount();
5104 rDocStat.aDocName = aDocName;
5105 rDocStat.nCellCount = GetCellCount();
5109 BOOL ScDocument::HasPrintRange()
5111 BOOL bResult = FALSE;
5113 for ( SCTAB i=0; !bResult && i<nMaxTableNumber; i++ )
5114 if ( pTab[i] )
5115 bResult = pTab[i]->IsPrintEntireSheet() || (pTab[i]->GetPrintRangeCount() > 0);
5117 return bResult;
5121 BOOL ScDocument::IsPrintEntireSheet( SCTAB nTab ) const
5123 return (ValidTab(nTab) ) && pTab[nTab] && pTab[nTab]->IsPrintEntireSheet();
5127 USHORT ScDocument::GetPrintRangeCount( SCTAB nTab )
5129 if (ValidTab(nTab) && pTab[nTab])
5130 return pTab[nTab]->GetPrintRangeCount();
5132 return 0;
5136 const ScRange* ScDocument::GetPrintRange( SCTAB nTab, USHORT nPos )
5138 if (ValidTab(nTab) && pTab[nTab])
5139 return pTab[nTab]->GetPrintRange(nPos);
5141 return NULL;
5145 const ScRange* ScDocument::GetRepeatColRange( SCTAB nTab )
5147 if (ValidTab(nTab) && pTab[nTab])
5148 return pTab[nTab]->GetRepeatColRange();
5150 return NULL;
5154 const ScRange* ScDocument::GetRepeatRowRange( SCTAB nTab )
5156 if (ValidTab(nTab) && pTab[nTab])
5157 return pTab[nTab]->GetRepeatRowRange();
5159 return NULL;
5163 void ScDocument::ClearPrintRanges( SCTAB nTab )
5165 if (ValidTab(nTab) && pTab[nTab])
5166 pTab[nTab]->ClearPrintRanges();
5170 void ScDocument::AddPrintRange( SCTAB nTab, const ScRange& rNew )
5172 if (ValidTab(nTab) && pTab[nTab])
5173 pTab[nTab]->AddPrintRange( rNew );
5177 //UNUSED2009-05 void ScDocument::SetPrintRange( SCTAB nTab, const ScRange& rNew )
5178 //UNUSED2009-05 {
5179 //UNUSED2009-05 if (ValidTab(nTab) && pTab[nTab])
5180 //UNUSED2009-05 pTab[nTab]->SetPrintRange( rNew );
5181 //UNUSED2009-05 }
5184 void ScDocument::SetPrintEntireSheet( SCTAB nTab )
5186 if (ValidTab(nTab) && pTab[nTab])
5187 pTab[nTab]->SetPrintEntireSheet();
5191 void ScDocument::SetRepeatColRange( SCTAB nTab, const ScRange* pNew )
5193 if (ValidTab(nTab) && pTab[nTab])
5194 pTab[nTab]->SetRepeatColRange( pNew );
5198 void ScDocument::SetRepeatRowRange( SCTAB nTab, const ScRange* pNew )
5200 if (ValidTab(nTab) && pTab[nTab])
5201 pTab[nTab]->SetRepeatRowRange( pNew );
5205 ScPrintRangeSaver* ScDocument::CreatePrintRangeSaver() const
5207 SCTAB nCount = GetTableCount();
5208 ScPrintRangeSaver* pNew = new ScPrintRangeSaver( nCount );
5209 for (SCTAB i=0; i<nCount; i++)
5210 if (pTab[i])
5211 pTab[i]->FillPrintSaver( pNew->GetTabData(i) );
5212 return pNew;
5216 void ScDocument::RestorePrintRanges( const ScPrintRangeSaver& rSaver )
5218 SCTAB nCount = rSaver.GetTabCount();
5219 for (SCTAB i=0; i<nCount; i++)
5220 if (pTab[i])
5221 pTab[i]->RestorePrintRanges( rSaver.GetTabData(i) );
5225 BOOL ScDocument::NeedPageResetAfterTab( SCTAB nTab ) const
5227 // Die Seitennummern-Zaehlung faengt bei einer Tabelle neu an, wenn eine
5228 // andere Vorlage als bei der vorherigen gesetzt ist (nur Namen vergleichen)
5229 // und eine Seitennummer angegeben ist (nicht 0)
5231 if ( nTab < MAXTAB && pTab[nTab] && pTab[nTab+1] )
5233 String aNew = pTab[nTab+1]->GetPageStyle();
5234 if ( aNew != pTab[nTab]->GetPageStyle() )
5236 SfxStyleSheetBase* pStyle = xPoolHelper->GetStylePool()->Find( aNew, SFX_STYLE_FAMILY_PAGE );
5237 if ( pStyle )
5239 const SfxItemSet& rSet = pStyle->GetItemSet();
5240 USHORT nFirst = ((const SfxUInt16Item&)rSet.Get(ATTR_PAGE_FIRSTPAGENO)).GetValue();
5241 if ( nFirst != 0 )
5242 return TRUE; // Seitennummer in neuer Vorlage angegeben
5247 return FALSE; // sonst nicht
5250 SfxUndoManager* ScDocument::GetUndoManager()
5252 if (!mpUndoManager)
5253 mpUndoManager = new SfxUndoManager;
5254 return mpUndoManager;
5258 void ScDocument::EnableUndo( bool bVal )
5260 GetUndoManager()->EnableUndo(bVal);
5261 mbUndoEnabled = bVal;