summaryrefslogtreecommitdiff
path: root/sc/source/core/data/document.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/core/data/document.cxx')
-rw-r--r--sc/source/core/data/document.cxx5233
1 files changed, 5233 insertions, 0 deletions
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
new file mode 100644
index 000000000000..bef4cbf87396
--- /dev/null
+++ b/sc/source/core/data/document.cxx
@@ -0,0 +1,5233 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#define _ZFORLIST_DECLARE_TABLE
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+
+#include <editeng/boxitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <svx/pageitem.hxx>
+#include <editeng/editeng.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdocapt.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/objsh.hxx>
+#include <svl/poolcach.hxx>
+#include <unotools/saveopt.hxx>
+#include <svl/zforlist.hxx>
+#include <unotools/charclass.hxx>
+#include <unotools/transliterationwrapper.hxx>
+#include <tools/tenccvt.hxx>
+
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/script/XVBACompat.hpp>
+#include <com/sun/star/sheet/TablePageBreakData.hpp>
+
+#include "document.hxx"
+#include "table.hxx"
+#include "attrib.hxx"
+#include "attarray.hxx"
+#include "markarr.hxx"
+#include "patattr.hxx"
+#include "rangenam.hxx"
+#include "poolhelp.hxx"
+#include "docpool.hxx"
+#include "stlpool.hxx"
+#include "stlsheet.hxx"
+#include "globstr.hrc"
+#include "rechead.hxx"
+#include "dbcolect.hxx"
+#include "pivot.hxx"
+#include "chartlis.hxx"
+#include "rangelst.hxx"
+#include "markdata.hxx"
+#include "drwlayer.hxx"
+#include "conditio.hxx"
+#include "validat.hxx"
+#include "prnsave.hxx"
+#include "chgtrack.hxx"
+#include "sc.hrc"
+#include "scresid.hxx"
+#include "hints.hxx"
+#include "detdata.hxx"
+#include "cell.hxx"
+#include "dpobject.hxx"
+#include "detfunc.hxx" // for UpdateAllComments
+#include "scmod.hxx"
+#include "dociter.hxx"
+#include "progress.hxx"
+#include "autonamecache.hxx"
+#include "bcaslot.hxx"
+#include "postit.hxx"
+#include "externalrefmgr.hxx"
+#include "tabprotection.hxx"
+#include "clipparam.hxx"
+
+#include <map>
+#include <limits>
+
+namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::sheet::TablePageBreakData;
+using ::std::set;
+
+struct ScDefaultAttr
+{
+ const ScPatternAttr* pAttr;
+ SCROW nFirst;
+ SCSIZE nCount;
+ ScDefaultAttr(const ScPatternAttr* pPatAttr) : pAttr(pPatAttr), nFirst(0), nCount(0) {}
+};
+
+struct ScLessDefaultAttr
+{
+ sal_Bool operator() (const ScDefaultAttr& rValue1, const ScDefaultAttr& rValue2) const
+ {
+ return rValue1.pAttr < rValue2.pAttr;
+ }
+};
+
+typedef std::set<ScDefaultAttr, ScLessDefaultAttr> ScDefaultAttrSet;
+
+void ScDocument::MakeTable( SCTAB nTab,bool _bNeedsNameCheck )
+{
+ if ( ValidTab(nTab) && !pTab[nTab] )
+ {
+ String aString = ScGlobal::GetRscString(STR_TABLE_DEF); //"Tabelle"
+ aString += String::CreateFromInt32(nTab+1);
+ if ( _bNeedsNameCheck )
+ CreateValidTabName( aString ); // keine doppelten
+
+ pTab[nTab] = new ScTable(this, nTab, aString);
+ pTab[nTab]->SetLoadingMedium(bLoadingMedium);
+ ++nMaxTableNumber;
+ }
+}
+
+
+BOOL ScDocument::HasTable( SCTAB nTab ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return TRUE;
+
+ return FALSE;
+}
+
+
+BOOL ScDocument::GetName( SCTAB nTab, String& rName ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ {
+ pTab[nTab]->GetName( rName );
+ return TRUE;
+ }
+ rName.Erase();
+ return FALSE;
+}
+
+BOOL ScDocument::SetCodeName( SCTAB nTab, String& rName )
+{
+ if (VALIDTAB(nTab))
+ {
+ if (pTab[nTab])
+ {
+ pTab[nTab]->SetCodeName( rName );
+ return TRUE;
+ }
+ }
+ OSL_TRACE( "**** can't set code name %s", rtl::OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr() );
+ return FALSE;
+}
+
+BOOL ScDocument::GetCodeName( SCTAB nTab, String& rName ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ {
+ pTab[nTab]->GetCodeName( rName );
+ return TRUE;
+ }
+ rName.Erase();
+ return FALSE;
+}
+
+
+BOOL ScDocument::GetTable( const String& rName, SCTAB& rTab ) const
+{
+ String aUpperName = rName;
+ ScGlobal::pCharClass->toUpper(aUpperName);
+
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ {
+ if ( pTab[i]->GetUpperName() == aUpperName )
+ {
+ rTab = i;
+ return TRUE;
+ }
+ }
+ rTab = 0;
+ return FALSE;
+}
+
+
+BOOL ScDocument::ValidTabName( const String& rName ) const
+{
+ xub_StrLen nLen = rName.Len();
+ if (!nLen)
+ return false;
+
+#if 1
+ // Restrict sheet names to what Excel accepts.
+ /* TODO: We may want to remove this restriction for full ODFF compliance.
+ * Merely loading and calculating ODF documents using these characters in
+ * sheet names is not affected by this, but all sheet name editing and
+ * copying functionality is, maybe falling back to "Sheet4" or similar. */
+ for (xub_StrLen i = 0; i < nLen; ++i)
+ {
+ const sal_Unicode c = rName.GetChar(i);
+ switch (c)
+ {
+ case ':':
+ case '\\':
+ case '/':
+ case '?':
+ case '*':
+ case '[':
+ case ']':
+ // these characters are not allowed to match XL's convention.
+ return false;
+ case '\'':
+ if (i == 0 || i == nLen - 1)
+ // single quote is not allowed at the first or last
+ // character position.
+ return false;
+ break;
+ }
+ }
+#endif
+
+ return true;
+}
+
+
+BOOL ScDocument::ValidNewTabName( const String& rName ) const
+{
+ BOOL bValid = ValidTabName(rName);
+ for (SCTAB i=0; (i<=MAXTAB) && bValid; i++)
+ if (pTab[i])
+ {
+ String aOldName;
+ pTab[i]->GetName(aOldName);
+ bValid = !ScGlobal::GetpTransliteration()->isEqual( rName, aOldName );
+ }
+ return bValid;
+}
+
+
+void ScDocument::CreateValidTabName(String& rName) const
+{
+ if ( !ValidTabName(rName) )
+ {
+ // neu erzeugen
+
+ const String aStrTable( ScResId(SCSTR_TABLE) );
+ BOOL bOk = FALSE;
+
+ // vorneweg testen, ob der Prefix als gueltig erkannt wird
+ // wenn nicht, nur doppelte vermeiden
+ BOOL bPrefix = ValidTabName( aStrTable );
+ DBG_ASSERT(bPrefix, "ungueltiger Tabellenname");
+ SCTAB nDummy;
+
+ SCTAB nLoops = 0; // "zur Sicherheit"
+ for ( SCTAB i = nMaxTableNumber+1; !bOk && nLoops <= MAXTAB; i++ )
+ {
+ rName = aStrTable;
+ rName += String::CreateFromInt32(i);
+ if (bPrefix)
+ bOk = ValidNewTabName( rName );
+ else
+ bOk = !GetTable( rName, nDummy );
+ ++nLoops;
+ }
+
+ DBG_ASSERT(bOk, "kein gueltiger Tabellenname gefunden");
+ if ( !bOk )
+ rName = aStrTable;
+ }
+ else
+ {
+ // uebergebenen Namen ueberpruefen
+
+ if ( !ValidNewTabName(rName) )
+ {
+ SCTAB i = 1;
+ String aName;
+ do
+ {
+ i++;
+ aName = rName;
+ aName += '_';
+ aName += String::CreateFromInt32(static_cast<sal_Int32>(i));
+ }
+ while (!ValidNewTabName(aName) && (i < MAXTAB+1));
+ rName = aName;
+ }
+ }
+}
+
+
+BOOL ScDocument::InsertTab( SCTAB nPos, const String& rName,
+ BOOL bExternalDocument )
+{
+ SCTAB nTabCount = GetTableCount();
+ BOOL bValid = ValidTab(nTabCount);
+ if ( !bExternalDocument ) // sonst rName == "'Doc'!Tab", vorher pruefen
+ bValid = (bValid && ValidNewTabName(rName));
+ if (bValid)
+ {
+ if (nPos == SC_TAB_APPEND || nPos == nTabCount)
+ {
+ pTab[nTabCount] = new ScTable(this, nTabCount, rName);
+ pTab[nTabCount]->SetCodeName( rName );
+ ++nMaxTableNumber;
+ if ( bExternalDocument )
+ pTab[nTabCount]->SetVisible( FALSE );
+ }
+ else
+ {
+ if (VALIDTAB(nPos) && (nPos < nTabCount))
+ {
+ ScRange aRange( 0,0,nPos, MAXCOL,MAXROW,MAXTAB );
+ xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
+ xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
+ pRangeName->UpdateTabRef( nPos, 1 );
+ pDBCollection->UpdateReference(
+ URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
+ if (pDPCollection)
+ pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
+ if (pDetOpList)
+ pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,1 );
+ UpdateChartRef( URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
+ UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,1 );
+ if ( pUnoBroadcaster )
+ pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,1 ) );
+
+ SCTAB i;
+ for (i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->UpdateInsertTab(nPos);
+
+ for (i = nTabCount; i > nPos; i--)
+ {
+ pTab[i] = pTab[i - 1];
+ }
+
+ pTab[nPos] = new ScTable(this, nPos, rName);
+ pTab[nPos]->SetCodeName( rName );
+ ++nMaxTableNumber;
+
+ // UpdateBroadcastAreas must be called between UpdateInsertTab,
+ // which ends listening, and StartAllListeners, to not modify
+ // areas that are to be inserted by starting listeners.
+ UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,1);
+ for (i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->UpdateCompile();
+ for (i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->StartAllListeners();
+
+ // update conditional formats after table is inserted
+ if ( pCondFormList )
+ pCondFormList->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
+ if ( pValidationList )
+ pValidationList->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
+ // #81844# sheet names of references are not valid until sheet is inserted
+ if ( pChartListenerCollection )
+ pChartListenerCollection->UpdateScheduledSeriesRanges();
+
+ SetDirty();
+ bValid = TRUE;
+ }
+ else
+ bValid = FALSE;
+ }
+ }
+ return bValid;
+}
+
+
+BOOL ScDocument::DeleteTab( SCTAB nTab, ScDocument* pRefUndoDoc )
+{
+ BOOL bValid = FALSE;
+ if (VALIDTAB(nTab))
+ {
+ if (pTab[nTab])
+ {
+ SCTAB nTabCount = GetTableCount();
+ if (nTabCount > 1)
+ {
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTab );
+ DelBroadcastAreasInRange( aRange );
+
+ // #i8180# remove database ranges etc. that are on the deleted tab
+ // (restored in undo with ScRefUndoData)
+
+ xColNameRanges->DeleteOnTab( nTab );
+ xRowNameRanges->DeleteOnTab( nTab );
+ pDBCollection->DeleteOnTab( nTab );
+ if (pDPCollection)
+ pDPCollection->DeleteOnTab( nTab );
+ if (pDetOpList)
+ pDetOpList->DeleteOnTab( nTab );
+ DeleteAreaLinksOnTab( nTab );
+
+ // normal reference update
+
+ aRange.aEnd.SetTab( MAXTAB );
+ xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
+ xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
+ pRangeName->UpdateTabRef( nTab, 2 );
+ pDBCollection->UpdateReference(
+ URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1 );
+ if (pDPCollection)
+ pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
+ if (pDetOpList)
+ pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1 );
+ UpdateChartRef( URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1 );
+ UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1 );
+ if ( pCondFormList )
+ pCondFormList->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
+ if ( pValidationList )
+ pValidationList->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
+ if ( pUnoBroadcaster )
+ pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1 ) );
+
+ SCTAB i;
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->UpdateDeleteTab(nTab,FALSE,
+ pRefUndoDoc ? pRefUndoDoc->pTab[i] : 0);
+ delete pTab[nTab];
+ for (i=nTab + 1; i < nTabCount; i++)
+ pTab[i - 1] = pTab[i];
+ pTab[nTabCount - 1] = NULL;
+ --nMaxTableNumber;
+ // UpdateBroadcastAreas must be called between UpdateDeleteTab,
+ // which ends listening, and StartAllListeners, to not modify
+ // areas that are to be inserted by starting listeners.
+ UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1);
+ for (i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->UpdateCompile();
+ // Excel-Filter loescht einige Tables waehrend des Ladens,
+ // Listener werden erst nach dem Laden aufgesetzt
+ if ( !bInsertingFromOtherDoc )
+ {
+ for (i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->StartAllListeners();
+ SetDirty();
+ }
+ // #81844# sheet names of references are not valid until sheet is deleted
+ pChartListenerCollection->UpdateScheduledSeriesRanges();
+
+ SetAutoCalc( bOldAutoCalc );
+ bValid = TRUE;
+ }
+ }
+ }
+ return bValid;
+}
+
+
+BOOL ScDocument::RenameTab( SCTAB nTab, const String& rName, BOOL /* bUpdateRef */,
+ BOOL bExternalDocument )
+{
+ BOOL bValid = FALSE;
+ SCTAB i;
+ if VALIDTAB(nTab)
+ if (pTab[nTab])
+ {
+ if ( bExternalDocument )
+ bValid = TRUE; // zusammengesetzter Name
+ else
+ bValid = ValidTabName(rName);
+ for (i=0; (i<=MAXTAB) && bValid; i++)
+ if (pTab[i] && (i != nTab))
+ {
+ String aOldName;
+ pTab[i]->GetName(aOldName);
+ bValid = !ScGlobal::GetpTransliteration()->isEqual( rName, aOldName );
+ }
+ if (bValid)
+ {
+ // #i75258# update charts before renaming, so they can get their live data objects.
+ // Once the charts are live, the sheet can be renamed without problems.
+ if ( pChartListenerCollection )
+ pChartListenerCollection->UpdateChartsContainingTab( nTab );
+ pTab[nTab]->SetName(rName);
+
+ // If formulas refer to the renamed sheet, the TokenArray remains valid,
+ // but the XML stream must be re-generated.
+ for (i=0; i<=MAXTAB; ++i)
+ if (pTab[i] && pTab[i]->IsStreamValid())
+ pTab[i]->SetStreamValid( FALSE );
+ }
+ }
+ return bValid;
+}
+
+
+void ScDocument::SetVisible( SCTAB nTab, BOOL bVisible )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->SetVisible(bVisible);
+}
+
+
+BOOL ScDocument::IsVisible( SCTAB nTab ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->IsVisible();
+
+ return FALSE;
+}
+
+
+BOOL ScDocument::IsStreamValid( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->IsStreamValid();
+
+ return FALSE;
+}
+
+
+void ScDocument::SetStreamValid( SCTAB nTab, BOOL bSet, BOOL bIgnoreLock )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetStreamValid( bSet, bIgnoreLock );
+}
+
+
+void ScDocument::LockStreamValid( bool bLock )
+{
+ mbStreamValidLocked = bLock;
+}
+
+
+BOOL ScDocument::IsPendingRowHeights( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->IsPendingRowHeights();
+
+ return FALSE;
+}
+
+
+void ScDocument::SetPendingRowHeights( SCTAB nTab, BOOL bSet )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetPendingRowHeights( bSet );
+}
+
+
+void ScDocument::SetLayoutRTL( SCTAB nTab, BOOL bRTL )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ {
+ if ( bImportingXML )
+ {
+ // #i57869# only set the LoadingRTL flag, the real setting (including mirroring)
+ // is applied in SetImportingXML(FALSE). This is so the shapes can be loaded in
+ // normal LTR mode.
+
+ pTab[nTab]->SetLoadingRTL( bRTL );
+ return;
+ }
+
+ pTab[nTab]->SetLayoutRTL( bRTL ); // only sets the flag
+ pTab[nTab]->SetDrawPageSize();
+
+ // mirror existing objects:
+
+ if (pDrawLayer)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+ if (pPage)
+ {
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ // objects with ScDrawObjData are re-positioned in SetPageSize,
+ // don't mirror again
+ ScDrawObjData* pData = ScDrawLayer::GetObjData( pObject );
+ if ( !pData )
+ pDrawLayer->MirrorRTL( pObject );
+
+ pObject->SetContextWritingMode( bRTL ? WritingMode2::RL_TB : WritingMode2::LR_TB );
+
+ pObject = aIter.Next();
+ }
+ }
+ }
+ }
+}
+
+
+BOOL ScDocument::IsLayoutRTL( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->IsLayoutRTL();
+
+ return FALSE;
+}
+
+
+BOOL ScDocument::IsNegativePage( SCTAB nTab ) const
+{
+ // Negative page area is always used for RTL layout.
+ // The separate method is used to find all RTL handling of drawing objects.
+ return IsLayoutRTL( nTab );
+}
+
+
+/* ----------------------------------------------------------------------------
+ benutzten Bereich suchen:
+
+ GetCellArea - nur Daten
+ GetTableArea - Daten / Attribute
+ GetPrintArea - beruecksichtigt auch Zeichenobjekte,
+ streicht Attribute bis ganz rechts / unten
+---------------------------------------------------------------------------- */
+
+
+BOOL ScDocument::GetCellArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->GetCellArea( rEndCol, rEndRow );
+
+ rEndCol = 0;
+ rEndRow = 0;
+ return FALSE;
+}
+
+
+BOOL ScDocument::GetTableArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->GetTableArea( rEndCol, rEndRow );
+
+ rEndCol = 0;
+ rEndRow = 0;
+ return FALSE;
+}
+
+bool ScDocument::ShrinkToDataArea(SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow) const
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return false;
+
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ pTab[nTab]->GetFirstDataPos(nCol1, nRow1);
+ pTab[nTab]->GetLastDataPos(nCol2, nRow2);
+
+ if (nCol1 > nCol2 || nRow1 > nRow2)
+ // invalid range.
+ return false;
+
+ // Make sure the area only shrinks, and doesn't grow.
+ if (rStartCol < nCol1)
+ rStartCol = nCol1;
+ if (nCol2 < rEndCol)
+ rEndCol = nCol2;
+ if (rStartRow < nRow1)
+ rStartRow = nRow1;
+ if (nRow2 < rEndRow)
+ rEndRow = nRow2;
+
+ if (rStartCol > rEndCol || rStartRow > rEndRow)
+ // invalid range.
+ return false;
+
+ return true; // success!
+}
+
+bool ScDocument::ShrinkToUsedDataArea( SCTAB nTab, SCCOL& rStartCol,
+ SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return false;
+ return pTab[nTab]->ShrinkToUsedDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bColumnsOnly);
+}
+
+// zusammenhaengender Bereich
+
+void ScDocument::GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
+ SCCOL& rEndCol, SCROW& rEndRow, BOOL bIncludeOld, bool bOnlyDown ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->GetDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bIncludeOld, bOnlyDown );
+}
+
+
+void ScDocument::LimitChartArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
+ SCCOL& rEndCol, SCROW& rEndRow )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->LimitChartArea( rStartCol, rStartRow, rEndCol, rEndRow );
+}
+
+
+void ScDocument::LimitChartIfAll( ScRangeListRef& rRangeList )
+{
+ ScRangeListRef aNew = new ScRangeList;
+ if (rRangeList.Is())
+ {
+ ULONG nCount = rRangeList->Count();
+ for (ULONG i=0; i<nCount; i++)
+ {
+ ScRange aRange(*rRangeList->GetObject( i ));
+ if ( ( aRange.aStart.Col() == 0 && aRange.aEnd.Col() == MAXCOL ) ||
+ ( aRange.aStart.Row() == 0 && aRange.aEnd.Row() == MAXROW ) )
+ {
+ SCCOL nStartCol = aRange.aStart.Col();
+ SCROW nStartRow = aRange.aStart.Row();
+ SCCOL nEndCol = aRange.aEnd.Col();
+ SCROW nEndRow = aRange.aEnd.Row();
+ SCTAB nTab = aRange.aStart.Tab();
+ if (pTab[nTab])
+ pTab[nTab]->LimitChartArea(nStartCol, nStartRow, nEndCol, nEndRow);
+ aRange.aStart.SetCol( nStartCol );
+ aRange.aStart.SetRow( nStartRow );
+ aRange.aEnd.SetCol( nEndCol );
+ aRange.aEnd.SetRow( nEndRow );
+ }
+ aNew->Append(aRange);
+ }
+ }
+ else
+ {
+ DBG_ERROR("LimitChartIfAll: Ref==0");
+ }
+ rRangeList = aNew;
+}
+
+
+void lcl_GetFirstTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark )
+{
+ // without ScMarkData, leave start/end unchanged
+ if ( pTabMark )
+ {
+ for (SCTAB nTab=0; nTab<=MAXTAB; ++nTab)
+ if (pTabMark->GetTableSelect(nTab))
+ {
+ // find first range of consecutive selected sheets
+ rTabRangeStart = nTab;
+ while ( nTab+1 <= MAXTAB && pTabMark->GetTableSelect(nTab+1) )
+ ++nTab;
+ rTabRangeEnd = nTab;
+ return;
+ }
+ }
+}
+
+bool lcl_GetNextTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark )
+{
+ if ( pTabMark )
+ {
+ // find next range of consecutive selected sheets after rTabRangeEnd
+ for (SCTAB nTab=rTabRangeEnd+1; nTab<=MAXTAB; ++nTab)
+ if (pTabMark->GetTableSelect(nTab))
+ {
+ rTabRangeStart = nTab;
+ while ( nTab+1 <= MAXTAB && pTabMark->GetTableSelect(nTab+1) )
+ ++nTab;
+ rTabRangeEnd = nTab;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+BOOL ScDocument::CanInsertRow( const ScRange& rRange ) const
+{
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+ PutInOrder( nStartCol, nEndCol );
+ PutInOrder( nStartRow, nEndRow );
+ PutInOrder( nStartTab, nEndTab );
+ SCSIZE nSize = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
+
+ BOOL bTest = TRUE;
+ for (SCTAB i=nStartTab; i<=nEndTab && bTest; i++)
+ if (pTab[i])
+ bTest &= pTab[i]->TestInsertRow( nStartCol, nEndCol, nSize );
+
+ return bTest;
+}
+
+
+BOOL ScDocument::InsertRow( SCCOL nStartCol, SCTAB nStartTab,
+ SCCOL nEndCol, SCTAB nEndTab,
+ SCROW nStartRow, SCSIZE nSize, ScDocument* pRefUndoDoc,
+ const ScMarkData* pTabMark )
+{
+ SCTAB i;
+
+ PutInOrder( nStartCol, nEndCol );
+ PutInOrder( nStartTab, nEndTab );
+ if ( pTabMark )
+ {
+ nStartTab = 0;
+ nEndTab = MAXTAB;
+ }
+
+ BOOL bTest = TRUE;
+ BOOL bRet = FALSE;
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ for ( i = nStartTab; i <= nEndTab && bTest; i++)
+ if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
+ bTest &= pTab[i]->TestInsertRow( nStartCol, nEndCol, nSize );
+ if (bTest)
+ {
+ // UpdateBroadcastAreas muss vor UpdateReference gerufen werden, damit nicht
+ // Eintraege verschoben werden, die erst bei UpdateReference neu erzeugt werden
+
+ // handle chunks of consecutive selected sheets together
+ SCTAB nTabRangeStart = nStartTab;
+ SCTAB nTabRangeEnd = nEndTab;
+ lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+ do
+ {
+ UpdateBroadcastAreas( URM_INSDEL, ScRange(
+ ScAddress( nStartCol, nStartRow, nTabRangeStart ),
+ ScAddress( nEndCol, MAXROW, nTabRangeEnd )), 0, static_cast<SCsROW>(nSize), 0 );
+ }
+ while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+
+ lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+ do
+ {
+ UpdateReference( URM_INSDEL, nStartCol, nStartRow, nTabRangeStart,
+ nEndCol, MAXROW, nTabRangeEnd,
+ 0, static_cast<SCsROW>(nSize), 0, pRefUndoDoc, FALSE ); // without drawing objects
+ }
+ while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+
+ for (i=nStartTab; i<=nEndTab; i++)
+ if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
+ pTab[i]->InsertRow( nStartCol, nEndCol, nStartRow, nSize );
+
+ // #82991# UpdateRef for drawing layer must be after inserting,
+ // when the new row heights are known.
+ for (i=nStartTab; i<=nEndTab; i++)
+ if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
+ pTab[i]->UpdateDrawRef( URM_INSDEL,
+ nStartCol, nStartRow, nStartTab, nEndCol, MAXROW, nEndTab,
+ 0, static_cast<SCsROW>(nSize), 0 );
+
+ if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
+ { // durch Restaurierung von Referenzen auf geloeschte Bereiche ist
+ // ein neues Listening faellig, bisherige Listener wurden in
+ // FormulaCell UpdateReference abgehaengt
+ StartAllListeners();
+ }
+ else
+ { // Listeners have been removed in UpdateReference
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->StartNeededListeners();
+ // #69592# at least all cells using range names pointing relative
+ // to the moved range must recalculate
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->SetRelNameDirty();
+ }
+ bRet = TRUE;
+ }
+ SetAutoCalc( bOldAutoCalc );
+ if ( bRet )
+ pChartListenerCollection->UpdateDirtyCharts();
+ return bRet;
+}
+
+
+BOOL ScDocument::InsertRow( const ScRange& rRange, ScDocument* pRefUndoDoc )
+{
+ return InsertRow( rRange.aStart.Col(), rRange.aStart.Tab(),
+ rRange.aEnd.Col(), rRange.aEnd.Tab(),
+ rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
+ pRefUndoDoc );
+}
+
+
+void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
+ SCCOL nEndCol, SCTAB nEndTab,
+ SCROW nStartRow, SCSIZE nSize,
+ ScDocument* pRefUndoDoc, BOOL* pUndoOutline,
+ const ScMarkData* pTabMark )
+{
+ SCTAB i;
+
+ PutInOrder( nStartCol, nEndCol );
+ PutInOrder( nStartTab, nEndTab );
+ if ( pTabMark )
+ {
+ nStartTab = 0;
+ nEndTab = MAXTAB;
+ }
+
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+
+ // handle chunks of consecutive selected sheets together
+ SCTAB nTabRangeStart = nStartTab;
+ SCTAB nTabRangeEnd = nEndTab;
+ lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+ do
+ {
+ if ( ValidRow(nStartRow+nSize) )
+ {
+ DelBroadcastAreasInRange( ScRange(
+ ScAddress( nStartCol, nStartRow, nTabRangeStart ),
+ ScAddress( nEndCol, nStartRow+nSize-1, nTabRangeEnd ) ) );
+ UpdateBroadcastAreas( URM_INSDEL, ScRange(
+ ScAddress( nStartCol, nStartRow+nSize, nTabRangeStart ),
+ ScAddress( nEndCol, MAXROW, nTabRangeEnd )), 0, -(static_cast<SCsROW>(nSize)), 0 );
+ }
+ else
+ DelBroadcastAreasInRange( ScRange(
+ ScAddress( nStartCol, nStartRow, nTabRangeStart ),
+ ScAddress( nEndCol, MAXROW, nTabRangeEnd ) ) );
+ }
+ while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+
+ if ( ValidRow(nStartRow+nSize) )
+ {
+ lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+ do
+ {
+ UpdateReference( URM_INSDEL, nStartCol, nStartRow+nSize, nTabRangeStart,
+ nEndCol, MAXROW, nTabRangeEnd,
+ 0, -(static_cast<SCsROW>(nSize)), 0, pRefUndoDoc, TRUE, false );
+ }
+ while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+ }
+
+ if (pUndoOutline)
+ *pUndoOutline = FALSE;
+
+ for ( i = nStartTab; i <= nEndTab; i++)
+ if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
+ pTab[i]->DeleteRow( nStartCol, nEndCol, nStartRow, nSize, pUndoOutline );
+
+ if ( ValidRow(nStartRow+nSize) )
+ { // Listeners have been removed in UpdateReference
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->StartNeededListeners();
+ // #69592# at least all cells using range names pointing relative to
+ // the moved range must recalculate
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->SetRelNameDirty();
+ }
+
+ SetAutoCalc( bOldAutoCalc );
+ pChartListenerCollection->UpdateDirtyCharts();
+}
+
+
+void ScDocument::DeleteRow( const ScRange& rRange, ScDocument* pRefUndoDoc, BOOL* pUndoOutline )
+{
+ DeleteRow( rRange.aStart.Col(), rRange.aStart.Tab(),
+ rRange.aEnd.Col(), rRange.aEnd.Tab(),
+ rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
+ pRefUndoDoc, pUndoOutline );
+}
+
+
+BOOL ScDocument::CanInsertCol( const ScRange& rRange ) const
+{
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+ PutInOrder( nStartCol, nEndCol );
+ PutInOrder( nStartRow, nEndRow );
+ PutInOrder( nStartTab, nEndTab );
+ SCSIZE nSize = static_cast<SCSIZE>(nEndCol - nStartCol + 1);
+
+ BOOL bTest = TRUE;
+ for (SCTAB i=nStartTab; i<=nEndTab && bTest; i++)
+ if (pTab[i])
+ bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
+
+ return bTest;
+}
+
+
+BOOL ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
+ SCROW nEndRow, SCTAB nEndTab,
+ SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
+ const ScMarkData* pTabMark )
+{
+ SCTAB i;
+
+ PutInOrder( nStartRow, nEndRow );
+ PutInOrder( nStartTab, nEndTab );
+ if ( pTabMark )
+ {
+ nStartTab = 0;
+ nEndTab = MAXTAB;
+ }
+
+ BOOL bTest = TRUE;
+ BOOL bRet = FALSE;
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ for ( i = nStartTab; i <= nEndTab && bTest; i++)
+ if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
+ bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
+ if (bTest)
+ {
+ // handle chunks of consecutive selected sheets together
+ SCTAB nTabRangeStart = nStartTab;
+ SCTAB nTabRangeEnd = nEndTab;
+ lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+ do
+ {
+ UpdateBroadcastAreas( URM_INSDEL, ScRange(
+ ScAddress( nStartCol, nStartRow, nTabRangeStart ),
+ ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), static_cast<SCsCOL>(nSize), 0, 0 );
+ }
+ while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+
+ lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+ do
+ {
+ UpdateReference( URM_INSDEL, nStartCol, nStartRow, nTabRangeStart,
+ MAXCOL, nEndRow, nTabRangeEnd,
+ static_cast<SCsCOL>(nSize), 0, 0, pRefUndoDoc, TRUE, false );
+ }
+ while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+
+ for (i=nStartTab; i<=nEndTab; i++)
+ if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
+ pTab[i]->InsertCol( nStartCol, nStartRow, nEndRow, nSize );
+
+ if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
+ { // durch Restaurierung von Referenzen auf geloeschte Bereiche ist
+ // ein neues Listening faellig, bisherige Listener wurden in
+ // FormulaCell UpdateReference abgehaengt
+ StartAllListeners();
+ }
+ else
+ { // Listeners have been removed in UpdateReference
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->StartNeededListeners();
+ // #69592# at least all cells using range names pointing relative
+ // to the moved range must recalculate
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->SetRelNameDirty();
+ }
+ bRet = TRUE;
+ }
+ SetAutoCalc( bOldAutoCalc );
+ if ( bRet )
+ pChartListenerCollection->UpdateDirtyCharts();
+ return bRet;
+}
+
+
+BOOL ScDocument::InsertCol( const ScRange& rRange, ScDocument* pRefUndoDoc )
+{
+ return InsertCol( rRange.aStart.Row(), rRange.aStart.Tab(),
+ rRange.aEnd.Row(), rRange.aEnd.Tab(),
+ rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
+ pRefUndoDoc );
+}
+
+
+void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTAB nEndTab,
+ SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
+ BOOL* pUndoOutline, const ScMarkData* pTabMark )
+{
+ SCTAB i;
+
+ PutInOrder( nStartRow, nEndRow );
+ PutInOrder( nStartTab, nEndTab );
+ if ( pTabMark )
+ {
+ nStartTab = 0;
+ nEndTab = MAXTAB;
+ }
+
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+
+ // handle chunks of consecutive selected sheets together
+ SCTAB nTabRangeStart = nStartTab;
+ SCTAB nTabRangeEnd = nEndTab;
+ lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+ do
+ {
+ if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
+ {
+ DelBroadcastAreasInRange( ScRange(
+ ScAddress( nStartCol, nStartRow, nTabRangeStart ),
+ ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize-1), nEndRow, nTabRangeEnd ) ) );
+ UpdateBroadcastAreas( URM_INSDEL, ScRange(
+ ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart ),
+ ScAddress( MAXCOL, nEndRow, nTabRangeEnd )), -static_cast<SCsCOL>(nSize), 0, 0 );
+ }
+ else
+ DelBroadcastAreasInRange( ScRange(
+ ScAddress( nStartCol, nStartRow, nTabRangeStart ),
+ ScAddress( MAXCOL, nEndRow, nTabRangeEnd ) ) );
+ }
+ while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+
+ if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
+ {
+ lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark );
+ do
+ {
+ UpdateReference( URM_INSDEL, sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart,
+ MAXCOL, nEndRow, nTabRangeEnd,
+ -static_cast<SCsCOL>(nSize), 0, 0, pRefUndoDoc, TRUE, false );
+ }
+ while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark ) );
+ }
+
+ if (pUndoOutline)
+ *pUndoOutline = FALSE;
+
+ for ( i = nStartTab; i <= nEndTab; i++)
+ if (pTab[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
+ pTab[i]->DeleteCol( nStartCol, nStartRow, nEndRow, nSize, pUndoOutline );
+
+ if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
+ { // Listeners have been removed in UpdateReference
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->StartNeededListeners();
+ // #69592# at least all cells using range names pointing relative to
+ // the moved range must recalculate
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->SetRelNameDirty();
+ }
+
+ SetAutoCalc( bOldAutoCalc );
+ pChartListenerCollection->UpdateDirtyCharts();
+}
+
+
+void ScDocument::DeleteCol( const ScRange& rRange, ScDocument* pRefUndoDoc, BOOL* pUndoOutline )
+{
+ DeleteCol( rRange.aStart.Row(), rRange.aStart.Tab(),
+ rRange.aEnd.Row(), rRange.aEnd.Tab(),
+ rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
+ pRefUndoDoc, pUndoOutline );
+}
+
+
+// fuer Area-Links: Zellen einuegen/loeschen, wenn sich der Bereich veraendert
+// (ohne Paint)
+
+
+void lcl_GetInsDelRanges( const ScRange& rOld, const ScRange& rNew,
+ ScRange& rColRange, BOOL& rInsCol, BOOL& rDelCol,
+ ScRange& rRowRange, BOOL& rInsRow, BOOL& rDelRow )
+{
+ DBG_ASSERT( rOld.aStart == rNew.aStart, "FitBlock: Anfang unterschiedlich" );
+
+ rInsCol = rDelCol = rInsRow = rDelRow = FALSE;
+
+ SCCOL nStartX = rOld.aStart.Col();
+ SCROW nStartY = rOld.aStart.Row();
+ SCCOL nOldEndX = rOld.aEnd.Col();
+ SCROW nOldEndY = rOld.aEnd.Row();
+ SCCOL nNewEndX = rNew.aEnd.Col();
+ SCROW nNewEndY = rNew.aEnd.Row();
+ SCTAB nTab = rOld.aStart.Tab();
+
+ // wenn es mehr Zeilen werden, werden Spalten auf der alten Hoehe eingefuegt/geloescht
+ BOOL bGrowY = ( nNewEndY > nOldEndY );
+ SCROW nColEndY = bGrowY ? nOldEndY : nNewEndY;
+ SCCOL nRowEndX = bGrowY ? nNewEndX : nOldEndX;
+
+ // Spalten
+
+ if ( nNewEndX > nOldEndX ) // Spalten einfuegen
+ {
+ rColRange = ScRange( nOldEndX+1, nStartY, nTab, nNewEndX, nColEndY, nTab );
+ rInsCol = TRUE;
+ }
+ else if ( nNewEndX < nOldEndX ) // Spalten loeschen
+ {
+ rColRange = ScRange( nNewEndX+1, nStartY, nTab, nOldEndX, nColEndY, nTab );
+ rDelCol = TRUE;
+ }
+
+ // Zeilen
+
+ if ( nNewEndY > nOldEndY ) // Zeilen einfuegen
+ {
+ rRowRange = ScRange( nStartX, nOldEndY+1, nTab, nRowEndX, nNewEndY, nTab );
+ rInsRow = TRUE;
+ }
+ else if ( nNewEndY < nOldEndY ) // Zeilen loeschen
+ {
+ rRowRange = ScRange( nStartX, nNewEndY+1, nTab, nRowEndX, nOldEndY, nTab );
+ rDelRow = TRUE;
+ }
+}
+
+
+BOOL ScDocument::HasPartOfMerged( const ScRange& rRange )
+{
+ BOOL bPart = FALSE;
+ SCTAB nTab = rRange.aStart.Tab();
+
+ SCCOL nStartX = rRange.aStart.Col();
+ SCROW nStartY = rRange.aStart.Row();
+ SCCOL nEndX = rRange.aEnd.Col();
+ SCROW nEndY = rRange.aEnd.Row();
+
+ if (HasAttrib( nStartX, nStartY, nTab, nEndX, nEndY, nTab,
+ HASATTR_MERGED | HASATTR_OVERLAPPED ))
+ {
+ ExtendMerge( nStartX, nStartY, nEndX, nEndY, nTab );
+ ExtendOverlapped( nStartX, nStartY, nEndX, nEndY, nTab );
+
+ bPart = ( nStartX != rRange.aStart.Col() || nEndX != rRange.aEnd.Col() ||
+ nStartY != rRange.aStart.Row() || nEndY != rRange.aEnd.Row() );
+ }
+ return bPart;
+}
+
+
+BOOL ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
+{
+ if ( rOld == rNew )
+ return TRUE;
+
+ BOOL bOk = TRUE;
+ BOOL bInsCol,bDelCol,bInsRow,bDelRow;
+ ScRange aColRange,aRowRange;
+ lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
+
+ if ( bInsCol && !CanInsertCol( aColRange ) ) // Zellen am Rand ?
+ bOk = FALSE;
+ if ( bInsRow && !CanInsertRow( aRowRange ) ) // Zellen am Rand ?
+ bOk = FALSE;
+
+ if ( bInsCol || bDelCol )
+ {
+ aColRange.aEnd.SetCol(MAXCOL);
+ if ( HasPartOfMerged(aColRange) )
+ bOk = FALSE;
+ }
+ if ( bInsRow || bDelRow )
+ {
+ aRowRange.aEnd.SetRow(MAXROW);
+ if ( HasPartOfMerged(aRowRange) )
+ bOk = FALSE;
+ }
+
+ return bOk;
+}
+
+
+void ScDocument::FitBlock( const ScRange& rOld, const ScRange& rNew, BOOL bClear )
+{
+ if (bClear)
+ DeleteAreaTab( rOld, IDF_ALL );
+
+ BOOL bInsCol,bDelCol,bInsRow,bDelRow;
+ ScRange aColRange,aRowRange;
+ lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
+
+ if ( bInsCol )
+ InsertCol( aColRange ); // Spalten zuerst einfuegen
+ if ( bInsRow )
+ InsertRow( aRowRange );
+
+ if ( bDelRow )
+ DeleteRow( aRowRange ); // Zeilen zuerst loeschen
+ if ( bDelCol )
+ DeleteCol( aColRange );
+
+ // Referenzen um eingefuegte Zeilen erweitern
+
+ if ( bInsCol || bInsRow )
+ {
+ ScRange aGrowSource = rOld;
+ aGrowSource.aEnd.SetCol(Min( rOld.aEnd.Col(), rNew.aEnd.Col() ));
+ aGrowSource.aEnd.SetRow(Min( rOld.aEnd.Row(), rNew.aEnd.Row() ));
+ SCCOL nGrowX = bInsCol ? ( rNew.aEnd.Col() - rOld.aEnd.Col() ) : 0;
+ SCROW nGrowY = bInsRow ? ( rNew.aEnd.Row() - rOld.aEnd.Row() ) : 0;
+ UpdateGrow( aGrowSource, nGrowX, nGrowY );
+ }
+}
+
+
+void ScDocument::DeleteArea(SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2,
+ const ScMarkData& rMark, USHORT nDelFlag)
+{
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ for (SCTAB i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ if ( rMark.GetTableSelect(i) || bIsUndo )
+ pTab[i]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
+ SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScDocument::DeleteAreaTab(SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2,
+ SCTAB nTab, USHORT nDelFlag)
+{
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ {
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ pTab[nTab]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
+ SetAutoCalc( bOldAutoCalc );
+ }
+}
+
+
+void ScDocument::DeleteAreaTab( const ScRange& rRange, USHORT nDelFlag )
+{
+ for ( SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); nTab++ )
+ DeleteAreaTab( rRange.aStart.Col(), rRange.aStart.Row(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(),
+ nTab, nDelFlag );
+}
+
+
+void ScDocument::InitUndoSelected( ScDocument* pSrcDoc, const ScMarkData& rTabSelection,
+ BOOL bColInfo, BOOL bRowInfo )
+{
+ if (bIsUndo)
+ {
+ Clear();
+
+ xPoolHelper = pSrcDoc->xPoolHelper;
+
+ String aString;
+ for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
+ if ( rTabSelection.GetTableSelect( nTab ) )
+ {
+ pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
+ nMaxTableNumber = nTab + 1;
+ }
+ }
+ else
+ {
+ DBG_ERROR("InitUndo");
+ }
+}
+
+
+void ScDocument::InitUndo( ScDocument* pSrcDoc, SCTAB nTab1, SCTAB nTab2,
+ BOOL bColInfo, BOOL bRowInfo )
+{
+ if (bIsUndo)
+ {
+ Clear();
+
+ xPoolHelper = pSrcDoc->xPoolHelper;
+
+ String aString;
+ for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
+ pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
+
+ nMaxTableNumber = nTab2 + 1;
+ }
+ else
+ {
+ DBG_ERROR("InitUndo");
+ }
+}
+
+
+void ScDocument::AddUndoTab( SCTAB nTab1, SCTAB nTab2, BOOL bColInfo, BOOL bRowInfo )
+{
+ if (bIsUndo)
+ {
+ String aString;
+ for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
+ if (!pTab[nTab])
+ pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
+
+ if ( nMaxTableNumber <= nTab2 )
+ nMaxTableNumber = nTab2 + 1;
+ }
+ else
+ {
+ DBG_ERROR("InitUndo");
+ }
+}
+
+
+void ScDocument::SetCutMode( BOOL bVal )
+{
+ if (bIsClip)
+ GetClipParam().mbCutMode = bVal;
+ else
+ {
+ DBG_ERROR("SetCutMode without bIsClip");
+ }
+}
+
+
+BOOL ScDocument::IsCutMode()
+{
+ if (bIsClip)
+ return GetClipParam().mbCutMode;
+ else
+ {
+ DBG_ERROR("IsCutMode ohne bIsClip");
+ return FALSE;
+ }
+}
+
+
+void ScDocument::CopyToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
+ USHORT nFlags, BOOL bOnlyMarked, ScDocument* pDestDoc,
+ const ScMarkData* pMarks, BOOL bColRowFlags )
+{
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ PutInOrder( nTab1, nTab2 );
+ if( !pDestDoc->aDocName.Len() )
+ pDestDoc->aDocName = aDocName;
+ if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
+ {
+ BOOL bOldAutoCalc = pDestDoc->GetAutoCalc();
+ pDestDoc->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ for (SCTAB i = nTab1; i <= nTab2; i++)
+ {
+ if (pTab[i] && pDestDoc->pTab[i])
+ pTab[i]->CopyToTable( nCol1, nRow1, nCol2, nRow2, nFlags,
+ bOnlyMarked, pDestDoc->pTab[i], pMarks,
+ FALSE, bColRowFlags );
+ }
+ pDestDoc->SetAutoCalc( bOldAutoCalc );
+ }
+}
+
+
+void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
+ USHORT nFlags, BOOL bOnlyMarked, ScDocument* pDestDoc,
+ const ScMarkData* pMarks)
+{
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ PutInOrder( nTab1, nTab2 );
+ if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
+ {
+ BOOL bOldAutoCalc = pDestDoc->GetAutoCalc();
+ pDestDoc->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ if (nTab1 > 0)
+ CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, FALSE, pDestDoc, pMarks );
+
+ for (SCTAB i = nTab1; i <= nTab2; i++)
+ {
+ if (pTab[i] && pDestDoc->pTab[i])
+ pTab[i]->UndoToTable(nCol1, nRow1, nCol2, nRow2, nFlags,
+ bOnlyMarked, pDestDoc->pTab[i], pMarks);
+ }
+
+ if (nTab2 < MAXTAB)
+ CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA, FALSE, pDestDoc, pMarks );
+ pDestDoc->SetAutoCalc( bOldAutoCalc );
+ }
+}
+
+
+void ScDocument::CopyToDocument(const ScRange& rRange,
+ USHORT nFlags, BOOL bOnlyMarked, ScDocument* pDestDoc,
+ const ScMarkData* pMarks, BOOL bColRowFlags)
+{
+ ScRange aNewRange = rRange;
+ aNewRange.Justify();
+
+ if( !pDestDoc->aDocName.Len() )
+ pDestDoc->aDocName = aDocName;
+ BOOL bOldAutoCalc = pDestDoc->GetAutoCalc();
+ pDestDoc->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ for (SCTAB i = aNewRange.aStart.Tab(); i <= aNewRange.aEnd.Tab(); i++)
+ if (pTab[i] && pDestDoc->pTab[i])
+ pTab[i]->CopyToTable(aNewRange.aStart.Col(), aNewRange.aStart.Row(),
+ aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
+ nFlags, bOnlyMarked, pDestDoc->pTab[i],
+ pMarks, FALSE, bColRowFlags);
+ pDestDoc->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScDocument::UndoToDocument(const ScRange& rRange,
+ USHORT nFlags, BOOL bOnlyMarked, ScDocument* pDestDoc,
+ const ScMarkData* pMarks)
+{
+ ScRange aNewRange = rRange;
+ aNewRange.Justify();
+ SCTAB nTab1 = aNewRange.aStart.Tab();
+ SCTAB nTab2 = aNewRange.aEnd.Tab();
+
+ BOOL bOldAutoCalc = pDestDoc->GetAutoCalc();
+ pDestDoc->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ if (nTab1 > 0)
+ CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, FALSE, pDestDoc, pMarks );
+
+ for (SCTAB i = nTab1; i <= nTab2; i++)
+ {
+ if (pTab[i] && pDestDoc->pTab[i])
+ pTab[i]->UndoToTable(aNewRange.aStart.Col(), aNewRange.aStart.Row(),
+ aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
+ nFlags, bOnlyMarked, pDestDoc->pTab[i], pMarks);
+ }
+
+ if (nTab2 < MAXTAB)
+ CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA, FALSE, pDestDoc, pMarks );
+ pDestDoc->SetAutoCalc( bOldAutoCalc );
+}
+
+void ScDocument::CopyToClip(const ScClipParam& rClipParam,
+ ScDocument* pClipDoc, const ScMarkData* pMarks,
+ bool bAllTabs, bool bKeepScenarioFlags, bool bIncludeObjects, bool bCloneNoteCaptions)
+{
+ DBG_ASSERT( bAllTabs || pMarks, "CopyToClip: ScMarkData fehlt" );
+
+ if (bIsClip)
+ return;
+
+ if (!pClipDoc)
+ {
+ DBG_ERROR("CopyToClip: no ClipDoc");
+ pClipDoc = SC_MOD()->GetClipDoc();
+ }
+
+ pClipDoc->aDocName = aDocName;
+ pClipDoc->SetClipParam(rClipParam);
+ pClipDoc->ResetClip(this, pMarks);
+
+ ScRange aClipRange = rClipParam.getWholeRange();
+ CopyRangeNamesToClip(pClipDoc, aClipRange, pMarks, bAllTabs);
+
+ for (SCTAB i = 0; i <= MAXTAB; ++i)
+ {
+ if (!pTab[i] || !pClipDoc->pTab[i])
+ continue;
+
+ if (pMarks && !pMarks->GetTableSelect(i))
+ continue;
+
+ pTab[i]->CopyToClip(rClipParam.maRanges, pClipDoc->pTab[i], bKeepScenarioFlags, bCloneNoteCaptions);
+
+ if (pDrawLayer && bIncludeObjects)
+ {
+ // also copy drawing objects
+ Rectangle aObjRect = GetMMRect(
+ aClipRange.aStart.Col(), aClipRange.aStart.Row(), aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i);
+ pDrawLayer->CopyToClip(pClipDoc, i, aObjRect);
+ }
+ }
+
+ // Make sure to mark overlapped cells.
+ pClipDoc->ExtendMerge(aClipRange, true);
+}
+
+void ScDocument::CopyTabToClip(SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2,
+ SCTAB nTab, ScDocument* pClipDoc)
+{
+ if (!bIsClip)
+ {
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ if (!pClipDoc)
+ {
+ DBG_ERROR("CopyTabToClip: no ClipDoc");
+ pClipDoc = SC_MOD()->GetClipDoc();
+ }
+
+ ScClipParam& rClipParam = pClipDoc->GetClipParam();
+ pClipDoc->aDocName = aDocName;
+ rClipParam.maRanges.RemoveAll();
+ rClipParam.maRanges.Append(ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0));
+ pClipDoc->ResetClip( this, nTab );
+
+ if (pTab[nTab] && pClipDoc->pTab[nTab])
+ pTab[nTab]->CopyToClip(nCol1, nRow1, nCol2, nRow2, pClipDoc->pTab[nTab], FALSE, TRUE);
+
+ pClipDoc->GetClipParam().mbCutMode = false;
+ }
+}
+
+
+void ScDocument::TransposeClip( ScDocument* pTransClip, USHORT nFlags, BOOL bAsLink )
+{
+ DBG_ASSERT( bIsClip && pTransClip && pTransClip->bIsClip,
+ "TransposeClip mit falschem Dokument" );
+
+ // initialisieren
+ // -> pTransClip muss vor dem Original-Dokument geloescht werden!
+
+ pTransClip->ResetClip(this, (ScMarkData*)NULL); // alle
+
+ // Bereiche uebernehmen
+
+ pTransClip->pRangeName->FreeAll();
+ for (USHORT i = 0; i < pRangeName->GetCount(); i++) //! DB-Bereiche Pivot-Bereiche auch !!!
+ {
+ USHORT nIndex = ((ScRangeData*)((*pRangeName)[i]))->GetIndex();
+ ScRangeData* pData = new ScRangeData(*((*pRangeName)[i]));
+ if (!pTransClip->pRangeName->Insert(pData))
+ delete pData;
+ else
+ pData->SetIndex(nIndex);
+ }
+
+ // Daten
+
+ ScRange aClipRange = GetClipParam().getWholeRange();
+ if ( ValidRow(aClipRange.aEnd.Row()-aClipRange.aStart.Row()) )
+ {
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ {
+ DBG_ASSERT( pTransClip->pTab[i], "TransposeClip: Tabelle nicht da" );
+ pTab[i]->TransposeClip( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
+ aClipRange.aEnd.Col(), aClipRange.aEnd.Row(),
+ pTransClip->pTab[i], nFlags, bAsLink );
+
+ if ( pDrawLayer && ( nFlags & IDF_OBJECTS ) )
+ {
+ // Drawing objects are copied to the new area without transposing.
+ // CopyFromClip is used to adjust the objects to the transposed block's
+ // cell range area.
+ // (pDrawLayer in the original clipboard document is set only if there
+ // are drawing objects to copy)
+
+ pTransClip->InitDrawLayer();
+ Rectangle aSourceRect = GetMMRect( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
+ aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i );
+ Rectangle aDestRect = pTransClip->GetMMRect( 0, 0,
+ static_cast<SCCOL>(aClipRange.aEnd.Row() - aClipRange.aStart.Row()),
+ static_cast<SCROW>(aClipRange.aEnd.Col() - aClipRange.aStart.Col()), i );
+ pTransClip->pDrawLayer->CopyFromClip( pDrawLayer, i, aSourceRect, ScAddress(0,0,i), aDestRect );
+ }
+ }
+
+ pTransClip->SetClipParam(GetClipParam());
+ pTransClip->GetClipParam().transpose();
+ }
+ else
+ {
+ DBG_ERROR("TransposeClip: zu gross");
+ }
+
+ // Dies passiert erst beim Einfuegen...
+
+ GetClipParam().mbCutMode = false;
+}
+
+void ScDocument::CopyRangeNamesToClip(ScDocument* pClipDoc, const ScRange& rClipRange, const ScMarkData* pMarks, bool bAllTabs)
+{
+ std::set<USHORT> aUsedNames; // indexes of named ranges that are used in the copied cells
+ for (SCTAB i = 0; i <= MAXTAB; ++i)
+ if (pTab[i] && pClipDoc->pTab[i])
+ if ( bAllTabs || !pMarks || pMarks->GetTableSelect(i) )
+ pTab[i]->FindRangeNamesInUse(
+ rClipRange.aStart.Col(), rClipRange.aStart.Row(),
+ rClipRange.aEnd.Col(), rClipRange.aEnd.Row(), aUsedNames);
+
+ pClipDoc->pRangeName->FreeAll();
+ for (USHORT i = 0; i < pRangeName->GetCount(); i++) //! DB-Bereiche Pivot-Bereiche auch !!!
+ {
+ USHORT nIndex = ((ScRangeData*)((*pRangeName)[i]))->GetIndex();
+ bool bInUse = ( aUsedNames.find(nIndex) != aUsedNames.end() );
+ if (bInUse)
+ {
+ ScRangeData* pData = new ScRangeData(*((*pRangeName)[i]));
+ if (!pClipDoc->pRangeName->Insert(pData))
+ delete pData;
+ else
+ pData->SetIndex(nIndex);
+ }
+ }
+}
+
+ScDocument::NumFmtMergeHandler::NumFmtMergeHandler(ScDocument* pDoc, ScDocument* pSrcDoc) :
+ mpDoc(pDoc)
+{
+ mpDoc->MergeNumberFormatter(pSrcDoc);
+}
+
+ScDocument::NumFmtMergeHandler::~NumFmtMergeHandler()
+{
+ mpDoc->pFormatExchangeList = NULL;
+}
+
+void ScDocument::MergeNumberFormatter(ScDocument* pSrcDoc)
+{
+ SvNumberFormatter* pThisFormatter = xPoolHelper->GetFormTable();
+ SvNumberFormatter* pOtherFormatter = pSrcDoc->xPoolHelper->GetFormTable();
+ if (pOtherFormatter && pOtherFormatter != pThisFormatter)
+ {
+ SvNumberFormatterIndexTable* pExchangeList =
+ pThisFormatter->MergeFormatter(*(pOtherFormatter));
+ if (pExchangeList->Count() > 0)
+ pFormatExchangeList = pExchangeList;
+ }
+}
+
+void ScDocument::CopyRangeNamesFromClip(ScDocument* pClipDoc, ScClipRangeNameData& rRangeNames)
+{
+ sal_uInt16 nClipRangeNameCount = pClipDoc->pRangeName->GetCount();
+ ScClipRangeNameData aClipRangeNames;
+
+ // array containing range names which might need update of indices
+ aClipRangeNames.mpRangeNames.resize(nClipRangeNameCount, NULL);
+
+ for (sal_uInt16 i = 0; i < nClipRangeNameCount; ++i) //! DB-Bereiche Pivot-Bereiche auch
+ {
+ /* Copy only if the name doesn't exist in this document.
+ If it exists we use the already existing name instead,
+ another possibility could be to create new names if
+ documents differ.
+ A proper solution would ask the user how to proceed.
+ The adjustment of the indices in the formulas is done later.
+ */
+ ScRangeData* pClipRangeData = (*pClipDoc->pRangeName)[i];
+ USHORT k;
+ if ( pRangeName->SearchName( pClipRangeData->GetName(), k ) )
+ {
+ aClipRangeNames.mpRangeNames[i] = NULL; // range name not inserted
+ USHORT nOldIndex = pClipRangeData->GetIndex();
+ USHORT nNewIndex = ((*pRangeName)[k])->GetIndex();
+ aClipRangeNames.insert(nOldIndex, nNewIndex);
+ if ( !aClipRangeNames.mbReplace )
+ aClipRangeNames.mbReplace = ( nOldIndex != nNewIndex );
+ }
+ else
+ {
+ ScRangeData* pData = new ScRangeData( *pClipRangeData );
+ pData->SetDocument(this);
+ if ( pRangeName->FindIndex( pData->GetIndex() ) )
+ pData->SetIndex(0); // need new index, done in Insert
+ if ( pRangeName->Insert( pData ) )
+ {
+ aClipRangeNames.mpRangeNames[i] = pData;
+ USHORT nOldIndex = pClipRangeData->GetIndex();
+ USHORT nNewIndex = pData->GetIndex();
+ aClipRangeNames.insert(nOldIndex, nNewIndex);
+ if ( !aClipRangeNames.mbReplace )
+ aClipRangeNames.mbReplace = ( nOldIndex != nNewIndex );
+ }
+ else
+ { // must be an overflow
+ delete pData;
+ aClipRangeNames.mpRangeNames[i] = NULL;
+ aClipRangeNames.insert(pClipRangeData->GetIndex(), 0);
+ aClipRangeNames.mbReplace = true;
+ }
+ }
+ }
+ rRangeNames = aClipRangeNames;
+}
+
+void ScDocument::UpdateRangeNamesInFormulas(
+ ScClipRangeNameData& rRangeNames, const ScRangeList& rDestRanges, const ScMarkData& rMark,
+ SCCOL nXw, SCROW nYw)
+{
+ // nXw and nYw are the extra width and height of the destination range
+ // extended due to presence of merged cell(s).
+
+ if (!rRangeNames.mbReplace)
+ return;
+
+ // first update all inserted named formulas if they contain other
+ // range names and used indices changed
+ size_t nRangeNameCount = rRangeNames.mpRangeNames.size();
+ for (size_t i = 0; i < nRangeNameCount; ++i) //! DB-Bereiche Pivot-Bereiche auch
+ {
+ if ( rRangeNames.mpRangeNames[i] )
+ rRangeNames.mpRangeNames[i]->ReplaceRangeNamesInUse(rRangeNames.maRangeMap);
+ }
+ // then update the formulas, they might need just the updated range names
+ for (ULONG nRange = 0; nRange < rDestRanges.Count(); ++nRange)
+ {
+ const ScRange* pRange = rDestRanges.GetObject( nRange);
+ SCCOL nCol1 = pRange->aStart.Col();
+ SCROW nRow1 = pRange->aStart.Row();
+ SCCOL nCol2 = pRange->aEnd.Col();
+ SCROW nRow2 = pRange->aEnd.Row();
+
+ SCCOL nC1 = nCol1;
+ SCROW nR1 = nRow1;
+ SCCOL nC2 = nC1 + nXw;
+ if (nC2 > nCol2)
+ nC2 = nCol2;
+ SCROW nR2 = nR1 + nYw;
+ if (nR2 > nRow2)
+ nR2 = nRow2;
+ do
+ {
+ do
+ {
+ for (SCTAB k = 0; k <= MAXTAB; k++)
+ {
+ if ( pTab[k] && rMark.GetTableSelect(k) )
+ pTab[k]->ReplaceRangeNamesInUse(nC1, nR1,
+ nC2, nR2, rRangeNames.maRangeMap);
+ }
+ nC1 = nC2 + 1;
+ nC2 = Min((SCCOL)(nC1 + nXw), nCol2);
+ } while (nC1 <= nCol2);
+ nC1 = nCol1;
+ nC2 = nC1 + nXw;
+ if (nC2 > nCol2)
+ nC2 = nCol2;
+ nR1 = nR2 + 1;
+ nR2 = Min((SCROW)(nR1 + nYw), nRow2);
+ } while (nR1 <= nRow2);
+ }
+}
+
+ScClipParam& ScDocument::GetClipParam()
+{
+ if (!mpClipParam.get())
+ mpClipParam.reset(new ScClipParam);
+
+ return *mpClipParam;
+}
+
+void ScDocument::SetClipParam(const ScClipParam& rParam)
+{
+ mpClipParam.reset(new ScClipParam(rParam));
+}
+
+BOOL ScDocument::IsClipboardSource() const
+{
+ ScDocument* pClipDoc = SC_MOD()->GetClipDoc();
+ return pClipDoc && pClipDoc->xPoolHelper.isValid() &&
+ xPoolHelper->GetDocPool() == pClipDoc->xPoolHelper->GetDocPool();
+}
+
+
+void ScDocument::StartListeningFromClip( SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2,
+ const ScMarkData& rMark, USHORT nInsFlag )
+{
+ if (nInsFlag & IDF_CONTENTS)
+ {
+ for (SCTAB i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ if (rMark.GetTableSelect(i))
+ pTab[i]->StartListeningInArea( nCol1, nRow1, nCol2, nRow2 );
+ }
+}
+
+
+void ScDocument::BroadcastFromClip( SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2,
+ const ScMarkData& rMark, USHORT nInsFlag )
+{
+ if (nInsFlag & IDF_CONTENTS)
+ {
+ ScBulkBroadcast aBulkBroadcast( GetBASM());
+ for (SCTAB i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ if (rMark.GetTableSelect(i))
+ pTab[i]->BroadcastInArea( nCol1, nRow1, nCol2, nRow2 );
+ }
+}
+
+
+void ScDocument::CopyBlockFromClip( SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2,
+ const ScMarkData& rMark,
+ SCsCOL nDx, SCsROW nDy,
+ const ScCopyBlockFromClipParams* pCBFCP )
+{
+ ScTable** ppClipTab = pCBFCP->pClipDoc->pTab;
+ SCTAB nTabEnd = pCBFCP->nTabEnd;
+ SCTAB nClipTab = 0;
+ for (SCTAB i = pCBFCP->nTabStart; i <= nTabEnd; i++)
+ {
+ if (pTab[i] && rMark.GetTableSelect(i) )
+ {
+ while (!ppClipTab[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
+
+ pTab[i]->CopyFromClip( nCol1, nRow1, nCol2, nRow2, nDx, nDy,
+ pCBFCP->nInsFlag, pCBFCP->bAsLink, pCBFCP->bSkipAttrForEmpty, ppClipTab[nClipTab] );
+
+ if ( pCBFCP->pClipDoc->pDrawLayer && ( pCBFCP->nInsFlag & IDF_OBJECTS ) )
+ {
+ // also copy drawing objects
+
+ // drawing layer must be created before calling CopyFromClip
+ // (ScDocShell::MakeDrawLayer also does InitItems etc.)
+ DBG_ASSERT( pDrawLayer, "CopyBlockFromClip: No drawing layer" );
+ if ( pDrawLayer )
+ {
+ // For GetMMRect, the row heights in the target document must already be valid
+ // (copied in an extra step before pasting, or updated after pasting cells, but
+ // before pasting objects).
+
+ Rectangle aSourceRect = pCBFCP->pClipDoc->GetMMRect(
+ nCol1-nDx, nRow1-nDy, nCol2-nDx, nRow2-nDy, nClipTab );
+ Rectangle aDestRect = GetMMRect( nCol1, nRow1, nCol2, nRow2, i );
+ pDrawLayer->CopyFromClip( pCBFCP->pClipDoc->pDrawLayer, nClipTab, aSourceRect,
+ ScAddress( nCol1, nRow1, i ), aDestRect );
+ }
+ }
+
+ nClipTab = (nClipTab+1) % (MAXTAB+1);
+ }
+ }
+ if ( pCBFCP->nInsFlag & IDF_CONTENTS )
+ {
+ nClipTab = 0;
+ for (SCTAB i = pCBFCP->nTabStart; i <= nTabEnd; i++)
+ {
+ if (pTab[i] && rMark.GetTableSelect(i) )
+ {
+ while (!ppClipTab[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
+ SCsTAB nDz = ((SCsTAB)i) - nClipTab;
+
+ // #89081# ranges of consecutive selected tables (in clipboard and dest. doc)
+ // must be handled in one UpdateReference call
+ SCTAB nFollow = 0;
+ while ( i + nFollow < nTabEnd
+ && rMark.GetTableSelect( i + nFollow + 1 )
+ && nClipTab + nFollow < MAXTAB
+ && ppClipTab[nClipTab + nFollow + 1] )
+ ++nFollow;
+
+ if ( pCBFCP->pClipDoc->GetClipParam().mbCutMode )
+ {
+ BOOL bOldInserting = IsInsertingFromOtherDoc();
+ SetInsertingFromOtherDoc( TRUE);
+ UpdateReference( URM_MOVE,
+ nCol1, nRow1, i, nCol2, nRow2, i+nFollow,
+ nDx, nDy, nDz, pCBFCP->pRefUndoDoc );
+ SetInsertingFromOtherDoc( bOldInserting);
+ }
+ else
+ UpdateReference( URM_COPY,
+ nCol1, nRow1, i, nCol2, nRow2, i+nFollow,
+ nDx, nDy, nDz, pCBFCP->pRefUndoDoc, FALSE );
+
+ nClipTab = (nClipTab+nFollow+1) % (MAXTAB+1);
+ i = sal::static_int_cast<SCTAB>( i + nFollow );
+ }
+ }
+ }
+}
+
+
+void ScDocument::CopyNonFilteredFromClip( SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2,
+ const ScMarkData& rMark,
+ SCsCOL nDx, SCsROW /* nDy */,
+ const ScCopyBlockFromClipParams* pCBFCP,
+ SCROW & rClipStartRow )
+{
+ // call CopyBlockFromClip for ranges of consecutive non-filtered rows
+ // nCol1/nRow1 etc. is in target doc
+
+ // filtered state is taken from first used table in clipboard (as in GetClipArea)
+ SCTAB nFlagTab = 0;
+ ScTable** ppClipTab = pCBFCP->pClipDoc->pTab;
+ while ( nFlagTab < MAXTAB && !ppClipTab[nFlagTab] )
+ ++nFlagTab;
+
+ SCROW nSourceRow = rClipStartRow;
+ SCROW nSourceEnd = 0;
+ if (pCBFCP->pClipDoc->GetClipParam().maRanges.Count())
+ nSourceEnd = pCBFCP->pClipDoc->GetClipParam().maRanges.First()->aEnd.Row();
+ SCROW nDestRow = nRow1;
+
+ while ( nSourceRow <= nSourceEnd && nDestRow <= nRow2 )
+ {
+ // skip filtered rows
+ nSourceRow = pCBFCP->pClipDoc->FirstNonFilteredRow(nSourceRow, nSourceEnd, nFlagTab);
+
+ if ( nSourceRow <= nSourceEnd )
+ {
+ // look for more non-filtered rows following
+ SCROW nLastRow = nSourceRow;
+ pCBFCP->pClipDoc->RowFiltered(nSourceRow, nFlagTab, NULL, &nLastRow);
+ SCROW nFollow = nLastRow - nSourceRow;
+
+ if (nFollow > nSourceEnd - nSourceRow)
+ nFollow = nSourceEnd - nSourceRow;
+ if (nFollow > nRow2 - nDestRow)
+ nFollow = nRow2 - nDestRow;
+
+ SCsROW nNewDy = ((SCsROW)nDestRow) - nSourceRow;
+ CopyBlockFromClip( nCol1, nDestRow, nCol2, nDestRow + nFollow, rMark, nDx, nNewDy, pCBFCP );
+
+ nSourceRow += nFollow + 1;
+ nDestRow += nFollow + 1;
+ }
+ }
+ rClipStartRow = nSourceRow;
+}
+
+
+void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMark,
+ USHORT nInsFlag,
+ ScDocument* pRefUndoDoc, ScDocument* pClipDoc, BOOL bResetCut,
+ BOOL bAsLink, BOOL bIncludeFiltered, BOOL bSkipAttrForEmpty,
+ const ScRangeList * pDestRanges )
+{
+ if (!bIsClip)
+ {
+ if (!pClipDoc)
+ {
+ DBG_ERROR("CopyFromClip: no ClipDoc");
+ pClipDoc = SC_MOD()->GetClipDoc();
+ }
+ if (pClipDoc->bIsClip && pClipDoc->GetTableCount())
+ {
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // avoid multiple recalculations
+
+ NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
+
+ ScClipRangeNameData aClipRangeNames;
+ CopyRangeNamesFromClip(pClipDoc, aClipRangeNames);
+
+ SCCOL nAllCol1 = rDestRange.aStart.Col();
+ SCROW nAllRow1 = rDestRange.aStart.Row();
+ SCCOL nAllCol2 = rDestRange.aEnd.Col();
+ SCROW nAllRow2 = rDestRange.aEnd.Row();
+
+ SCCOL nXw = 0;
+ SCROW nYw = 0;
+ ScRange aClipRange = pClipDoc->GetClipParam().getWholeRange();
+ for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++) // find largest merge overlap
+ if (pClipDoc->pTab[nTab]) // all sheets of the clipboard content
+ {
+ SCCOL nThisEndX = aClipRange.aEnd.Col();
+ SCROW nThisEndY = aClipRange.aEnd.Row();
+ pClipDoc->ExtendMerge( aClipRange.aStart.Col(),
+ aClipRange.aStart.Row(),
+ nThisEndX, nThisEndY, nTab );
+ // only extra value from ExtendMerge
+ nThisEndX = sal::static_int_cast<SCCOL>( nThisEndX - aClipRange.aEnd.Col() );
+ nThisEndY = sal::static_int_cast<SCROW>( nThisEndY - aClipRange.aEnd.Row() );
+ if ( nThisEndX > nXw )
+ nXw = nThisEndX;
+ if ( nThisEndY > nYw )
+ nYw = nThisEndY;
+ }
+
+ SCCOL nDestAddX;
+ SCROW nDestAddY;
+ pClipDoc->GetClipArea( nDestAddX, nDestAddY, bIncludeFiltered );
+ nXw = sal::static_int_cast<SCCOL>( nXw + nDestAddX );
+ nYw = sal::static_int_cast<SCROW>( nYw + nDestAddY ); // ClipArea, plus ExtendMerge value
+
+ /* Decide which contents to delete before copying. Delete all
+ contents if nInsFlag contains any real content flag.
+ #i102056# Notes are pasted from clipboard in a second pass,
+ together with the special flag IDF_ADDNOTES that states to not
+ overwrite/delete existing cells but to insert the notes into
+ these cells. In this case, just delete old notes from the
+ destination area. */
+ USHORT nDelFlag = IDF_NONE;
+ if ( (nInsFlag & (IDF_CONTENTS | IDF_ADDNOTES)) == (IDF_NOTE | IDF_ADDNOTES) )
+ nDelFlag |= IDF_NOTE;
+ else if ( nInsFlag & IDF_CONTENTS )
+ nDelFlag |= IDF_CONTENTS;
+ // With bSkipAttrForEmpty, don't remove attributes, copy
+ // on top of existing attributes instead.
+ if ( ( nInsFlag & IDF_ATTRIB ) && !bSkipAttrForEmpty )
+ nDelFlag |= IDF_ATTRIB;
+
+ ScCopyBlockFromClipParams aCBFCP;
+ aCBFCP.pRefUndoDoc = pRefUndoDoc;
+ aCBFCP.pClipDoc = pClipDoc;
+ aCBFCP.nInsFlag = nInsFlag;
+ aCBFCP.bAsLink = bAsLink;
+ aCBFCP.bSkipAttrForEmpty = bSkipAttrForEmpty;
+ aCBFCP.nTabStart = MAXTAB; // wird in der Schleife angepasst
+ aCBFCP.nTabEnd = 0; // wird in der Schleife angepasst
+
+ // Inc/DecRecalcLevel einmal aussen, damit nicht fuer jeden Block
+ // die Draw-Seitengroesse neu berechnet werden muss
+ //! nur wenn ganze Zeilen/Spalten kopiert werden?
+
+ for (SCTAB j = 0; j <= MAXTAB; j++)
+ if (pTab[j] && rMark.GetTableSelect(j))
+ {
+ if ( j < aCBFCP.nTabStart )
+ aCBFCP.nTabStart = j;
+ aCBFCP.nTabEnd = j;
+ pTab[j]->IncRecalcLevel();
+ }
+
+ ScRangeList aLocalRangeList;
+ if (!pDestRanges)
+ {
+ aLocalRangeList.Append( rDestRange);
+ pDestRanges = &aLocalRangeList;
+ }
+
+ bInsertingFromOtherDoc = TRUE; // kein Broadcast/Listener aufbauen bei Insert
+
+ // bei mindestens 64 Zeilen wird in ScColumn::CopyFromClip voralloziert
+ BOOL bDoDouble = ( nYw < 64 && nAllRow2 - nAllRow1 > 64);
+ BOOL bOldDouble = ScColumn::bDoubleAlloc;
+ if (bDoDouble)
+ ScColumn::bDoubleAlloc = TRUE;
+
+ SCCOL nClipStartCol = aClipRange.aStart.Col();
+ SCROW nClipStartRow = aClipRange.aStart.Row();
+ // WaE: commented because unused: SCCOL nClipEndCol = pClipDoc->aClipRange.aEnd.Col();
+ SCROW nClipEndRow = aClipRange.aEnd.Row();
+ for (ULONG nRange = 0; nRange < pDestRanges->Count(); ++nRange)
+ {
+ const ScRange* pRange = pDestRanges->GetObject( nRange);
+ SCCOL nCol1 = pRange->aStart.Col();
+ SCROW nRow1 = pRange->aStart.Row();
+ SCCOL nCol2 = pRange->aEnd.Col();
+ SCROW nRow2 = pRange->aEnd.Row();
+
+ DeleteArea(nCol1, nRow1, nCol2, nRow2, rMark, nDelFlag);
+
+ SCCOL nC1 = nCol1;
+ SCROW nR1 = nRow1;
+ SCCOL nC2 = nC1 + nXw;
+ if (nC2 > nCol2)
+ nC2 = nCol2;
+ SCROW nR2 = nR1 + nYw;
+ if (nR2 > nRow2)
+ nR2 = nRow2;
+
+ do
+ {
+ // Pasting is done column-wise, when pasting to a filtered
+ // area this results in partitioning and we have to
+ // remember and reset the start row for each column until
+ // it can be advanced for the next chunk of unfiltered
+ // rows.
+ SCROW nSaveClipStartRow = nClipStartRow;
+ do
+ {
+ nClipStartRow = nSaveClipStartRow;
+ SCsCOL nDx = ((SCsCOL)nC1) - nClipStartCol;
+ SCsROW nDy = ((SCsROW)nR1) - nClipStartRow;
+ if ( bIncludeFiltered )
+ {
+ CopyBlockFromClip( nC1, nR1, nC2, nR2, rMark, nDx,
+ nDy, &aCBFCP );
+ nClipStartRow += nR2 - nR1 + 1;
+ }
+ else
+ {
+ CopyNonFilteredFromClip( nC1, nR1, nC2, nR2, rMark,
+ nDx, nDy, &aCBFCP, nClipStartRow );
+ }
+ // Not needed for columns, but if it was this would be how to.
+ //if (nClipStartCol > nClipEndCol)
+ // nClipStartCol = pClipDoc->aClipRange.aStart.Col();
+ nC1 = nC2 + 1;
+ nC2 = Min((SCCOL)(nC1 + nXw), nCol2);
+ } while (nC1 <= nCol2);
+ if (nClipStartRow > nClipEndRow)
+ nClipStartRow = aClipRange.aStart.Row();
+ nC1 = nCol1;
+ nC2 = nC1 + nXw;
+ if (nC2 > nCol2)
+ nC2 = nCol2;
+ nR1 = nR2 + 1;
+ nR2 = Min((SCROW)(nR1 + nYw), nRow2);
+ } while (nR1 <= nRow2);
+ }
+
+ ScColumn::bDoubleAlloc = bOldDouble;
+
+ for (SCTAB k = 0; k <= MAXTAB; k++)
+ if (pTab[k] && rMark.GetTableSelect(k))
+ pTab[k]->DecRecalcLevel();
+
+ bInsertingFromOtherDoc = FALSE;
+
+ UpdateRangeNamesInFormulas(aClipRangeNames, *pDestRanges, rMark, nXw, nYw);
+
+ // Listener aufbauen nachdem alles inserted wurde
+ StartListeningFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
+ // nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
+ BroadcastFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
+ if (bResetCut)
+ pClipDoc->GetClipParam().mbCutMode = false;
+ SetAutoCalc( bOldAutoCalc );
+ }
+ }
+}
+
+static SCROW lcl_getLastNonFilteredRow(
+ const ScBitMaskCompressedArray<SCROW, BYTE>& rFlags, SCROW nBegRow, SCROW nEndRow,
+ SCROW nRowCount)
+{
+ SCROW nFilteredRow = rFlags.GetFirstForCondition(
+ nBegRow, nEndRow, CR_FILTERED, CR_FILTERED);
+
+ SCROW nRow = nFilteredRow - 1;
+ if (nRow - nBegRow + 1 > nRowCount)
+ // make sure the row range stays within the data size.
+ nRow = nBegRow + nRowCount - 1;
+
+ return nRow;
+}
+
+void ScDocument::CopyMultiRangeFromClip(
+ const ScAddress& rDestPos, const ScMarkData& rMark, sal_uInt16 nInsFlag, ScDocument* pClipDoc,
+ bool bResetCut, bool bAsLink, bool /*bIncludeFiltered*/, bool bSkipAttrForEmpty)
+{
+ if (bIsClip)
+ return;
+
+ if (!pClipDoc->bIsClip || !pClipDoc->GetTableCount())
+ // There is nothing in the clip doc to copy.
+ return;
+
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // avoid multiple recalculations
+
+ NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
+
+ ScClipRangeNameData aClipRangeNames;
+ CopyRangeNamesFromClip(pClipDoc, aClipRangeNames);
+
+ SCCOL nCol1 = rDestPos.Col();
+ SCROW nRow1 = rDestPos.Row();
+ ScClipParam& rClipParam = pClipDoc->GetClipParam();
+
+ ScCopyBlockFromClipParams aCBFCP;
+ aCBFCP.pRefUndoDoc = NULL;
+ aCBFCP.pClipDoc = pClipDoc;
+ aCBFCP.nInsFlag = nInsFlag;
+ aCBFCP.bAsLink = bAsLink;
+ aCBFCP.bSkipAttrForEmpty = bSkipAttrForEmpty;
+ aCBFCP.nTabStart = MAXTAB;
+ aCBFCP.nTabEnd = 0;
+
+ for (SCTAB j = 0; j <= MAXTAB; ++j)
+ {
+ if (pTab[j] && rMark.GetTableSelect(j))
+ {
+ if ( j < aCBFCP.nTabStart )
+ aCBFCP.nTabStart = j;
+ aCBFCP.nTabEnd = j;
+ pTab[j]->IncRecalcLevel();
+ }
+ }
+
+ ScRange aDestRange;
+ rMark.GetMarkArea(aDestRange);
+ SCROW nLastMarkedRow = aDestRange.aEnd.Row();
+
+ bInsertingFromOtherDoc = TRUE; // kein Broadcast/Listener aufbauen bei Insert
+
+ SCROW nBegRow = nRow1;
+ sal_uInt16 nDelFlag = IDF_CONTENTS;
+ const ScBitMaskCompressedArray<SCROW, BYTE>& rFlags = GetRowFlagsArray(aCBFCP.nTabStart);
+
+ for (ScRange* p = rClipParam.maRanges.First(); p; p = rClipParam.maRanges.Next())
+ {
+ // The begin row must not be filtered.
+
+ SCROW nRowCount = p->aEnd.Row() - p->aStart.Row() + 1;
+
+ SCsCOL nDx = static_cast<SCsCOL>(nCol1 - p->aStart.Col());
+ SCsROW nDy = static_cast<SCsROW>(nBegRow - p->aStart.Row());
+ SCCOL nCol2 = nCol1 + p->aEnd.Col() - p->aStart.Col();
+
+ SCROW nEndRow = lcl_getLastNonFilteredRow(rFlags, nBegRow, nLastMarkedRow, nRowCount);
+
+ if (!bSkipAttrForEmpty)
+ DeleteArea(nCol1, nBegRow, nCol2, nEndRow, rMark, nDelFlag);
+
+ CopyBlockFromClip(nCol1, nBegRow, nCol2, nEndRow, rMark, nDx, nDy, &aCBFCP);
+ nRowCount -= nEndRow - nBegRow + 1;
+
+ while (nRowCount > 0)
+ {
+ // Get the first non-filtered row.
+ SCROW nNonFilteredRow = rFlags.GetFirstForCondition(nEndRow+1, nLastMarkedRow, CR_FILTERED, 0);
+ if (nNonFilteredRow > nLastMarkedRow)
+ return;
+
+ SCROW nRowsSkipped = nNonFilteredRow - nEndRow - 1;
+ nDy += nRowsSkipped;
+
+ nBegRow = nNonFilteredRow;
+ nEndRow = lcl_getLastNonFilteredRow(rFlags, nBegRow, nLastMarkedRow, nRowCount);
+
+ if (!bSkipAttrForEmpty)
+ DeleteArea(nCol1, nBegRow, nCol2, nEndRow, rMark, nDelFlag);
+
+ CopyBlockFromClip(nCol1, nBegRow, nCol2, nEndRow, rMark, nDx, nDy, &aCBFCP);
+ nRowCount -= nEndRow - nBegRow + 1;
+ }
+
+ if (rClipParam.meDirection == ScClipParam::Row)
+ // Begin row for the next range being pasted.
+ nBegRow = rFlags.GetFirstForCondition(nEndRow+1, nLastMarkedRow, CR_FILTERED, 0);
+ else
+ nBegRow = nRow1;
+
+ if (rClipParam.meDirection == ScClipParam::Column)
+ nCol1 += p->aEnd.Col() - p->aStart.Col() + 1;
+ }
+
+ for (SCTAB i = 0; i <= MAXTAB; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ pTab[i]->DecRecalcLevel();
+
+ bInsertingFromOtherDoc = FALSE;
+
+ ScRangeList aRanges;
+ aRanges.Append(aDestRange);
+ SCCOL nCols = aDestRange.aEnd.Col() - aDestRange.aStart.Col() + 1;
+ SCROW nRows = aDestRange.aEnd.Row() - aDestRange.aStart.Row() + 1;
+ UpdateRangeNamesInFormulas(aClipRangeNames, aRanges, rMark, nCols-1, nRows-1);
+
+ // Listener aufbauen nachdem alles inserted wurde
+ StartListeningFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
+ aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
+ // nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
+ BroadcastFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
+ aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
+
+ if (bResetCut)
+ pClipDoc->GetClipParam().mbCutMode = false;
+ SetAutoCalc( bOldAutoCalc );
+}
+
+void ScDocument::SetClipArea( const ScRange& rArea, BOOL bCut )
+{
+ if (bIsClip)
+ {
+ ScClipParam& rClipParam = GetClipParam();
+ rClipParam.maRanges.RemoveAll();
+ rClipParam.maRanges.Append(rArea);
+ rClipParam.mbCutMode = bCut;
+ }
+ else
+ {
+ DBG_ERROR("SetClipArea: kein Clip");
+ }
+}
+
+
+void ScDocument::GetClipArea(SCCOL& nClipX, SCROW& nClipY, BOOL bIncludeFiltered)
+{
+ if (!bIsClip)
+ {
+ DBG_ERROR("GetClipArea: kein Clip");
+ return;
+ }
+
+ ScRangeList& rClipRanges = GetClipParam().maRanges;
+ if (!rClipRanges.Count())
+ // No clip range. Bail out.
+ return;
+
+ ScRangePtr p = rClipRanges.First();
+ SCCOL nStartCol = p->aStart.Col();
+ SCCOL nEndCol = p->aEnd.Col();
+ SCROW nStartRow = p->aStart.Row();
+ SCROW nEndRow = p->aEnd.Row();
+ for (p = rClipRanges.Next(); p; p = rClipRanges.Next())
+ {
+ if (p->aStart.Col() < nStartCol)
+ nStartCol = p->aStart.Col();
+ if (p->aStart.Row() < nStartRow)
+ nStartRow = p->aStart.Row();
+ if (p->aEnd.Col() > nEndCol)
+ nEndCol = p->aEnd.Col();
+ if (p->aEnd.Row() < nEndRow)
+ nEndRow = p->aEnd.Row();
+ }
+
+ nClipX = nEndCol - nStartCol;
+
+ if ( bIncludeFiltered )
+ nClipY = nEndRow - nStartRow;
+ else
+ {
+ // count non-filtered rows
+ // count on first used table in clipboard
+ SCTAB nCountTab = 0;
+ while ( nCountTab < MAXTAB && !pTab[nCountTab] )
+ ++nCountTab;
+
+ SCROW nResult = CountNonFilteredRows(nStartRow, nEndRow, nCountTab);
+
+ if ( nResult > 0 )
+ nClipY = nResult - 1;
+ else
+ nClipY = 0; // always return at least 1 row
+ }
+}
+
+
+void ScDocument::GetClipStart(SCCOL& nClipX, SCROW& nClipY)
+{
+ if (bIsClip)
+ {
+ ScRangeList& rClipRanges = GetClipParam().maRanges;
+ if (rClipRanges.Count())
+ {
+ nClipX = rClipRanges.First()->aStart.Col();
+ nClipY = rClipRanges.First()->aStart.Row();
+ }
+ }
+ else
+ {
+ DBG_ERROR("GetClipStart: kein Clip");
+ }
+}
+
+
+BOOL ScDocument::HasClipFilteredRows()
+{
+ // count on first used table in clipboard
+ SCTAB nCountTab = 0;
+ while ( nCountTab < MAXTAB && !pTab[nCountTab] )
+ ++nCountTab;
+
+ ScRangeList& rClipRanges = GetClipParam().maRanges;
+ if (!rClipRanges.Count())
+ return false;
+
+ for (ScRange* p = rClipRanges.First(); p; p = rClipRanges.Next())
+ {
+ bool bAnswer = pTab[nCountTab]->HasFilteredRows(p->aStart.Row(), p->aEnd.Row());
+ if (bAnswer)
+ return true;
+ }
+ return false;
+}
+
+
+void ScDocument::MixDocument( const ScRange& rRange, USHORT nFunction, BOOL bSkipEmpty,
+ ScDocument* pSrcDoc )
+{
+ SCTAB nTab1 = rRange.aStart.Tab();
+ SCTAB nTab2 = rRange.aEnd.Tab();
+ for (SCTAB i = nTab1; i <= nTab2; i++)
+ if (pTab[i] && pSrcDoc->pTab[i])
+ pTab[i]->MixData( rRange.aStart.Col(), rRange.aStart.Row(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(),
+ nFunction, bSkipEmpty, pSrcDoc->pTab[i] );
+}
+
+
+void ScDocument::FillTab( const ScRange& rSrcArea, const ScMarkData& rMark,
+ USHORT nFlags, USHORT nFunction,
+ BOOL bSkipEmpty, BOOL bAsLink )
+{
+ USHORT nDelFlags = nFlags;
+ if (nDelFlags & IDF_CONTENTS)
+ nDelFlags |= IDF_CONTENTS; // immer alle Inhalte oder keine loeschen!
+
+ SCTAB nSrcTab = rSrcArea.aStart.Tab();
+
+ if (ValidTab(nSrcTab) && pTab[nSrcTab])
+ {
+ SCCOL nStartCol = rSrcArea.aStart.Col();
+ SCROW nStartRow = rSrcArea.aStart.Row();
+ SCCOL nEndCol = rSrcArea.aEnd.Col();
+ SCROW nEndRow = rSrcArea.aEnd.Row();
+ ScDocument* pMixDoc = NULL;
+ BOOL bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
+
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+
+ SCTAB nCount = GetTableCount();
+ for (SCTAB i=0; i<nCount; i++)
+ if ( i!=nSrcTab && pTab[i] && rMark.GetTableSelect(i) )
+ {
+ if (bDoMix)
+ {
+ if (!pMixDoc)
+ {
+ pMixDoc = new ScDocument( SCDOCMODE_UNDO );
+ pMixDoc->InitUndo( this, i, i );
+ }
+ else
+ pMixDoc->AddUndoTab( i, i );
+ pTab[i]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
+ IDF_CONTENTS, FALSE, pMixDoc->pTab[i] );
+ }
+ pTab[i]->DeleteArea( nStartCol,nStartRow, nEndCol,nEndRow, nDelFlags);
+ pTab[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
+ nFlags, FALSE, pTab[i], NULL, bAsLink );
+
+ if (bDoMix)
+ pTab[i]->MixData( nStartCol,nStartRow, nEndCol,nEndRow,
+ nFunction, bSkipEmpty, pMixDoc->pTab[i] );
+ }
+
+ delete pMixDoc;
+
+ SetAutoCalc( bOldAutoCalc );
+ }
+ else
+ {
+ DBG_ERROR("falsche Tabelle");
+ }
+}
+
+
+void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
+ USHORT nFlags, USHORT nFunction,
+ BOOL bSkipEmpty, BOOL bAsLink )
+{
+ USHORT nDelFlags = nFlags;
+ if (nDelFlags & IDF_CONTENTS)
+ nDelFlags |= IDF_CONTENTS; // immer alle Inhalte oder keine loeschen!
+
+ if (ValidTab(nSrcTab) && pTab[nSrcTab])
+ {
+ ScDocument* pMixDoc = NULL;
+ BOOL bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
+
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+
+ ScRange aArea;
+ rMark.GetMultiMarkArea( aArea );
+ SCCOL nStartCol = aArea.aStart.Col();
+ SCROW nStartRow = aArea.aStart.Row();
+ SCCOL nEndCol = aArea.aEnd.Col();
+ SCROW nEndRow = aArea.aEnd.Row();
+
+ SCTAB nCount = GetTableCount();
+ for (SCTAB i=0; i<nCount; i++)
+ if ( i!=nSrcTab && pTab[i] && rMark.GetTableSelect(i) )
+ {
+ if (bDoMix)
+ {
+ if (!pMixDoc)
+ {
+ pMixDoc = new ScDocument( SCDOCMODE_UNDO );
+ pMixDoc->InitUndo( this, i, i );
+ }
+ else
+ pMixDoc->AddUndoTab( i, i );
+ pTab[i]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
+ IDF_CONTENTS, TRUE, pMixDoc->pTab[i], &rMark );
+ }
+
+ pTab[i]->DeleteSelection( nDelFlags, rMark );
+ pTab[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
+ nFlags, TRUE, pTab[i], &rMark, bAsLink );
+
+ if (bDoMix)
+ pTab[i]->MixMarked( rMark, nFunction, bSkipEmpty, pMixDoc->pTab[i] );
+ }
+
+ delete pMixDoc;
+
+ SetAutoCalc( bOldAutoCalc );
+ }
+ else
+ {
+ DBG_ERROR("falsche Tabelle");
+ }
+}
+
+
+void ScDocument::PutCell( SCCOL nCol, SCROW nRow, SCTAB nTab, ScBaseCell* pCell, BOOL bForceTab )
+{
+ if (VALIDTAB(nTab))
+ {
+ if ( bForceTab && !pTab[nTab] )
+ {
+ BOOL bExtras = !bIsUndo; // Spaltenbreiten, Zeilenhoehen, Flags
+
+ pTab[nTab] = new ScTable(this, nTab,
+ String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("temp")),
+ bExtras, bExtras);
+ ++nMaxTableNumber;
+ }
+
+ if (pTab[nTab])
+ pTab[nTab]->PutCell( nCol, nRow, pCell );
+ }
+}
+
+
+void ScDocument::PutCell( const ScAddress& rPos, ScBaseCell* pCell, BOOL bForceTab )
+{
+ SCTAB nTab = rPos.Tab();
+ if ( bForceTab && !pTab[nTab] )
+ {
+ BOOL bExtras = !bIsUndo; // Spaltenbreiten, Zeilenhoehen, Flags
+
+ pTab[nTab] = new ScTable(this, nTab,
+ String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("temp")),
+ bExtras, bExtras);
+ ++nMaxTableNumber;
+ }
+
+ if (pTab[nTab])
+ pTab[nTab]->PutCell( rPos, pCell );
+}
+
+
+BOOL ScDocument::SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rString,
+ SvNumberFormatter* pFormatter, bool bDetectNumberFormat )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->SetString( nCol, nRow, nTab, rString, pFormatter, bDetectNumberFormat );
+ else
+ return FALSE;
+}
+
+
+void ScDocument::SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->SetValue( nCol, nRow, rVal );
+}
+
+
+void ScDocument::GetString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString )
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ pTab[nTab]->GetString( nCol, nRow, rString );
+ else
+ rString.Erase();
+}
+
+
+void ScDocument::GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString )
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ pTab[nTab]->GetInputString( nCol, nRow, rString );
+ else
+ rString.Erase();
+}
+
+
+void ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, double& rValue )
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ rValue = pTab[nTab]->GetValue( nCol, nRow );
+ else
+ rValue = 0.0;
+}
+
+
+double ScDocument::GetValue( const ScAddress& rPos )
+{
+ SCTAB nTab = rPos.Tab();
+ if ( pTab[nTab] )
+ return pTab[nTab]->GetValue( rPos );
+ return 0.0;
+}
+
+
+void ScDocument::GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ sal_uInt32& rFormat )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ {
+ rFormat = pTab[nTab]->GetNumberFormat( nCol, nRow );
+ return ;
+ }
+ rFormat = 0;
+}
+
+
+sal_uInt32 ScDocument::GetNumberFormat( const ScAddress& rPos ) const
+{
+ SCTAB nTab = rPos.Tab();
+ if ( pTab[nTab] )
+ return pTab[nTab]->GetNumberFormat( rPos );
+ return 0;
+}
+
+
+void ScDocument::GetNumberFormatInfo( short& nType, ULONG& nIndex,
+ const ScAddress& rPos, const ScBaseCell* pCell ) const
+{
+ SCTAB nTab = rPos.Tab();
+ if ( pTab[nTab] )
+ {
+ nIndex = pTab[nTab]->GetNumberFormat( rPos );
+ if ( (nIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && pCell &&
+ pCell->GetCellType() == CELLTYPE_FORMULA )
+ static_cast<const ScFormulaCell*>(pCell)->GetFormatInfo( nType, nIndex );
+ else
+ nType = GetFormatTable()->GetType( nIndex );
+ }
+ else
+ {
+ nType = NUMBERFORMAT_UNDEFINED;
+ nIndex = 0;
+ }
+}
+
+
+void ScDocument::GetFormula( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rFormula,
+ BOOL bAsciiExport ) const
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ pTab[nTab]->GetFormula( nCol, nRow, rFormula, bAsciiExport );
+ else
+ rFormula.Erase();
+}
+
+
+CellType ScDocument::GetCellType( const ScAddress& rPos ) const
+{
+ SCTAB nTab = rPos.Tab();
+ if ( pTab[nTab] )
+ return pTab[nTab]->GetCellType( rPos );
+ return CELLTYPE_NONE;
+}
+
+
+void ScDocument::GetCellType( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ CellType& rCellType ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ rCellType = pTab[nTab]->GetCellType( nCol, nRow );
+ else
+ rCellType = CELLTYPE_NONE;
+}
+
+
+void ScDocument::GetCell( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ ScBaseCell*& rpCell ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ rpCell = pTab[nTab]->GetCell( nCol, nRow );
+ else
+ {
+ DBG_ERROR("GetCell ohne Tabelle");
+ rpCell = NULL;
+ }
+}
+
+
+ScBaseCell* ScDocument::GetCell( const ScAddress& rPos ) const
+{
+ SCTAB nTab = rPos.Tab();
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetCell( rPos );
+
+ DBG_ERROR("GetCell ohne Tabelle");
+ return NULL;
+}
+
+
+BOOL ScDocument::HasStringData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ return pTab[nTab]->HasStringData( nCol, nRow );
+ else
+ return FALSE;
+}
+
+
+BOOL ScDocument::HasValueData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ return pTab[nTab]->HasValueData( nCol, nRow );
+ else
+ return FALSE;
+}
+
+
+BOOL ScDocument::HasStringCells( const ScRange& rRange ) const
+{
+ // TRUE, wenn String- oder Editzellen im Bereich
+
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+
+ for ( SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++ )
+ if ( pTab[nTab] && pTab[nTab]->HasStringCells( nStartCol, nStartRow, nEndCol, nEndRow ) )
+ return TRUE;
+
+ return FALSE;
+}
+
+
+BOOL ScDocument::HasSelectionData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ sal_uInt32 nValidation = static_cast< const SfxUInt32Item* >( GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA ) )->GetValue();
+ if( nValidation )
+ {
+ const ScValidationData* pData = GetValidationEntry( nValidation );
+ if( pData && pData->HasSelectionList() )
+ return TRUE;
+ }
+ return HasStringCells( ScRange( nCol, 0, nTab, nCol, MAXROW, nTab ) );
+}
+
+
+ScPostIt* ScDocument::GetNote( const ScAddress& rPos )
+{
+ ScTable* pTable = ValidTab( rPos.Tab() ) ? pTab[ rPos.Tab() ] : 0;
+ return pTable ? pTable->GetNote( rPos.Col(), rPos.Row() ) : 0;
+}
+
+
+void ScDocument::TakeNote( const ScAddress& rPos, ScPostIt*& rpNote )
+{
+ if( ValidTab( rPos.Tab() ) && pTab[ rPos.Tab() ] )
+ pTab[ rPos.Tab() ]->TakeNote( rPos.Col(), rPos.Row(), rpNote );
+ else
+ DELETEZ( rpNote );
+}
+
+
+ScPostIt* ScDocument::ReleaseNote( const ScAddress& rPos )
+{
+ ScTable* pTable = ValidTab( rPos.Tab() ) ? pTab[ rPos.Tab() ] : 0;
+ return pTable ? pTable->ReleaseNote( rPos.Col(), rPos.Row() ) : 0;
+}
+
+
+ScPostIt* ScDocument::GetOrCreateNote( const ScAddress& rPos )
+{
+ ScPostIt* pNote = GetNote( rPos );
+ if( !pNote )
+ {
+ pNote = new ScPostIt( *this, rPos, false );
+ TakeNote( rPos, pNote );
+ }
+ return pNote;
+}
+
+
+void ScDocument::DeleteNote( const ScAddress& rPos )
+{
+ if( ValidTab( rPos.Tab() ) && pTab[ rPos.Tab() ] )
+ pTab[ rPos.Tab() ]->DeleteNote( rPos.Col(), rPos.Row() );
+}
+
+
+void ScDocument::InitializeNoteCaptions( SCTAB nTab, bool bForced )
+{
+ if( ValidTab( nTab ) && pTab[ nTab ] )
+ pTab[ nTab ]->InitializeNoteCaptions( bForced );
+}
+
+void ScDocument::InitializeAllNoteCaptions( bool bForced )
+{
+ for( SCTAB nTab = 0; nTab < GetTableCount(); ++nTab )
+ InitializeNoteCaptions( nTab, bForced );
+}
+
+void ScDocument::SetDirty()
+{
+ BOOL bOldAutoCalc = GetAutoCalc();
+ bAutoCalc = FALSE; // keine Mehrfachberechnung
+ { // scope for bulk broadcast
+ ScBulkBroadcast aBulkBroadcast( GetBASM());
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i]) pTab[i]->SetDirty();
+ }
+
+ // Charts werden zwar auch ohne AutoCalc im Tracking auf Dirty gesetzt,
+ // wenn alle Formeln dirty sind, werden die Charts aber nicht mehr erwischt
+ // (#45205#) - darum alle Charts nochmal explizit
+ if (pChartListenerCollection)
+ pChartListenerCollection->SetDirty();
+
+ SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScDocument::SetDirty( const ScRange& rRange )
+{
+ BOOL bOldAutoCalc = GetAutoCalc();
+ bAutoCalc = FALSE; // keine Mehrfachberechnung
+ { // scope for bulk broadcast
+ ScBulkBroadcast aBulkBroadcast( GetBASM());
+ SCTAB nTab2 = rRange.aEnd.Tab();
+ for (SCTAB i=rRange.aStart.Tab(); i<=nTab2; i++)
+ if (pTab[i]) pTab[i]->SetDirty( rRange );
+ }
+ SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScDocument::SetTableOpDirty( const ScRange& rRange )
+{
+ BOOL bOldAutoCalc = GetAutoCalc();
+ bAutoCalc = FALSE; // no multiple recalculation
+ SCTAB nTab2 = rRange.aEnd.Tab();
+ for (SCTAB i=rRange.aStart.Tab(); i<=nTab2; i++)
+ if (pTab[i]) pTab[i]->SetTableOpDirty( rRange );
+ SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScDocument::InterpretDirtyCells( const ScRangeList& rRanges )
+{
+ ULONG nRangeCount = rRanges.Count();
+ for (ULONG nPos=0; nPos<nRangeCount; nPos++)
+ {
+ ScCellIterator aIter( this, *rRanges.GetObject(nPos) );
+ ScBaseCell* pCell = aIter.GetFirst();
+ while (pCell)
+ {
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ if ( static_cast<ScFormulaCell*>(pCell)->GetDirty() && GetAutoCalc() )
+ static_cast<ScFormulaCell*>(pCell)->Interpret();
+ }
+ pCell = aIter.GetNext();
+ }
+ }
+}
+
+
+void ScDocument::AddTableOpFormulaCell( ScFormulaCell* pCell )
+{
+ ScInterpreterTableOpParams* p = aTableOpList.Last();
+ if ( p && p->bCollectNotifications )
+ {
+ if ( p->bRefresh )
+ { // refresh pointers only
+ p->aNotifiedFormulaCells.push_back( pCell );
+ }
+ else
+ { // init both, address and pointer
+ p->aNotifiedFormulaCells.push_back( pCell );
+ p->aNotifiedFormulaPos.push_back( pCell->aPos );
+ }
+ }
+}
+
+
+void ScDocument::CalcAll()
+{
+ ClearLookupCaches(); // Ensure we don't deliver zombie data.
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( TRUE );
+ SCTAB i;
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i]) pTab[i]->SetDirtyVar();
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i]) pTab[i]->CalcAll();
+ ClearFormulaTree();
+ SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScDocument::CompileAll()
+{
+ if ( pCondFormList )
+ pCondFormList->CompileAll();
+
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i]) pTab[i]->CompileAll();
+ SetDirty();
+}
+
+
+void ScDocument::CompileXML()
+{
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE );
+ ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(
+ STR_PROGRESS_CALCULATING ), GetXMLImportedFormulaCount() );
+
+ // #b6355215# set AutoNameCache to speed up automatic name lookup
+ DBG_ASSERT( !pAutoNameCache, "AutoNameCache already set" );
+ pAutoNameCache = new ScAutoNameCache( this );
+
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i]) pTab[i]->CompileXML( aProgress );
+
+ DELETEZ( pAutoNameCache ); // valid only during CompileXML, where cell contents don't change
+
+ if ( pCondFormList )
+ pCondFormList->CompileXML();
+ if ( pValidationList )
+ pValidationList->CompileXML();
+
+ SetDirty();
+ SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScDocument::CalcAfterLoad()
+{
+ SCTAB i;
+
+ if (bIsClip) // Excel-Dateien werden aus dem Clipboard in ein Clip-Doc geladen
+ return; // dann wird erst beim Einfuegen in das richtige Doc berechnet
+
+ bCalcingAfterLoad = TRUE;
+ for ( i = 0; i <= MAXTAB; i++)
+ if (pTab[i]) pTab[i]->CalcAfterLoad();
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i]) pTab[i]->SetDirtyAfterLoad();
+ bCalcingAfterLoad = FALSE;
+
+ SetDetectiveDirty(FALSE); // noch keine wirklichen Aenderungen
+}
+
+
+USHORT ScDocument::GetErrCode( const ScAddress& rPos ) const
+{
+ SCTAB nTab = rPos.Tab();
+ if ( pTab[nTab] )
+ return pTab[nTab]->GetErrCode( rPos );
+ return 0;
+}
+
+
+void ScDocument::ResetChanged( const ScRange& rRange )
+{
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+ for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
+ if (pTab[nTab])
+ pTab[nTab]->ResetChanged( rRange );
+}
+
+//
+// Spaltenbreiten / Zeilenhoehen --------------------------------------
+//
+
+
+void ScDocument::SetColWidth( SCCOL nCol, SCTAB nTab, USHORT nNewWidth )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetColWidth( nCol, nNewWidth );
+}
+
+
+void ScDocument::SetRowHeight( SCROW nRow, SCTAB nTab, USHORT nNewHeight )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetRowHeight( nRow, nNewHeight );
+}
+
+
+void ScDocument::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, USHORT nNewHeight )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetRowHeightRange
+ ( nStartRow, nEndRow, nNewHeight, 1.0, 1.0 );
+}
+
+void ScDocument::SetRowHeightOnly( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, USHORT nNewHeight )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetRowHeightOnly( nStartRow, nEndRow, nNewHeight );
+}
+
+void ScDocument::SetManualHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, BOOL bManual )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetManualHeight( nStartRow, nEndRow, bManual );
+}
+
+
+USHORT ScDocument::GetColWidth( SCCOL nCol, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetColWidth( nCol );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+USHORT ScDocument::GetOriginalWidth( SCCOL nCol, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetOriginalWidth( nCol );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+USHORT ScDocument::GetCommonWidth( SCCOL nEndCol, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetCommonWidth( nEndCol );
+ DBG_ERROR("Wrong table number");
+ return 0;
+}
+
+
+USHORT ScDocument::GetOriginalHeight( SCROW nRow, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetOriginalHeight( nRow );
+ DBG_ERROR("Wrong table number");
+ return 0;
+}
+
+
+USHORT ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, bool bHiddenAsZero ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetRowHeight( nRow, NULL, NULL, bHiddenAsZero );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+ULONG ScDocument::GetRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
+{
+ if (nStartRow == nEndRow)
+ return GetRowHeight( nStartRow, nTab); // faster for a single row
+
+ // check bounds because this method replaces former for(i=start;i<=end;++i) loops
+ if (nStartRow > nEndRow)
+ return 0;
+
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetRowHeight( nStartRow, nEndRow);
+
+ DBG_ERROR("wrong sheet number");
+ return 0;
+}
+
+SCROW ScDocument::GetRowForHeight( SCTAB nTab, ULONG nHeight ) const
+{
+ return pTab[nTab]->GetRowForHeight(nHeight);
+}
+
+ULONG ScDocument::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow,
+ SCTAB nTab, double fScale ) const
+{
+ // faster for a single row
+ if (nStartRow == nEndRow)
+ return (ULONG) (GetRowHeight( nStartRow, nTab) * fScale);
+
+ // check bounds because this method replaces former for(i=start;i<=end;++i) loops
+ if (nStartRow > nEndRow)
+ return 0;
+
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetScaledRowHeight( nStartRow, nEndRow, fScale);
+
+ DBG_ERROR("wrong sheet number");
+ return 0;
+}
+
+SCROW ScDocument::GetHiddenRowCount( SCROW nRow, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetHiddenRowCount( nRow );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+ULONG ScDocument::GetColOffset( SCCOL nCol, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetColOffset( nCol );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+ULONG ScDocument::GetRowOffset( SCROW nRow, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetRowOffset( nRow );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+USHORT ScDocument::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ BOOL bFormula, const ScMarkData* pMarkData,
+ BOOL bSimpleTextImport )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetOptimalColWidth( nCol, pDev, nPPTX, nPPTY,
+ rZoomX, rZoomY, bFormula, pMarkData, bSimpleTextImport );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+long ScDocument::GetNeededSize( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ BOOL bWidth, BOOL bTotalSize )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetNeededSize
+ ( nCol, nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, bTotalSize );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+BOOL ScDocument::SetOptimalHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, USHORT nExtra,
+ OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ BOOL bShrink )
+{
+//! MarkToMulti();
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->SetOptimalHeight( nStartRow, nEndRow, nExtra,
+ pDev, nPPTX, nPPTY, rZoomX, rZoomY, bShrink );
+ DBG_ERROR("Falsche Tabellennummer");
+ return FALSE;
+}
+
+
+void ScDocument::UpdateAllRowHeights( OutputDevice* pDev, double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY, const ScMarkData* pTabMark )
+{
+ // one progress across all (selected) sheets
+
+ ULONG nCellCount = 0;
+ for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
+ if ( pTab[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
+ nCellCount += pTab[nTab]->GetWeightedCount();
+
+ ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), nCellCount );
+
+ ULONG nProgressStart = 0;
+ for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
+ if ( pTab[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
+ {
+ pTab[nTab]->SetOptimalHeight( 0, MAXROW, 0,
+ pDev, nPPTX, nPPTY, rZoomX, rZoomY, FALSE, &aProgress, nProgressStart );
+ nProgressStart += pTab[nTab]->GetWeightedCount();
+ }
+}
+
+
+//
+// Spalten-/Zeilen-Flags ----------------------------------------------
+//
+
+void ScDocument::ShowCol(SCCOL nCol, SCTAB nTab, BOOL bShow)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->ShowCol( nCol, bShow );
+}
+
+
+void ScDocument::ShowRow(SCROW nRow, SCTAB nTab, BOOL bShow)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->ShowRow( nRow, bShow );
+}
+
+
+void ScDocument::ShowRows(SCROW nRow1, SCROW nRow2, SCTAB nTab, BOOL bShow)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->ShowRows( nRow1, nRow2, bShow );
+}
+
+
+void ScDocument::SetColFlags( SCCOL nCol, SCTAB nTab, BYTE nNewFlags )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetColFlags( nCol, nNewFlags );
+}
+
+
+void ScDocument::SetRowFlags( SCROW nRow, SCTAB nTab, BYTE nNewFlags )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetRowFlags( nRow, nNewFlags );
+}
+
+
+void ScDocument::SetRowFlags( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, BYTE nNewFlags )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetRowFlags( nStartRow, nEndRow, nNewFlags );
+}
+
+
+BYTE ScDocument::GetColFlags( SCCOL nCol, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetColFlags( nCol );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+BYTE ScDocument::GetRowFlags( SCROW nRow, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetRowFlags( nRow );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+ScBitMaskCompressedArray< SCROW, BYTE> & ScDocument::GetRowFlagsArrayModifiable(
+ SCTAB nTab )
+{
+ return const_cast< ScBitMaskCompressedArray< SCROW, BYTE> & >(
+ GetRowFlagsArray( nTab));
+}
+
+const ScBitMaskCompressedArray< SCROW, BYTE> & ScDocument::GetRowFlagsArray(
+ SCTAB nTab ) const
+{
+ const ScBitMaskCompressedArray< SCROW, BYTE> * pFlags;
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pFlags = pTab[nTab]->GetRowFlagsArray();
+ else
+ {
+ DBG_ERROR("wrong sheet number");
+ pFlags = 0;
+ }
+ if (!pFlags)
+ {
+ DBG_ERROR("no row flags at sheet");
+ static ScBitMaskCompressedArray< SCROW, BYTE> aDummy( MAXROW, 0);
+ pFlags = &aDummy;
+ }
+ return *pFlags;
+}
+
+void ScDocument::GetAllRowBreaks(set<SCROW>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return;
+
+ pTab[nTab]->GetAllRowBreaks(rBreaks, bPage, bManual);
+}
+
+void ScDocument::GetAllColBreaks(set<SCCOL>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return;
+
+ pTab[nTab]->GetAllColBreaks(rBreaks, bPage, bManual);
+}
+
+ScBreakType ScDocument::HasRowBreak(SCROW nRow, SCTAB nTab) const
+{
+ ScBreakType nType = BREAK_NONE;
+ if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
+ return nType;
+
+ if (pTab[nTab]->HasRowPageBreak(nRow))
+ nType |= BREAK_PAGE;
+
+ if (pTab[nTab]->HasRowManualBreak(nRow))
+ nType |= BREAK_MANUAL;
+
+ return nType;
+}
+
+ScBreakType ScDocument::HasColBreak(SCCOL nCol, SCTAB nTab) const
+{
+ ScBreakType nType = BREAK_NONE;
+ if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
+ return nType;
+
+ if (pTab[nTab]->HasColPageBreak(nCol))
+ nType |= BREAK_PAGE;
+
+ if (pTab[nTab]->HasColManualBreak(nCol))
+ nType |= BREAK_MANUAL;
+
+ return nType;
+}
+
+void ScDocument::SetRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
+{
+ if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
+ return;
+
+ pTab[nTab]->SetRowBreak(nRow, bPage, bManual);
+}
+
+void ScDocument::SetColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
+{
+ if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
+ return;
+
+ pTab[nTab]->SetColBreak(nCol, bPage, bManual);
+}
+
+void ScDocument::RemoveRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
+{
+ if (!ValidTab(nTab) || !pTab[nTab] || !ValidRow(nRow))
+ return;
+
+ pTab[nTab]->RemoveRowBreak(nRow, bPage, bManual);
+}
+
+void ScDocument::RemoveColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
+{
+ if (!ValidTab(nTab) || !pTab[nTab] || !ValidCol(nCol))
+ return;
+
+ pTab[nTab]->RemoveColBreak(nCol, bPage, bManual);
+}
+
+Sequence<TablePageBreakData> ScDocument::GetRowBreakData(SCTAB nTab) const
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return Sequence<TablePageBreakData>();
+
+ return pTab[nTab]->GetRowBreakData();
+}
+
+bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return false;
+
+ return pTab[nTab]->RowHidden(nRow, pFirstRow, pLastRow);
+}
+
+bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW& rLastRow)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ {
+ rLastRow = nRow;
+ return false;
+ }
+
+ return pTab[nTab]->RowHidden(nRow, rLastRow);
+}
+
+
+bool ScDocument::HasHiddenRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return false;
+
+ return pTab[nTab]->HasHiddenRows(nStartRow, nEndRow);
+}
+
+bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL& rLastCol)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ {
+ rLastCol = nCol;
+ return false;
+ }
+
+ return pTab[nTab]->ColHidden(nCol, rLastCol);
+}
+
+bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ {
+ if (pFirstCol)
+ *pFirstCol = nCol;
+ if (pLastCol)
+ *pLastCol = nCol;
+ return false;
+ }
+
+ return pTab[nTab]->ColHidden(nCol, pFirstCol, pLastCol);
+}
+
+void ScDocument::SetRowHidden(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHidden)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return;
+
+ pTab[nTab]->SetRowHidden(nStartRow, nEndRow, bHidden);
+}
+
+void ScDocument::SetColHidden(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bHidden)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return;
+
+ pTab[nTab]->SetColHidden(nStartCol, nEndCol, bHidden);
+}
+
+SCROW ScDocument::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return ::std::numeric_limits<SCROW>::max();;
+
+ return pTab[nTab]->FirstVisibleRow(nStartRow, nEndRow);
+}
+
+SCROW ScDocument::LastVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return ::std::numeric_limits<SCROW>::max();;
+
+ return pTab[nTab]->LastVisibleRow(nStartRow, nEndRow);
+}
+
+SCROW ScDocument::CountVisibleRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return 0;
+
+ return pTab[nTab]->CountVisibleRows(nStartRow, nEndRow);
+}
+
+bool ScDocument::RowFiltered(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return false;
+
+ return pTab[nTab]->RowFiltered(nRow, pFirstRow, pLastRow);
+}
+
+bool ScDocument::HasFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return false;
+
+ return pTab[nTab]->HasFilteredRows(nStartRow, nEndRow);
+}
+
+bool ScDocument::ColFiltered(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return false;
+
+ return pTab[nTab]->ColFiltered(nCol, pFirstCol, pLastCol);
+}
+
+void ScDocument::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bFiltered)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return;
+
+ pTab[nTab]->SetRowFiltered(nStartRow, nEndRow, bFiltered);
+}
+
+void ScDocument::SetColFiltered(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bFiltered)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return;
+
+ pTab[nTab]->SetColFiltered(nStartCol, nEndCol, bFiltered);
+}
+
+SCROW ScDocument::FirstNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return ::std::numeric_limits<SCROW>::max();;
+
+ return pTab[nTab]->FirstNonFilteredRow(nStartRow, nEndRow);
+}
+
+SCROW ScDocument::LastNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return ::std::numeric_limits<SCROW>::max();;
+
+ return pTab[nTab]->LastNonFilteredRow(nStartRow, nEndRow);
+}
+
+SCROW ScDocument::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return 0;
+
+ return pTab[nTab]->CountNonFilteredRows(nStartRow, nEndRow);
+}
+
+void ScDocument::SyncColRowFlags()
+{
+ for (SCTAB i = 0; i <= nMaxTableNumber; ++i)
+ {
+ if (!ValidTab(i) || !pTab[i])
+ continue;
+
+ pTab[i]->SyncColRowFlags();
+ }
+}
+
+SCROW ScDocument::GetLastFlaggedRow( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetLastFlaggedRow();
+ return 0;
+}
+
+
+SCCOL ScDocument::GetLastChangedCol( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetLastChangedCol();
+ return 0;
+}
+
+SCROW ScDocument::GetLastChangedRow( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetLastChangedRow();
+ return 0;
+}
+
+
+SCCOL ScDocument::GetNextDifferentChangedCol( SCTAB nTab, SCCOL nStart) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ {
+ BYTE nStartFlags = pTab[nTab]->GetColFlags(nStart);
+ USHORT nStartWidth = pTab[nTab]->GetOriginalWidth(nStart);
+ for (SCCOL nCol = nStart + 1; nCol <= MAXCOL; nCol++)
+ {
+ if (((nStartFlags & CR_MANUALBREAK) != (pTab[nTab]->GetColFlags(nCol) & CR_MANUALBREAK)) ||
+ (nStartWidth != pTab[nTab]->GetOriginalWidth(nCol)) ||
+ ((nStartFlags & CR_HIDDEN) != (pTab[nTab]->GetColFlags(nCol) & CR_HIDDEN)) )
+ return nCol;
+ }
+ return MAXCOL+1;
+ }
+ return 0;
+}
+
+SCROW ScDocument::GetNextDifferentChangedRow( SCTAB nTab, SCROW nStart, bool bCareManualSize) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] && pTab[nTab]->GetRowFlagsArray() && pTab[nTab]->mpRowHeights )
+ {
+ BYTE nStartFlags = pTab[nTab]->GetRowFlags(nStart);
+ USHORT nStartHeight = pTab[nTab]->GetOriginalHeight(nStart);
+ for (SCROW nRow = nStart + 1; nRow <= MAXROW; nRow++)
+ {
+ size_t nIndex; // ignored
+ SCROW nFlagsEndRow;
+ SCROW nHeightEndRow;
+ BYTE nFlags = pTab[nTab]->GetRowFlagsArray()->GetValue( nRow, nIndex, nFlagsEndRow );
+ USHORT nHeight = pTab[nTab]->GetRowHeight(nRow, NULL, &nHeightEndRow);
+ if (((nStartFlags & CR_MANUALBREAK) != (nFlags & CR_MANUALBREAK)) ||
+ ((nStartFlags & CR_MANUALSIZE) != (nFlags & CR_MANUALSIZE)) ||
+ (bCareManualSize && (nStartFlags & CR_MANUALSIZE) && (nStartHeight != nHeight)) ||
+ (!bCareManualSize && ((nStartHeight != nHeight))))
+ return nRow;
+
+ nRow = std::min( nFlagsEndRow, nHeightEndRow );
+ }
+ return MAXROW+1;
+ }
+ return 0;
+}
+
+BOOL ScDocument::GetColDefault( SCTAB nTab, SCCOL nCol, SCROW nLastRow, SCROW& nDefault)
+{
+ BOOL bRet(FALSE);
+ nDefault = 0;
+ ScDocAttrIterator aDocAttrItr(this, nTab, nCol, 0, nCol, nLastRow);
+ SCCOL nColumn;
+ SCROW nStartRow;
+ SCROW nEndRow;
+ const ScPatternAttr* pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
+ if (nEndRow < nLastRow)
+ {
+ ScDefaultAttrSet aSet;
+ ScDefaultAttrSet::iterator aItr = aSet.end();
+ while (pAttr)
+ {
+ ScDefaultAttr aAttr(pAttr);
+ aItr = aSet.find(aAttr);
+ if (aItr == aSet.end())
+ {
+ aAttr.nCount = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
+ aAttr.nFirst = nStartRow;
+ aSet.insert(aAttr);
+ }
+ else
+ {
+ aAttr.nCount = aItr->nCount + static_cast<SCSIZE>(nEndRow - nStartRow + 1);
+ aAttr.nFirst = aItr->nFirst;
+ aSet.erase(aItr);
+ aSet.insert(aAttr);
+ }
+ pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
+ }
+ ScDefaultAttrSet::iterator aDefaultItr = aSet.begin();
+ aItr = aDefaultItr;
+ aItr++;
+ while (aItr != aSet.end())
+ {
+ // for entries with equal count, use the one with the lowest start row,
+ // don't use the random order of pointer comparisons
+ if ( aItr->nCount > aDefaultItr->nCount ||
+ ( aItr->nCount == aDefaultItr->nCount && aItr->nFirst < aDefaultItr->nFirst ) )
+ aDefaultItr = aItr;
+ aItr++;
+ }
+ nDefault = aDefaultItr->nFirst;
+ bRet = TRUE;
+ }
+ else
+ bRet = TRUE;
+ return bRet;
+}
+
+BOOL ScDocument::GetRowDefault( SCTAB /* nTab */, SCROW /* nRow */, SCCOL /* nLastCol */, SCCOL& /* nDefault */ )
+{
+ BOOL bRet(FALSE);
+ return bRet;
+}
+
+void ScDocument::StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->StripHidden( rX1, rY1, rX2, rY2 );
+}
+
+
+void ScDocument::ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->ExtendHidden( rX1, rY1, rX2, rY2 );
+}
+
+//
+// Attribute ----------------------------------------------------------
+//
+
+const SfxPoolItem* ScDocument::GetAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, USHORT nWhich ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ {
+ const SfxPoolItem* pTemp = pTab[nTab]->GetAttr( nCol, nRow, nWhich );
+ if (pTemp)
+ return pTemp;
+ else
+ {
+ DBG_ERROR( "Attribut Null" );
+ }
+ }
+ return &xPoolHelper->GetDocPool()->GetDefaultItem( nWhich );
+}
+
+
+const ScPatternAttr* ScDocument::GetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetPattern( nCol, nRow );
+ return NULL;
+}
+
+
+const ScPatternAttr* ScDocument::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetMostUsedPattern( nCol, nStartRow, nEndRow );
+ return NULL;
+}
+
+
+void ScDocument::ApplyAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem& rAttr )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->ApplyAttr( nCol, nRow, rAttr );
+}
+
+
+void ScDocument::ApplyPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->ApplyPattern( nCol, nRow, rAttr );
+}
+
+
+void ScDocument::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow,
+ const ScMarkData& rMark,
+ const ScPatternAttr& rAttr )
+{
+ for (SCTAB i=0; i <= MAXTAB; i++)
+ if (pTab[i])
+ if (rMark.GetTableSelect(i))
+ pTab[i]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
+}
+
+
+void ScDocument::ApplyPatternAreaTab( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScPatternAttr& rAttr )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
+}
+
+void ScDocument::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
+ const ScMarkData& rMark, const ScPatternAttr& rPattern, short nNewType )
+{
+ for (SCTAB i=0; i <= MAXTAB; i++)
+ if (pTab[i])
+ if (rMark.GetTableSelect(i))
+ pTab[i]->ApplyPatternIfNumberformatIncompatible( rRange, rPattern, nNewType );
+}
+
+
+void ScDocument::ApplyStyle( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScStyleSheet& rStyle)
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->ApplyStyle( nCol, nRow, rStyle );
+}
+
+
+void ScDocument::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow,
+ const ScMarkData& rMark,
+ const ScStyleSheet& rStyle)
+{
+ for (SCTAB i=0; i <= MAXTAB; i++)
+ if (pTab[i])
+ if (rMark.GetTableSelect(i))
+ pTab[i]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
+}
+
+
+void ScDocument::ApplyStyleAreaTab( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScStyleSheet& rStyle)
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
+}
+
+
+void ScDocument::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
+{
+ // ApplySelectionStyle needs multi mark
+ if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
+ {
+ ScRange aRange;
+ rMark.GetMarkArea( aRange );
+ ApplyStyleArea( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rStyle );
+ }
+ else
+ {
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if ( pTab[i] && rMark.GetTableSelect(i) )
+ pTab[i]->ApplySelectionStyle( rStyle, rMark );
+ }
+}
+
+
+void ScDocument::ApplySelectionLineStyle( const ScMarkData& rMark,
+ const SvxBorderLine* pLine, BOOL bColorOnly )
+{
+ if ( bColorOnly && !pLine )
+ return;
+
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ if (rMark.GetTableSelect(i))
+ pTab[i]->ApplySelectionLineStyle( rMark, pLine, bColorOnly );
+}
+
+
+const ScStyleSheet* ScDocument::GetStyle( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetStyle(nCol, nRow);
+ else
+ return NULL;
+}
+
+
+const ScStyleSheet* ScDocument::GetSelectionStyle( const ScMarkData& rMark ) const
+{
+ BOOL bEqual = TRUE;
+ BOOL bFound;
+
+ const ScStyleSheet* pStyle = NULL;
+ const ScStyleSheet* pNewStyle;
+
+ if ( rMark.IsMultiMarked() )
+ for (SCTAB i=0; i<=MAXTAB && bEqual; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ {
+ pNewStyle = pTab[i]->GetSelectionStyle( rMark, bFound );
+ if (bFound)
+ {
+ if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
+ bEqual = FALSE; // unterschiedliche
+ pStyle = pNewStyle;
+ }
+ }
+ if ( rMark.IsMarked() )
+ {
+ ScRange aRange;
+ rMark.GetMarkArea( aRange );
+ for (SCTAB i=aRange.aStart.Tab(); i<=aRange.aEnd.Tab() && bEqual; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ {
+ pNewStyle = pTab[i]->GetAreaStyle( bFound,
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row() );
+ if (bFound)
+ {
+ if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
+ bEqual = FALSE; // unterschiedliche
+ pStyle = pNewStyle;
+ }
+ }
+ }
+
+ return bEqual ? pStyle : NULL;
+}
+
+
+void ScDocument::StyleSheetChanged( const SfxStyleSheetBase* pStyleSheet, BOOL bRemoved,
+ OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY )
+{
+ for (SCTAB i=0; i <= MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->StyleSheetChanged
+ ( pStyleSheet, bRemoved, pDev, nPPTX, nPPTY, rZoomX, rZoomY );
+
+ if ( pStyleSheet && pStyleSheet->GetName() == ScGlobal::GetRscString(STR_STYLENAME_STANDARD) )
+ {
+ // update attributes for all note objects
+ ScDetectiveFunc::UpdateAllComments( *this );
+ }
+}
+
+
+BOOL ScDocument::IsStyleSheetUsed( const ScStyleSheet& rStyle, BOOL bGatherAllStyles ) const
+{
+ if ( bStyleSheetUsageInvalid || rStyle.GetUsage() == ScStyleSheet::UNKNOWN )
+ {
+ if ( bGatherAllStyles )
+ {
+ SfxStyleSheetIterator aIter( xPoolHelper->GetStylePool(),
+ SFX_STYLE_FAMILY_PARA );
+ for ( const SfxStyleSheetBase* pStyle = aIter.First(); pStyle;
+ pStyle = aIter.Next() )
+ {
+ const ScStyleSheet* pScStyle = PTR_CAST( ScStyleSheet, pStyle );
+ if ( pScStyle )
+ pScStyle->SetUsage( ScStyleSheet::NOTUSED );
+ }
+ }
+
+ BOOL bIsUsed = FALSE;
+
+ for ( SCTAB i=0; i<=MAXTAB; i++ )
+ {
+ if ( pTab[i] )
+ {
+ if ( pTab[i]->IsStyleSheetUsed( rStyle, bGatherAllStyles ) )
+ {
+ if ( !bGatherAllStyles )
+ return TRUE;
+ bIsUsed = TRUE;
+ }
+ }
+ }
+
+ if ( bGatherAllStyles )
+ bStyleSheetUsageInvalid = FALSE;
+
+ return bIsUsed;
+ }
+
+ return rStyle.GetUsage() == ScStyleSheet::USED;
+}
+
+
+BOOL ScDocument::ApplyFlagsTab( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, INT16 nFlags )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->ApplyFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
+
+ DBG_ERROR("ApplyFlags: falsche Tabelle");
+ return FALSE;
+}
+
+
+BOOL ScDocument::RemoveFlagsTab( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, INT16 nFlags )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->RemoveFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
+
+ DBG_ERROR("RemoveFlags: falsche Tabelle");
+ return FALSE;
+}
+
+
+void ScDocument::SetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr,
+ BOOL bPutToPool )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->SetPattern( nCol, nRow, rAttr, bPutToPool );
+}
+
+
+void ScDocument::SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr,
+ BOOL bPutToPool )
+{
+ SCTAB nTab = rPos.Tab();
+ if (pTab[nTab])
+ pTab[nTab]->SetPattern( rPos, rAttr, bPutToPool );
+}
+
+
+ScPatternAttr* ScDocument::CreateSelectionPattern( const ScMarkData& rMark, BOOL bDeep )
+{
+ ScMergePatternState aState;
+
+ if ( rMark.IsMultiMarked() ) // multi selection
+ {
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ pTab[i]->MergeSelectionPattern( aState, rMark, bDeep );
+ }
+ if ( rMark.IsMarked() ) // simle selection
+ {
+ ScRange aRange;
+ rMark.GetMarkArea(aRange);
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ pTab[i]->MergePatternArea( aState,
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), bDeep );
+ }
+
+ DBG_ASSERT( aState.pItemSet, "SelectionPattern Null" );
+ if (aState.pItemSet)
+ return new ScPatternAttr( aState.pItemSet );
+ else
+ return new ScPatternAttr( GetPool() ); // empty
+}
+
+
+const ScPatternAttr* ScDocument::GetSelectionPattern( const ScMarkData& rMark, BOOL bDeep )
+{
+ delete pSelectionAttr;
+ pSelectionAttr = CreateSelectionPattern( rMark, bDeep );
+ return pSelectionAttr;
+}
+
+
+void ScDocument::GetSelectionFrame( const ScMarkData& rMark,
+ SvxBoxItem& rLineOuter,
+ SvxBoxInfoItem& rLineInner )
+{
+ rLineOuter.SetLine(NULL, BOX_LINE_TOP);
+ rLineOuter.SetLine(NULL, BOX_LINE_BOTTOM);
+ rLineOuter.SetLine(NULL, BOX_LINE_LEFT);
+ rLineOuter.SetLine(NULL, BOX_LINE_RIGHT);
+ rLineOuter.SetDistance(0);
+
+ rLineInner.SetLine(NULL, BOXINFO_LINE_HORI);
+ rLineInner.SetLine(NULL, BOXINFO_LINE_VERT);
+ rLineInner.SetTable(TRUE);
+ rLineInner.SetDist(TRUE);
+ rLineInner.SetMinDist(FALSE);
+
+ ScLineFlags aFlags;
+
+ if (rMark.IsMarked())
+ {
+ ScRange aRange;
+ rMark.GetMarkArea(aRange);
+ rLineInner.EnableHor( aRange.aStart.Row() != aRange.aEnd.Row() );
+ rLineInner.EnableVer( aRange.aStart.Col() != aRange.aEnd.Col() );
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ pTab[i]->MergeBlockFrame( &rLineOuter, &rLineInner, aFlags,
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row() );
+ }
+
+ // Don't care Status auswerten
+
+ rLineInner.SetValid( VALID_LEFT, ( aFlags.nLeft != SC_LINE_DONTCARE ) );
+ rLineInner.SetValid( VALID_RIGHT, ( aFlags.nRight != SC_LINE_DONTCARE ) );
+ rLineInner.SetValid( VALID_TOP, ( aFlags.nTop != SC_LINE_DONTCARE ) );
+ rLineInner.SetValid( VALID_BOTTOM, ( aFlags.nBottom != SC_LINE_DONTCARE ) );
+ rLineInner.SetValid( VALID_HORI, ( aFlags.nHori != SC_LINE_DONTCARE ) );
+ rLineInner.SetValid( VALID_VERT, ( aFlags.nVert != SC_LINE_DONTCARE ) );
+}
+
+
+bool ScDocument::HasAttrib( SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2, USHORT nMask )
+{
+ if ( nMask & HASATTR_ROTATE )
+ {
+ // Attribut im Dokument ueberhaupt verwendet?
+ // (wie in fillinfo)
+
+ ScDocumentPool* pPool = xPoolHelper->GetDocPool();
+
+ BOOL bAnyItem = FALSE;
+ USHORT nRotCount = pPool->GetItemCount( ATTR_ROTATE_VALUE );
+ for (USHORT nItem=0; nItem<nRotCount; nItem++)
+ {
+ const SfxPoolItem* pItem = pPool->GetItem( ATTR_ROTATE_VALUE, nItem );
+ if ( pItem )
+ {
+ // 90 or 270 degrees is former SvxOrientationItem - only look for other values
+ // (see ScPatternAttr::GetCellOrientation)
+ INT32 nAngle = static_cast<const SfxInt32Item*>(pItem)->GetValue();
+ if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
+ {
+ bAnyItem = TRUE;
+ break;
+ }
+ }
+ }
+ if (!bAnyItem)
+ nMask &= ~HASATTR_ROTATE;
+ }
+
+ if ( nMask & HASATTR_RTL )
+ {
+ // first check if right-to left is in the pool at all
+ // (the same item is used in cell and page format)
+
+ ScDocumentPool* pPool = xPoolHelper->GetDocPool();
+
+ BOOL bHasRtl = FALSE;
+ USHORT nDirCount = pPool->GetItemCount( ATTR_WRITINGDIR );
+ for (USHORT nItem=0; nItem<nDirCount; nItem++)
+ {
+ const SfxPoolItem* pItem = pPool->GetItem( ATTR_WRITINGDIR, nItem );
+ if ( pItem && ((const SvxFrameDirectionItem*)pItem)->GetValue() == FRMDIR_HORI_RIGHT_TOP )
+ {
+ bHasRtl = TRUE;
+ break;
+ }
+ }
+ if (!bHasRtl)
+ nMask &= ~HASATTR_RTL;
+ }
+
+ if (!nMask)
+ return false;
+
+ bool bFound = false;
+ for (SCTAB i=nTab1; i<=nTab2 && !bFound; i++)
+ if (pTab[i])
+ {
+ if ( nMask & HASATTR_RTL )
+ {
+ if ( GetEditTextDirection(i) == EE_HTEXTDIR_R2L ) // sheet default
+ bFound = true;
+ }
+ if ( nMask & HASATTR_RIGHTORCENTER )
+ {
+ // On a RTL sheet, don't start to look for the default left value
+ // (which is then logically right), instead always assume TRUE.
+ // That way, ScAttrArray::HasAttrib doesn't have to handle RTL sheets.
+
+ if ( IsLayoutRTL(i) )
+ bFound = true;
+ }
+
+ if ( !bFound )
+ bFound = pTab[i]->HasAttrib( nCol1, nRow1, nCol2, nRow2, nMask );
+ }
+
+ return bFound;
+}
+
+bool ScDocument::HasAttrib( const ScRange& rRange, USHORT nMask )
+{
+ return HasAttrib( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(),
+ nMask );
+}
+
+void ScDocument::FindMaxRotCol( SCTAB nTab, RowInfo* pRowInfo, SCSIZE nArrCount,
+ SCCOL nX1, SCCOL nX2 ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->FindMaxRotCol( pRowInfo, nArrCount, nX1, nX2 );
+ else
+ {
+ DBG_ERRORFILE("FindMaxRotCol: falsche Tabelle");
+ }
+}
+
+void ScDocument::GetBorderLines( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ const SvxBorderLine** ppLeft, const SvxBorderLine** ppTop,
+ const SvxBorderLine** ppRight, const SvxBorderLine** ppBottom ) const
+{
+ //! Seitengrenzen fuer Druck beruecksichtigen !!!!!
+
+ const SvxBoxItem* pThisAttr = (const SvxBoxItem*) GetEffItem( nCol, nRow, nTab, ATTR_BORDER );
+ DBG_ASSERT(pThisAttr,"wo ist das Attribut?");
+
+ const SvxBorderLine* pLeftLine = pThisAttr->GetLeft();
+ const SvxBorderLine* pTopLine = pThisAttr->GetTop();
+ const SvxBorderLine* pRightLine = pThisAttr->GetRight();
+ const SvxBorderLine* pBottomLine = pThisAttr->GetBottom();
+
+ if ( nCol > 0 )
+ {
+ const SvxBorderLine* pOther = ((const SvxBoxItem*)
+ GetEffItem( nCol-1, nRow, nTab, ATTR_BORDER ))->GetRight();
+ if ( ScHasPriority( pOther, pLeftLine ) )
+ pLeftLine = pOther;
+ }
+ if ( nRow > 0 )
+ {
+ const SvxBorderLine* pOther = ((const SvxBoxItem*)
+ GetEffItem( nCol, nRow-1, nTab, ATTR_BORDER ))->GetBottom();
+ if ( ScHasPriority( pOther, pTopLine ) )
+ pTopLine = pOther;
+ }
+ if ( nCol < MAXCOL )
+ {
+ const SvxBorderLine* pOther = ((const SvxBoxItem*)
+ GetEffItem( nCol+1, nRow, nTab, ATTR_BORDER ))->GetLeft();
+ if ( ScHasPriority( pOther, pRightLine ) )
+ pRightLine = pOther;
+ }
+ if ( nRow < MAXROW )
+ {
+ const SvxBorderLine* pOther = ((const SvxBoxItem*)
+ GetEffItem( nCol, nRow+1, nTab, ATTR_BORDER ))->GetTop();
+ if ( ScHasPriority( pOther, pBottomLine ) )
+ pBottomLine = pOther;
+ }
+
+ if (ppLeft)
+ *ppLeft = pLeftLine;
+ if (ppTop)
+ *ppTop = pTopLine;
+ if (ppRight)
+ *ppRight = pRightLine;
+ if (ppBottom)
+ *ppBottom = pBottomLine;
+}
+
+BOOL ScDocument::IsBlockEmpty( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, bool bIgnoreNotes ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->IsBlockEmpty( nStartCol, nStartRow, nEndCol, nEndRow, bIgnoreNotes );
+
+ DBG_ERROR("Falsche Tabellennummer");
+ return FALSE;
+}
+
+
+void ScDocument::LockTable(SCTAB nTab)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->LockTable();
+ else
+ {
+ DBG_ERROR("Falsche Tabellennummer");
+ }
+}
+
+
+void ScDocument::UnlockTable(SCTAB nTab)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->UnlockTable();
+ else
+ {
+ DBG_ERROR("Falsche Tabellennummer");
+ }
+}
+
+
+BOOL ScDocument::IsBlockEditable( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow,
+ BOOL* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
+{
+ // import into read-only document is possible
+ if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
+ {
+ if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = FALSE;
+ return FALSE;
+ }
+
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->IsBlockEditable( nStartCol, nStartRow, nEndCol,
+ nEndRow, pOnlyNotBecauseOfMatrix );
+
+ DBG_ERROR("Falsche Tabellennummer");
+ if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = FALSE;
+ return FALSE;
+}
+
+
+BOOL ScDocument::IsSelectionEditable( const ScMarkData& rMark,
+ BOOL* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
+{
+ // import into read-only document is possible
+ if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
+ {
+ if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = FALSE;
+ return FALSE;
+ }
+
+ ScRange aRange;
+ rMark.GetMarkArea(aRange);
+
+ BOOL bOk = TRUE;
+ BOOL bMatrix = ( pOnlyNotBecauseOfMatrix != NULL );
+ for ( SCTAB i=0; i<=MAXTAB && (bOk || bMatrix); i++ )
+ {
+ if ( pTab[i] && rMark.GetTableSelect(i) )
+ {
+ if (rMark.IsMarked())
+ {
+ if ( !pTab[i]->IsBlockEditable( aRange.aStart.Col(),
+ aRange.aStart.Row(), aRange.aEnd.Col(),
+ aRange.aEnd.Row(), pOnlyNotBecauseOfMatrix ) )
+ {
+ bOk = FALSE;
+ if ( pOnlyNotBecauseOfMatrix )
+ bMatrix = *pOnlyNotBecauseOfMatrix;
+ }
+ }
+ if (rMark.IsMultiMarked())
+ {
+ if ( !pTab[i]->IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix ) )
+ {
+ bOk = FALSE;
+ if ( pOnlyNotBecauseOfMatrix )
+ bMatrix = *pOnlyNotBecauseOfMatrix;
+ }
+ }
+ }
+ }
+
+ if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = ( !bOk && bMatrix );
+
+ return bOk;
+}
+
+
+BOOL ScDocument::HasSelectedBlockMatrixFragment( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow,
+ const ScMarkData& rMark ) const
+{
+ BOOL bOk = TRUE;
+ for (SCTAB i=0; i<=MAXTAB && bOk; i++)
+ if (pTab[i])
+ if (rMark.GetTableSelect(i))
+ if (pTab[i]->HasBlockMatrixFragment( nStartCol, nStartRow, nEndCol, nEndRow ))
+ bOk = FALSE;
+
+ return !bOk;
+}
+
+
+BOOL ScDocument::GetMatrixFormulaRange( const ScAddress& rCellPos, ScRange& rMatrix )
+{
+ // if rCell is part of a matrix formula, return its complete range
+
+ BOOL bRet = FALSE;
+ ScBaseCell* pCell = GetCell( rCellPos );
+ if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ ScAddress aOrigin = rCellPos;
+ if ( ((ScFormulaCell*)pCell)->GetMatrixOrigin( aOrigin ) )
+ {
+ if ( aOrigin != rCellPos )
+ pCell = GetCell( aOrigin );
+ if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ SCCOL nSizeX;
+ SCROW nSizeY;
+ ((ScFormulaCell*)pCell)->GetMatColsRows(nSizeX,nSizeY);
+ if ( !(nSizeX > 0 && nSizeY > 0) )
+ {
+ // GetMatrixEdge computes also dimensions of the matrix
+ // if not already done (may occur if document is loaded
+ // from old file format).
+ // Needs an "invalid" initialized address.
+ aOrigin.SetInvalid();
+ ((ScFormulaCell*)pCell)->GetMatrixEdge(aOrigin);
+ ((ScFormulaCell*)pCell)->GetMatColsRows(nSizeX,nSizeY);
+ }
+ if ( nSizeX > 0 && nSizeY > 0 )
+ {
+ ScAddress aEnd( aOrigin.Col() + nSizeX - 1,
+ aOrigin.Row() + nSizeY - 1,
+ aOrigin.Tab() );
+
+ rMatrix.aStart = aOrigin;
+ rMatrix.aEnd = aEnd;
+ bRet = TRUE;
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+
+BOOL ScDocument::ExtendOverlapped( SCCOL& rStartCol, SCROW& rStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
+{
+ BOOL bFound = FALSE;
+ if ( ValidColRow(rStartCol,rStartRow) && ValidColRow(nEndCol,nEndRow) && ValidTab(nTab) )
+ {
+ if (pTab[nTab])
+ {
+ SCCOL nCol;
+ SCCOL nOldCol = rStartCol;
+ SCROW nOldRow = rStartRow;
+ for (nCol=nOldCol; nCol<=nEndCol; nCol++)
+ while (((ScMergeFlagAttr*)GetAttr(nCol,rStartRow,nTab,ATTR_MERGE_FLAG))->
+ IsVerOverlapped())
+ --rStartRow;
+
+ //! weiterreichen ?
+
+ ScAttrArray* pAttrArray = pTab[nTab]->aCol[nOldCol].pAttrArray;
+ SCSIZE nIndex;
+ pAttrArray->Search( nOldRow, nIndex );
+ SCROW nAttrPos = nOldRow;
+ while (nAttrPos<=nEndRow)
+ {
+ DBG_ASSERT( nIndex < pAttrArray->nCount, "Falscher Index im AttrArray" );
+
+ if (((ScMergeFlagAttr&)pAttrArray->pData[nIndex].pPattern->
+ GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped())
+ {
+ SCROW nLoopEndRow = Min( nEndRow, pAttrArray->pData[nIndex].nRow );
+ for (SCROW nAttrRow = nAttrPos; nAttrRow <= nLoopEndRow; nAttrRow++)
+ {
+ SCCOL nTempCol = nOldCol;
+ do
+ --nTempCol;
+ while (((ScMergeFlagAttr*)GetAttr(nTempCol,nAttrRow,nTab,ATTR_MERGE_FLAG))
+ ->IsHorOverlapped());
+ if (nTempCol < rStartCol)
+ rStartCol = nTempCol;
+ }
+ }
+ nAttrPos = pAttrArray->pData[nIndex].nRow + 1;
+ ++nIndex;
+ }
+ }
+ }
+ else
+ {
+ DBG_ERROR("ExtendOverlapped: falscher Bereich");
+ }
+
+ return bFound;
+}
+
+
+BOOL ScDocument::ExtendMergeSel( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL& rEndCol, SCROW& rEndRow,
+ const ScMarkData& rMark, BOOL bRefresh, BOOL bAttrs )
+{
+ // use all selected sheets from rMark
+
+ BOOL bFound = FALSE;
+ SCCOL nOldEndCol = rEndCol;
+ SCROW nOldEndRow = rEndRow;
+
+ for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
+ if ( pTab[nTab] && rMark.GetTableSelect(nTab) )
+ {
+ SCCOL nThisEndCol = nOldEndCol;
+ SCROW nThisEndRow = nOldEndRow;
+ if ( ExtendMerge( nStartCol, nStartRow, nThisEndCol, nThisEndRow, nTab, bRefresh, bAttrs ) )
+ bFound = TRUE;
+ if ( nThisEndCol > rEndCol )
+ rEndCol = nThisEndCol;
+ if ( nThisEndRow > rEndRow )
+ rEndRow = nThisEndRow;
+ }
+
+ return bFound;
+}
+
+
+BOOL ScDocument::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL& rEndCol, SCROW& rEndRow,
+ SCTAB nTab, BOOL bRefresh, BOOL bAttrs )
+{
+ BOOL bFound = FALSE;
+ if ( ValidColRow(nStartCol,nStartRow) && ValidColRow(rEndCol,rEndRow) && ValidTab(nTab) )
+ {
+ if (pTab[nTab])
+ bFound = pTab[nTab]->ExtendMerge( nStartCol, nStartRow, rEndCol, rEndRow, bRefresh, bAttrs );
+
+ if (bRefresh)
+ RefreshAutoFilter( nStartCol, nStartRow, rEndCol, rEndRow, nTab );
+ }
+ else
+ {
+ DBG_ERROR("ExtendMerge: falscher Bereich");
+ }
+
+ return bFound;
+}
+
+
+BOOL ScDocument::ExtendMerge( ScRange& rRange, BOOL bRefresh, BOOL bAttrs )
+{
+ BOOL bFound = FALSE;
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+
+ PutInOrder( nStartTab, nEndTab );
+ for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++ )
+ {
+ SCCOL nExtendCol = rRange.aEnd.Col();
+ SCROW nExtendRow = rRange.aEnd.Row();
+ if (ExtendMerge( rRange.aStart.Col(), rRange.aStart.Row(),
+ nExtendCol, nExtendRow,
+ nTab, bRefresh, bAttrs ) )
+ {
+ bFound = TRUE;
+ if (nExtendCol > nEndCol) nEndCol = nExtendCol;
+ if (nExtendRow > nEndRow) nEndRow = nExtendRow;
+ }
+ }
+
+ rRange.aEnd.SetCol(nEndCol);
+ rRange.aEnd.SetRow(nEndRow);
+
+ return bFound;
+}
+
+BOOL ScDocument::ExtendTotalMerge( ScRange& rRange )
+{
+ // Bereich genau dann auf zusammengefasste Zellen erweitern, wenn
+ // dadurch keine neuen nicht-ueberdeckten Zellen getroffen werden
+
+ BOOL bRet = FALSE;
+ ScRange aExt = rRange;
+ if (ExtendMerge(aExt))
+ {
+ if ( aExt.aEnd.Row() > rRange.aEnd.Row() )
+ {
+ ScRange aTest = aExt;
+ aTest.aStart.SetRow( rRange.aEnd.Row() + 1 );
+ if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
+ aExt.aEnd.SetRow(rRange.aEnd.Row());
+ }
+ if ( aExt.aEnd.Col() > rRange.aEnd.Col() )
+ {
+ ScRange aTest = aExt;
+ aTest.aStart.SetCol( rRange.aEnd.Col() + 1 );
+ if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
+ aExt.aEnd.SetCol(rRange.aEnd.Col());
+ }
+
+ bRet = ( aExt.aEnd != rRange.aEnd );
+ rRange = aExt;
+ }
+ return bRet;
+}
+
+BOOL ScDocument::ExtendOverlapped( ScRange& rRange )
+{
+ BOOL bFound = FALSE;
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+
+ PutInOrder( nStartTab, nEndTab );
+ for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++ )
+ {
+ SCCOL nExtendCol = rRange.aStart.Col();
+ SCROW nExtendRow = rRange.aStart.Row();
+ ExtendOverlapped( nExtendCol, nExtendRow,
+ rRange.aEnd.Col(), rRange.aEnd.Row(), nTab );
+ if (nExtendCol < nStartCol)
+ {
+ nStartCol = nExtendCol;
+ bFound = TRUE;
+ }
+ if (nExtendRow < nStartRow)
+ {
+ nStartRow = nExtendRow;
+ bFound = TRUE;
+ }
+ }
+
+ rRange.aStart.SetCol(nStartCol);
+ rRange.aStart.SetRow(nStartRow);
+
+ return bFound;
+}
+
+BOOL ScDocument::RefreshAutoFilter( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
+{
+ USHORT nCount = pDBCollection->GetCount();
+ USHORT i;
+ ScDBData* pData;
+ SCTAB nDBTab;
+ SCCOL nDBStartCol;
+ SCROW nDBStartRow;
+ SCCOL nDBEndCol;
+ SCROW nDBEndRow;
+
+ // Autofilter loeschen
+
+ BOOL bChange = RemoveFlagsTab( nStartCol,nStartRow, nEndCol,nEndRow, nTab, SC_MF_AUTO );
+
+ // Autofilter setzen
+
+ for (i=0; i<nCount; i++)
+ {
+ pData = (*pDBCollection)[i];
+ if (pData->HasAutoFilter())
+ {
+ pData->GetArea( nDBTab, nDBStartCol,nDBStartRow, nDBEndCol,nDBEndRow );
+ if ( nDBTab==nTab && nDBStartRow<=nEndRow && nDBEndRow>=nStartRow &&
+ nDBStartCol<=nEndCol && nDBEndCol>=nStartCol )
+ {
+ if (ApplyFlagsTab( nDBStartCol,nDBStartRow, nDBEndCol,nDBStartRow,
+ nDBTab, SC_MF_AUTO ))
+ bChange = TRUE;
+ }
+ }
+ }
+ return bChange;
+}
+
+
+BOOL ScDocument::IsHorOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
+ GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
+ if (pAttr)
+ return pAttr->IsHorOverlapped();
+ else
+ {
+ DBG_ERROR("Overlapped: Attr==0");
+ return FALSE;
+ }
+}
+
+
+BOOL ScDocument::IsVerOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
+ GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
+ if (pAttr)
+ return pAttr->IsVerOverlapped();
+ else
+ {
+ DBG_ERROR("Overlapped: Attr==0");
+ return FALSE;
+ }
+}
+
+
+void ScDocument::ApplySelectionFrame( const ScMarkData& rMark,
+ const SvxBoxItem* pLineOuter,
+ const SvxBoxInfoItem* pLineInner )
+{
+ ScRangeList aRangeList;
+ rMark.FillRangeListWithMarks( &aRangeList, FALSE );
+ ULONG nRangeCount = aRangeList.Count();
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ {
+ if (pTab[i] && rMark.GetTableSelect(i))
+ {
+ for (ULONG j=0; j<nRangeCount; j++)
+ {
+ ScRange aRange = *aRangeList.GetObject(j);
+ pTab[i]->ApplyBlockFrame( pLineOuter, pLineInner,
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row() );
+ }
+ }
+ }
+}
+
+
+void ScDocument::ApplyFrameAreaTab( const ScRange& rRange,
+ const SvxBoxItem* pLineOuter,
+ const SvxBoxInfoItem* pLineInner )
+{
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCTAB nEndTab = rRange.aStart.Tab();
+ for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
+ if (pTab[nTab])
+ pTab[nTab]->ApplyBlockFrame( pLineOuter, pLineInner,
+ rRange.aStart.Col(), rRange.aStart.Row(),
+ rRange.aEnd.Col(), rRange.aEnd.Row() );
+}
+
+
+void ScDocument::ApplySelectionPattern( const ScPatternAttr& rAttr, const ScMarkData& rMark )
+{
+ const SfxItemSet* pSet = &rAttr.GetItemSet();
+ BOOL bSet = FALSE;
+ USHORT i;
+ for (i=ATTR_PATTERN_START; i<=ATTR_PATTERN_END && !bSet; i++)
+ if (pSet->GetItemState(i) == SFX_ITEM_SET)
+ bSet = TRUE;
+
+ if (bSet)
+ {
+ // ApplySelectionCache needs multi mark
+ if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
+ {
+ ScRange aRange;
+ rMark.GetMarkArea( aRange );
+ ApplyPatternArea( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rAttr );
+ }
+ else
+ {
+ SfxItemPoolCache aCache( xPoolHelper->GetDocPool(), pSet );
+ for (SCTAB nTab=0; nTab<=MAXTAB; nTab++)
+ if (pTab[nTab])
+ if (rMark.GetTableSelect(nTab))
+ pTab[nTab]->ApplySelectionCache( &aCache, rMark );
+ }
+ }
+}
+
+
+void ScDocument::ChangeSelectionIndent( BOOL bIncrement, const ScMarkData& rMark )
+{
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ pTab[i]->ChangeSelectionIndent( bIncrement, rMark );
+}
+
+
+void ScDocument::ClearSelectionItems( const USHORT* pWhich, const ScMarkData& rMark )
+{
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ pTab[i]->ClearSelectionItems( pWhich, rMark );
+}
+
+
+void ScDocument::DeleteSelection( USHORT nDelFlag, const ScMarkData& rMark )
+{
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ pTab[i]->DeleteSelection( nDelFlag, rMark );
+}
+
+
+void ScDocument::DeleteSelectionTab( SCTAB nTab, USHORT nDelFlag, const ScMarkData& rMark )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->DeleteSelection( nDelFlag, rMark );
+ else
+ {
+ DBG_ERROR("Falsche Tabelle");
+ }
+}
+
+
+ScPatternAttr* ScDocument::GetDefPattern() const
+{
+ return (ScPatternAttr*) &xPoolHelper->GetDocPool()->GetDefaultItem(ATTR_PATTERN);
+}
+
+
+ScDocumentPool* ScDocument::GetPool()
+{
+ return xPoolHelper->GetDocPool();
+}
+
+
+
+ScStyleSheetPool* ScDocument::GetStyleSheetPool() const
+{
+ return xPoolHelper->GetStylePool();
+}
+
+
+SCSIZE ScDocument::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, ScDirection eDir )
+{
+ PutInOrder(nStartCol, nEndCol);
+ PutInOrder(nStartRow, nEndRow);
+ PutInOrder(nStartTab, nEndTab);
+ if (VALIDTAB(nStartTab))
+ {
+ if (pTab[nStartTab])
+ return pTab[nStartTab]->GetEmptyLinesInBlock(nStartCol, nStartRow, nEndCol, nEndRow, eDir);
+ else
+ return 0;
+ }
+ else
+ return 0;
+}
+
+
+void ScDocument::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->FindAreaPos( rCol, rRow, nMovX, nMovY );
+}
+
+
+void ScDocument::GetNextPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY,
+ BOOL bMarked, BOOL bUnprotected, const ScMarkData& rMark )
+{
+ DBG_ASSERT( !nMovX || !nMovY, "GetNextPos: nur X oder Y" );
+
+ ScMarkData aCopyMark = rMark;
+ aCopyMark.SetMarking(FALSE);
+ aCopyMark.MarkToMulti();
+
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->GetNextPos( rCol, rRow, nMovX, nMovY, bMarked, bUnprotected, aCopyMark );
+}
+
+//
+// Datei-Operationen
+//
+
+
+void ScDocument::UpdStlShtPtrsFrmNms()
+{
+ ScPatternAttr::pDoc = this;
+
+ ScDocumentPool* pPool = xPoolHelper->GetDocPool();
+
+ USHORT nCount = pPool->GetItemCount(ATTR_PATTERN);
+ ScPatternAttr* pPattern;
+ for (USHORT i=0; i<nCount; i++)
+ {
+ pPattern = (ScPatternAttr*)pPool->GetItem(ATTR_PATTERN, i);
+ if (pPattern)
+ pPattern->UpdateStyleSheet();
+ }
+ ((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).UpdateStyleSheet();
+}
+
+
+void ScDocument::StylesToNames()
+{
+ ScPatternAttr::pDoc = this;
+
+ ScDocumentPool* pPool = xPoolHelper->GetDocPool();
+
+ USHORT nCount = pPool->GetItemCount(ATTR_PATTERN);
+ ScPatternAttr* pPattern;
+ for (USHORT i=0; i<nCount; i++)
+ {
+ pPattern = (ScPatternAttr*)pPool->GetItem(ATTR_PATTERN, i);
+ if (pPattern)
+ pPattern->StyleToName();
+ }
+ ((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).StyleToName();
+}
+
+
+ULONG ScDocument::GetCellCount() const
+{
+ ULONG nCellCount = 0L;
+
+ for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
+ if ( pTab[nTab] )
+ nCellCount += pTab[nTab]->GetCellCount();
+
+ return nCellCount;
+}
+
+SCSIZE ScDocument::GetCellCount(SCTAB nTab, SCCOL nCol) const
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ return 0;
+
+ return pTab[nTab]->GetCellCount(nCol);
+}
+
+ULONG ScDocument::GetCodeCount() const
+{
+ ULONG nCodeCount = 0;
+
+ for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
+ if ( pTab[nTab] )
+ nCodeCount += pTab[nTab]->GetCodeCount();
+
+ return nCodeCount;
+}
+
+
+ULONG ScDocument::GetWeightedCount() const
+{
+ ULONG nCellCount = 0L;
+
+ for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
+ if ( pTab[nTab] )
+ nCellCount += pTab[nTab]->GetWeightedCount();
+
+ return nCellCount;
+}
+
+
+void ScDocument::PageStyleModified( SCTAB nTab, const String& rNewName )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->PageStyleModified( rNewName );
+}
+
+
+void ScDocument::SetPageStyle( SCTAB nTab, const String& rName )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetPageStyle( rName );
+}
+
+
+const String& ScDocument::GetPageStyle( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetPageStyle();
+
+ return EMPTY_STRING;
+}
+
+
+void ScDocument::SetPageSize( SCTAB nTab, const Size& rSize )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetPageSize( rSize );
+}
+
+Size ScDocument::GetPageSize( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetPageSize();
+
+ DBG_ERROR("falsche Tab");
+ return Size();
+}
+
+
+void ScDocument::SetRepeatArea( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetRepeatArea( nStartCol, nEndCol, nStartRow, nEndRow );
+}
+
+void ScDocument::InvalidatePageBreaks(SCTAB nTab)
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->InvalidatePageBreaks();
+}
+
+void ScDocument::UpdatePageBreaks( SCTAB nTab, const ScRange* pUserArea )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->UpdatePageBreaks( pUserArea );
+}
+
+void ScDocument::RemoveManualBreaks( SCTAB nTab )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->RemoveManualBreaks();
+}
+
+BOOL ScDocument::HasManualBreaks( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->HasManualBreaks();
+
+ DBG_ERROR("falsche Tab");
+ return FALSE;
+}
+
+
+void ScDocument::GetDocStat( ScDocStat& rDocStat )
+{
+ rDocStat.nTableCount = GetTableCount();
+ rDocStat.aDocName = aDocName;
+ rDocStat.nCellCount = GetCellCount();
+}
+
+
+BOOL ScDocument::HasPrintRange()
+{
+ BOOL bResult = FALSE;
+
+ for ( SCTAB i=0; !bResult && i<nMaxTableNumber; i++ )
+ if ( pTab[i] )
+ bResult = pTab[i]->IsPrintEntireSheet() || (pTab[i]->GetPrintRangeCount() > 0);
+
+ return bResult;
+}
+
+
+BOOL ScDocument::IsPrintEntireSheet( SCTAB nTab ) const
+{
+ return (ValidTab(nTab) ) && pTab[nTab] && pTab[nTab]->IsPrintEntireSheet();
+}
+
+
+USHORT ScDocument::GetPrintRangeCount( SCTAB nTab )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetPrintRangeCount();
+
+ return 0;
+}
+
+
+const ScRange* ScDocument::GetPrintRange( SCTAB nTab, USHORT nPos )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetPrintRange(nPos);
+
+ return NULL;
+}
+
+
+const ScRange* ScDocument::GetRepeatColRange( SCTAB nTab )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetRepeatColRange();
+
+ return NULL;
+}
+
+
+const ScRange* ScDocument::GetRepeatRowRange( SCTAB nTab )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetRepeatRowRange();
+
+ return NULL;
+}
+
+
+void ScDocument::ClearPrintRanges( SCTAB nTab )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->ClearPrintRanges();
+}
+
+
+void ScDocument::AddPrintRange( SCTAB nTab, const ScRange& rNew )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->AddPrintRange( rNew );
+}
+
+
+//UNUSED2009-05 void ScDocument::SetPrintRange( SCTAB nTab, const ScRange& rNew )
+//UNUSED2009-05 {
+//UNUSED2009-05 if (ValidTab(nTab) && pTab[nTab])
+//UNUSED2009-05 pTab[nTab]->SetPrintRange( rNew );
+//UNUSED2009-05 }
+
+
+void ScDocument::SetPrintEntireSheet( SCTAB nTab )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->SetPrintEntireSheet();
+}
+
+
+void ScDocument::SetRepeatColRange( SCTAB nTab, const ScRange* pNew )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->SetRepeatColRange( pNew );
+}
+
+
+void ScDocument::SetRepeatRowRange( SCTAB nTab, const ScRange* pNew )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->SetRepeatRowRange( pNew );
+}
+
+
+ScPrintRangeSaver* ScDocument::CreatePrintRangeSaver() const
+{
+ SCTAB nCount = GetTableCount();
+ ScPrintRangeSaver* pNew = new ScPrintRangeSaver( nCount );
+ for (SCTAB i=0; i<nCount; i++)
+ if (pTab[i])
+ pTab[i]->FillPrintSaver( pNew->GetTabData(i) );
+ return pNew;
+}
+
+
+void ScDocument::RestorePrintRanges( const ScPrintRangeSaver& rSaver )
+{
+ SCTAB nCount = rSaver.GetTabCount();
+ for (SCTAB i=0; i<nCount; i++)
+ if (pTab[i])
+ pTab[i]->RestorePrintRanges( rSaver.GetTabData(i) );
+}
+
+
+BOOL ScDocument::NeedPageResetAfterTab( SCTAB nTab ) const
+{
+ // Die Seitennummern-Zaehlung faengt bei einer Tabelle neu an, wenn eine
+ // andere Vorlage als bei der vorherigen gesetzt ist (nur Namen vergleichen)
+ // und eine Seitennummer angegeben ist (nicht 0)
+
+ if ( nTab < MAXTAB && pTab[nTab] && pTab[nTab+1] )
+ {
+ String aNew = pTab[nTab+1]->GetPageStyle();
+ if ( aNew != pTab[nTab]->GetPageStyle() )
+ {
+ SfxStyleSheetBase* pStyle = xPoolHelper->GetStylePool()->Find( aNew, SFX_STYLE_FAMILY_PAGE );
+ if ( pStyle )
+ {
+ const SfxItemSet& rSet = pStyle->GetItemSet();
+ USHORT nFirst = ((const SfxUInt16Item&)rSet.Get(ATTR_PAGE_FIRSTPAGENO)).GetValue();
+ if ( nFirst != 0 )
+ return TRUE; // Seitennummer in neuer Vorlage angegeben
+ }
+ }
+ }
+
+ return FALSE; // sonst nicht
+}
+
+SfxUndoManager* ScDocument::GetUndoManager()
+{
+ if (!mpUndoManager)
+ mpUndoManager = new SfxUndoManager;
+ return mpUndoManager;
+}
+
+ScRowBreakIterator* ScDocument::GetRowBreakIterator(SCTAB nTab) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return new ScRowBreakIterator(pTab[nTab]->maRowPageBreaks);
+ return NULL;
+}
+
+void ScDocument::EnableUndo( bool bVal )
+{
+ GetUndoManager()->EnableUndo(bVal);
+ mbUndoEnabled = bVal;
+}
+
+bool ScDocument::IsInVBAMode() const
+{
+ bool bResult = false;
+ if ( pShell )
+ {
+ com::sun::star::uno::Reference< com::sun::star::script::XVBACompat > xVBA( pShell->GetBasicContainer(), com::sun::star::uno::UNO_QUERY );
+ bResult = xVBA->getVBACompatModeOn();
+ }
+ return bResult;
+}