Files
libreoffice/sc/source/core/data/document.cxx
Markus Mohrhard 067dca9c3e make more calc methods const
Change-Id: Ifc4775546ded8f524379946eb799dbbb314f7e8c
2012-08-10 00:48:41 +02:00

5730 lines
194 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* 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.
*
************************************************************************/
#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 <sfx2/docfile.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 <tools/urlobj.hxx>
#include <com/sun/star/text/WritingMode2.hpp>
#include <com/sun/star/script/vba/XVBACompatibility.hpp>
#include <com/sun/star/sheet/TablePageBreakData.hpp>
#include <com/sun/star/lang/NotInitializedException.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 "dbdata.hxx"
#include "pivot.hxx"
#include "chartlis.hxx"
#include "rangelst.hxx"
#include "markdata.hxx"
#include "drwlayer.hxx"
#include "conditio.hxx"
#include "colorscale.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 "stlalgorithm.hxx"
#include "defaultsoptions.hxx"
#include <map>
#include <limits>
using ::editeng::SvxBorderLine;
using namespace ::com::sun::star;
namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
using ::com::sun::star::uno::Sequence;
using ::com::sun::star::sheet::TablePageBreakData;
using ::std::set;
using ::rtl::OUString;
// The constant parameters to CopyBlockFromClip
struct ScCopyBlockFromClipParams
{
ScDocument* pRefUndoDoc;
ScDocument* pClipDoc;
sal_uInt16 nInsFlag;
SCTAB nTabStart;
SCTAB nTabEnd;
bool bAsLink;
bool bSkipAttrForEmpty;
};
struct ScDefaultAttr
{
const ScPatternAttr* pAttr;
SCROW nFirst;
SCSIZE nCount;
ScDefaultAttr(const ScPatternAttr* pPatAttr) : pAttr(pPatAttr), nFirst(0), nCount(0) {}
};
struct ScLessDefaultAttr
{
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) && ( nTab >= static_cast<SCTAB>(maTabs.size()) ||!maTabs[nTab]) )
{
// Get Custom prefix
const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
rtl::OUString aString = rOpt.GetInitTabPrefix();
aString += rtl::OUString::valueOf(static_cast<sal_Int32>(nTab+1));
if ( _bNeedsNameCheck )
CreateValidTabName( aString ); // no doubles
if (nTab < static_cast<SCTAB>(maTabs.size()))
{
maTabs[nTab] = new ScTable(this, nTab, aString);
}
else
{
while(nTab > static_cast<SCTAB>(maTabs.size()))
maTabs.push_back(NULL);
maTabs.push_back( new ScTable(this, nTab, aString) );
}
maTabs[nTab]->SetLoadingMedium(bLoadingMedium);
}
}
bool ScDocument::HasTable( SCTAB nTab ) const
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
if (maTabs[nTab])
return true;
return false;
}
bool ScDocument::GetName( SCTAB nTab, rtl::OUString& rName ) const
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
if (maTabs[nTab])
{
maTabs[nTab]->GetName( rName );
return true;
}
rName = rtl::OUString();
return false;
}
rtl::OUString ScDocument::GetCopyTabName( SCTAB nTab ) const
{
if (nTab < static_cast<SCTAB>(maTabNames.size()))
return maTabNames[nTab];
else
return rtl::OUString();
}
bool ScDocument::SetCodeName( SCTAB nTab, const rtl::OUString& rName )
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
{
if (maTabs[nTab])
{
maTabs[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, rtl::OUString& rName ) const
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
if (maTabs[nTab])
{
maTabs[nTab]->GetCodeName( rName );
return true;
}
rName = rtl::OUString();
return false;
}
bool ScDocument::GetTable( const rtl::OUString& rName, SCTAB& rTab ) const
{
rtl::OUString aUpperName = ScGlobal::pCharClass->uppercase(rName);
for (SCTAB i=0; i< static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i])
{
if (aUpperName.equals(maTabs[i]->GetUpperName()))
{
rTab = i;
return true;
}
}
rTab = 0;
return false;
}
ScDBData* ScDocument::GetAnonymousDBData(SCTAB nTab)
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
return maTabs[nTab]->GetAnonymousDBData();
return NULL;
}
void ScDocument::SetAnonymousDBData(SCTAB nTab, ScDBData* pDBData)
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
maTabs[nTab]->SetAnonymousDBData(pDBData);
}
bool ScDocument::ValidTabName( const rtl::OUString& rName )
{
if (rName.isEmpty())
return false;
sal_Int32 nLen = rName.getLength();
#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 (sal_Int32 i = 0; i < nLen; ++i)
{
const sal_Unicode c = rName[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 rtl::OUString& rName ) const
{
bool bValid = ValidTabName(rName);
TableContainer::const_iterator it = maTabs.begin();
for (; it != maTabs.end() && bValid; ++it)
if ( *it )
{
rtl::OUString aOldName;
(*it)->GetName(aOldName);
bValid = !ScGlobal::GetpTransliteration()->isEqual( rName, aOldName );
}
return bValid;
}
void ScDocument::CreateValidTabName(rtl::OUString& rName) const
{
if ( !ValidTabName(rName) )
{
// Find new one
// Get Custom prefix
const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
rtl::OUString aStrTable = rOpt.GetInitTabPrefix();
bool bOk = false;
// First test if the prefix is valid, if so only avoid doubles
bool bPrefix = ValidTabName( aStrTable );
OSL_ENSURE(bPrefix, "Invalid Table Name");
SCTAB nDummy;
for ( SCTAB i = static_cast<SCTAB>(maTabs.size())+1; !bOk ; i++ )
{
rtl::OUStringBuffer aBuf;
aBuf.append(aStrTable);
aBuf.append(static_cast<sal_Int32>(i));
rName = aBuf.makeStringAndClear();
if (bPrefix)
bOk = ValidNewTabName( rName );
else
bOk = !GetTable( rName, nDummy );
}
}
else
{
// testing the supplied Name
if ( !ValidNewTabName(rName) )
{
SCTAB i = 1;
rtl::OUStringBuffer aName;
do
{
i++;
aName = rName;
aName.append('_');
aName.append(static_cast<sal_Int32>(i));
}
while (!ValidNewTabName(aName.toString()) && (i < MAXTAB+1));
rName = aName.makeStringAndClear();
}
}
}
void ScDocument::CreateValidTabNames(std::vector<rtl::OUString>& aNames, SCTAB nCount) const
{
aNames.clear();//ensure that the vector is empty
// Get Custom prefix
const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
rtl::OUString aStrTable = rOpt.GetInitTabPrefix();
rtl::OUStringBuffer rName;
bool bOk = false;
// First test if the prefix is valid, if so only avoid doubles
bool bPrefix = ValidTabName( aStrTable );
OSL_ENSURE(bPrefix, "Invalid Table Name");
SCTAB nDummy;
SCTAB i = static_cast<SCTAB>(maTabs.size())+1;
for (SCTAB j = 0; j < nCount; ++j)
{
bOk = false;
while(!bOk)
{
rName = aStrTable;
rName.append(static_cast<sal_Int32>(i));
if (bPrefix)
bOk = ValidNewTabName( rName.toString() );
else
bOk = !GetTable( rName.toString(), nDummy );
i++;
}
aNames.push_back(rName.makeStringAndClear());
}
}
void ScDocument::AppendTabOnLoad(const rtl::OUString& rName)
{
SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
if (!ValidTab(nTabCount))
// max table count reached. No more tables.
return;
rtl::OUString aName = rName;
CreateValidTabName(aName);
maTabs.push_back( new ScTable(this, nTabCount, aName) );
}
void ScDocument::SetTabNameOnLoad(SCTAB nTab, const rtl::OUString& rName)
{
if (!ValidTab(nTab) || static_cast<SCTAB>(maTabs.size()) <= nTab)
return;
if (!ValidTabName(rName))
return;
maTabs[nTab]->SetName(rName);
}
bool ScDocument::InsertTab( SCTAB nPos, const rtl::OUString& rName,
bool bExternalDocument )
{
SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
bool bValid = ValidTab(nTabCount);
if ( !bExternalDocument ) // else test rName == "'Doc'!Tab" first
bValid = (bValid && ValidNewTabName(rName));
if (bValid)
{
if (nPos == SC_TAB_APPEND || nPos >= nTabCount)
{
maTabs.push_back( new ScTable(this, nTabCount, rName) );
if ( bExternalDocument )
maTabs[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 );
if (pRangeName)
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;
TableContainer::iterator it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if ( *it )
(*it)->UpdateInsertTab(nPos);
maTabs.push_back(NULL);
for (i = nTabCount; i > nPos; i--)
{
maTabs[i] = maTabs[i - 1];
}
maTabs[nPos] = new ScTable(this, nPos, rName);
// 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);
it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if ( *it )
(*it)->UpdateCompile();
it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if ( *it )
(*it)->StartAllListeners();
if ( pValidationList )
pValidationList->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
// sheet names of references are not valid until sheet is inserted
if ( pChartListenerCollection )
pChartListenerCollection->UpdateScheduledSeriesRanges();
bValid = true;
}
else
bValid = false;
}
}
if (bValid)
SetDirty();
return bValid;
}
bool ScDocument::InsertTabs( SCTAB nPos, const std::vector<rtl::OUString>& rNames,
bool bExternalDocument, bool bNamesValid )
{
SCTAB nNewSheets = static_cast<SCTAB>(rNames.size());
SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
bool bValid = bNamesValid || ValidTab(nTabCount+nNewSheets);
// if ( !bExternalDocument ) // else test rName == "'Doc'!Tab" first
// bValid = (bValid && ValidNewTabName(rNames));
if (bValid)
{
if (nPos == SC_TAB_APPEND || nPos >= nTabCount)
{
for ( SCTAB i = 0; i < nNewSheets; ++i )
{
maTabs.push_back( new ScTable(this, nTabCount + i, rNames.at(i)) );
if ( bExternalDocument )
maTabs[nTabCount+i]->SetVisible( false );
}
}
else
{
if (VALIDTAB(nPos) && (nPos < nTabCount))
{
ScRange aRange( 0,0,nPos, MAXCOL,MAXROW,MAXTAB );
xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,nNewSheets );
xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,nNewSheets );
if (pRangeName)
pRangeName->UpdateTabRef( nPos, 1, 0, nNewSheets);
pDBCollection->UpdateReference(
URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,nNewSheets );
if (pDPCollection)
pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,nNewSheets );
if (pDetOpList)
pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,nNewSheets );
UpdateChartRef( URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,nNewSheets );
UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0, nNewSheets );
if ( pUnoBroadcaster )
pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,nNewSheets ) );
TableContainer::iterator it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if ( *it )
(*it)->UpdateInsertTab(nPos, nNewSheets);
it = maTabs.begin();
maTabs.insert(it+nPos,nNewSheets, NULL);
for (SCTAB i = 0; i < nNewSheets; ++i)
{
maTabs[nPos + i] = new ScTable(this, nPos + i, rNames.at(i));
}
// 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,nNewSheets);
it = maTabs.begin();
for (; it != maTabs.end(); ++it)
{
if ( *it )
(*it)->UpdateCompile();
}
it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if ( *it )
(*it)->StartAllListeners();
if ( pValidationList )
pValidationList->UpdateReference( URM_INSDEL, aRange, 0,0,nNewSheets );
// sheet names of references are not valid until sheet is inserted
if ( pChartListenerCollection )
pChartListenerCollection->UpdateScheduledSeriesRanges();
bValid = true;
}
else
bValid = false;
}
}
if (bValid)
SetDirty();
return bValid;
}
bool ScDocument::DeleteTab( SCTAB nTab, ScDocument* pRefUndoDoc )
{
bool bValid = false;
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
{
if (maTabs[nTab])
{
SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
if (nTabCount > 1)
{
bool bOldAutoCalc = GetAutoCalc();
SetAutoCalc( false ); // avoid multiple calculations
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( static_cast<SCTAB>(maTabs.size())-1 );
xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
if (pRangeName)
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 ( pValidationList )
pValidationList->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
if ( pUnoBroadcaster )
pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1 ) );
for (SCTAB i = 0, n = static_cast<SCTAB>(maTabs.size()); i < n; ++i)
if (maTabs[i])
maTabs[i]->UpdateDeleteTab(
nTab, false, pRefUndoDoc ? pRefUndoDoc->maTabs[i] : 0);
TableContainer::iterator it = maTabs.begin() + nTab;
delete *it;
maTabs.erase(it);
// 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);
it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if ( *it )
(*it)->UpdateCompile();
// Excel-Filter deletes some Tables while loading, Listeners will
// only be triggered after the loading is done.
if ( !bInsertingFromOtherDoc )
{
it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if ( *it )
(*it)->StartAllListeners();
SetDirty();
}
// sheet names of references are not valid until sheet is deleted
pChartListenerCollection->UpdateScheduledSeriesRanges();
SetAutoCalc( bOldAutoCalc );
bValid = true;
}
}
}
return bValid;
}
bool ScDocument::DeleteTabs( SCTAB nTab, SCTAB nSheets, ScDocument* pRefUndoDoc )
{
bool bValid = false;
if (VALIDTAB(nTab) && (nTab + nSheets) < static_cast<SCTAB>(maTabs.size()))
{
if (maTabs[nTab])
{
SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
if (nTabCount > nSheets)
{
bool bOldAutoCalc = GetAutoCalc();
SetAutoCalc( false ); // avoid multiple calculations
for (SCTAB aTab = 0; aTab < nSheets; ++aTab)
{
ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTab + aTab );
DelBroadcastAreasInRange( aRange );
// #i8180# remove database ranges etc. that are on the deleted tab
// (restored in undo with ScRefUndoData)
xColNameRanges->DeleteOnTab( nTab + aTab );
xRowNameRanges->DeleteOnTab( nTab + aTab );
pDBCollection->DeleteOnTab( nTab + aTab );
if (pDPCollection)
pDPCollection->DeleteOnTab( nTab + aTab );
if (pDetOpList)
pDetOpList->DeleteOnTab( nTab + aTab );
DeleteAreaLinksOnTab( nTab + aTab );
if (pRangeName)
pRangeName->UpdateTabRef( nTab + aTab, 2 );
}
// normal reference update
ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTabCount - 1 );
xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1*nSheets );
xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1*nSheets );
pDBCollection->UpdateReference(
URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1*nSheets );
if (pDPCollection)
pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1*nSheets );
if (pDetOpList)
pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1*nSheets );
UpdateChartRef( URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1*nSheets );
UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1*nSheets );
if ( pValidationList )
pValidationList->UpdateReference( URM_INSDEL, aRange, 0,0,-1*nSheets );
if ( pUnoBroadcaster )
pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1*nSheets ) );
for (SCTAB i = 0, n = static_cast<SCTAB>(maTabs.size()); i < n; ++i)
if (maTabs[i])
maTabs[i]->UpdateDeleteTab(
nTab, false, pRefUndoDoc ? pRefUndoDoc->maTabs[i] : 0,nSheets);
TableContainer::iterator it = maTabs.begin() + nTab;
TableContainer::iterator itEnd = it + nSheets;
std::for_each(it, itEnd, ScDeleteObjectByPtr<ScTable>());
maTabs.erase(it, itEnd);
// 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*nSheets);
it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if ( *it )
(*it)->UpdateCompile();
// Excel-Filter deletes some Tables while loading, Listeners will
// only be triggered after the loading is done.
if ( !bInsertingFromOtherDoc )
{
it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if ( *it )
(*it)->StartAllListeners();
SetDirty();
}
// 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 rtl::OUString& rName, bool /* bUpdateRef */,
bool bExternalDocument )
{
bool bValid = false;
SCTAB i;
if VALIDTAB(nTab)
if (maTabs[nTab])
{
if ( bExternalDocument )
bValid = true; // composed name
else
bValid = ValidTabName(rName);
for (i=0; (i< static_cast<SCTAB>(maTabs.size())) && bValid; i++)
if (maTabs[i] && (i != nTab))
{
rtl::OUString aOldName;
maTabs[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 );
maTabs[nTab]->SetName(rName);
// If formulas refer to the renamed sheet, the TokenArray remains valid,
// but the XML stream must be re-generated.
TableContainer::iterator it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if ( *it && (*it)->IsStreamValid())
(*it)->SetStreamValid( false );
}
}
return bValid;
}
void ScDocument::SetVisible( SCTAB nTab, bool bVisible )
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
if (maTabs[nTab])
maTabs[nTab]->SetVisible(bVisible);
}
bool ScDocument::IsVisible( SCTAB nTab ) const
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
if (maTabs[nTab])
return maTabs[nTab]->IsVisible();
return false;
}
bool ScDocument::IsStreamValid( SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->IsStreamValid();
return false;
}
void ScDocument::SetStreamValid( SCTAB nTab, bool bSet, bool bIgnoreLock )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->SetStreamValid( bSet, bIgnoreLock );
}
void ScDocument::LockStreamValid( bool bLock )
{
mbStreamValidLocked = bLock;
}
bool ScDocument::IsPendingRowHeights( SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->IsPendingRowHeights();
return false;
}
void ScDocument::SetPendingRowHeights( SCTAB nTab, bool bSet )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->SetPendingRowHeights( bSet );
}
void ScDocument::SetLayoutRTL( SCTAB nTab, bool bRTL )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[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.
maTabs[nTab]->SetLoadingRTL( bRTL );
return;
}
maTabs[nTab]->SetLayoutRTL( bRTL ); // only sets the flag
maTabs[nTab]->SetDrawPageSize();
// mirror existing objects:
if (pDrawLayer)
{
SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
OSL_ENSURE(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) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
return maTabs[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 );
}
/* ----------------------------------------------------------------------------
used search area:
GetCellArea - Only Data
GetTableArea - Data / Attributes
GetPrintArea - intended for character objects,
sweeps attributes all the way to bottom / right
---------------------------------------------------------------------------- */
bool ScDocument::GetCellArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
if (maTabs[nTab])
return maTabs[nTab]->GetCellArea( rEndCol, rEndRow );
rEndCol = 0;
rEndRow = 0;
return false;
}
bool ScDocument::GetTableArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
if (maTabs[nTab])
return maTabs[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) || nTab >= static_cast<SCTAB> (maTabs.size()) || !maTabs[nTab])
return false;
SCCOL nCol1, nCol2;
SCROW nRow1, nRow2;
maTabs[nTab]->GetFirstDataPos(nCol1, nRow1);
maTabs[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( bool& o_bShrunk, SCTAB nTab, SCCOL& rStartCol,
SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB> (maTabs.size()) || !maTabs[nTab])
{
o_bShrunk = false;
return false;
}
return maTabs[nTab]->ShrinkToUsedDataArea( o_bShrunk, rStartCol, rStartRow, rEndCol, rEndRow, bColumnsOnly);
}
// connected area
void ScDocument::GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
SCCOL& rEndCol, SCROW& rEndRow, bool bIncludeOld, bool bOnlyDown ) const
{
if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab])
maTabs[nTab]->GetDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bIncludeOld, bOnlyDown );
}
void ScDocument::LimitChartArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
SCCOL& rEndCol, SCROW& rEndRow )
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
if (maTabs[nTab])
maTabs[nTab]->LimitChartArea( rStartCol, rStartRow, rEndCol, rEndRow );
}
void ScDocument::LimitChartIfAll( ScRangeListRef& rRangeList )
{
ScRangeListRef aNew = new ScRangeList;
if (rRangeList.Is())
{
for ( size_t i = 0, nCount = rRangeList->size(); i < nCount; i++ )
{
ScRange aRange( *(*rRangeList)[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 ( nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab])
maTabs[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
{
OSL_FAIL("LimitChartIfAll: Ref==0");
}
rRangeList = aNew;
}
void lcl_GetFirstTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark, SCTAB aMaxTab )
{
// without ScMarkData, leave start/end unchanged
if ( pTabMark )
{
for (SCTAB nTab=0; nTab< aMaxTab; ++nTab)
if (pTabMark->GetTableSelect(nTab))
{
// find first range of consecutive selected sheets
rTabRangeStart = pTabMark->GetFirstSelected();
while ( nTab+1 < aMaxTab && pTabMark->GetTableSelect(nTab+1) )
++nTab;
rTabRangeEnd = nTab;
return;
}
}
}
bool lcl_GetNextTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark, SCTAB aMaxTab )
{
if ( pTabMark )
{
// find next range of consecutive selected sheets after rTabRangeEnd
for (SCTAB nTab=rTabRangeEnd+1; nTab< aMaxTab; ++nTab)
if (pTabMark->GetTableSelect(nTab))
{
rTabRangeStart = nTab;
while ( nTab+1 < aMaxTab && 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 < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i])
bTest &= maTabs[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 = static_cast<SCTAB>(maTabs.size()) -1;
}
bool bTest = true;
bool bRet = false;
bool bOldAutoCalc = GetAutoCalc();
SetAutoCalc( false ); // avoid mulitple calculations
for ( i = nStartTab; i <= nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
bTest &= maTabs[i]->TestInsertRow( nStartCol, nEndCol, nSize );
if (bTest)
{
// UpdateBroadcastAreas have to be called before UpdateReference, so that entries
// aren't shifted that would be rebuild at UpdateReference
// handle chunks of consecutive selected sheets together
SCTAB nTabRangeStart = nStartTab;
SCTAB nTabRangeEnd = nEndTab;
lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
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, static_cast<SCTAB>(maTabs.size()) ) );
lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
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, static_cast<SCTAB>(maTabs.size()) ) );
for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
maTabs[i]->InsertRow( nStartCol, nEndCol, nStartRow, nSize );
// UpdateRef for drawing layer must be after inserting,
// when the new row heights are known.
for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
maTabs[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
TableContainer::iterator it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if (*it)
(*it)->StartNeededListeners();
// at least all cells using range names pointing relative
// to the moved range must recalculate
it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if (*it)
(*it)->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 = static_cast<SCTAB>(maTabs.size())-1;
}
bool bOldAutoCalc = GetAutoCalc();
SetAutoCalc( false ); // avoid multiple calculations
// handle chunks of consecutive selected sheets together
SCTAB nTabRangeStart = nStartTab;
SCTAB nTabRangeEnd = nEndTab;
lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
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, static_cast<SCTAB>(maTabs.size()) ) );
if ( ValidRow(nStartRow+nSize) )
{
lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
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, static_cast<SCTAB>(maTabs.size()) ) );
}
if (pUndoOutline)
*pUndoOutline = false;
for ( i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
maTabs[i]->DeleteRow( nStartCol, nEndCol, nStartRow, nSize, pUndoOutline );
if ( ValidRow(nStartRow+nSize) )
{ // Listeners have been removed in UpdateReference
TableContainer::iterator it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if (*it)
(*it)->StartNeededListeners();
// at least all cells using range names pointing relative
// to the moved range must recalculate
it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if (*it)
(*it)->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 < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i])
bTest &= maTabs[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 = static_cast<SCTAB>(maTabs.size())-1;
}
bool bTest = true;
bool bRet = false;
bool bOldAutoCalc = GetAutoCalc();
SetAutoCalc( false ); // avoid multiple calculations
for ( i = nStartTab; i <= nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
bTest &= maTabs[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, static_cast<SCTAB>(maTabs.size()) );
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, static_cast<SCTAB>(maTabs.size()) ) );
lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
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, static_cast<SCTAB>(maTabs.size()) ) );
for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
maTabs[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
TableContainer::iterator it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if (*it)
(*it)->StartNeededListeners();
// at least all cells using range names pointing relative
// to the moved range must recalculate
it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if (*it)
(*it)->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 = static_cast<SCTAB>(maTabs.size())-1;
}
bool bOldAutoCalc = GetAutoCalc();
SetAutoCalc( false ); // avoid multiple calculations
// handle chunks of consecutive selected sheets together
SCTAB nTabRangeStart = nStartTab;
SCTAB nTabRangeEnd = nEndTab;
lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
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, static_cast<SCTAB>(maTabs.size()) ) );
if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
{
lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
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, static_cast<SCTAB>(maTabs.size()) ) );
}
if (pUndoOutline)
*pUndoOutline = false;
for ( i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
maTabs[i]->DeleteCol( nStartCol, nStartRow, nEndRow, nSize, pUndoOutline );
if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
{// Listeners have been removed in UpdateReference
TableContainer::iterator it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if (*it)
(*it)->StartNeededListeners();
// at least all cells using range names pointing relative
// to the moved range must recalculate
it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if (*it)
(*it)->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 )
{
OSL_ENSURE( rOld.aStart == rNew.aStart, "FitBlock: Beginning is different" );
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, sal_uInt16 nDelFlag)
{
PutInOrder( nCol1, nCol2 );
PutInOrder( nRow1, nRow2 );
bool bOldAutoCalc = GetAutoCalc();
SetAutoCalc( false ); // avoid multiple calculations
for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i])
if ( rMark.GetTableSelect(i) || bIsUndo )
maTabs[i]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
SetAutoCalc( bOldAutoCalc );
}
void ScDocument::DeleteAreaTab(SCCOL nCol1, SCROW nRow1,
SCCOL nCol2, SCROW nRow2,
SCTAB nTab, sal_uInt16 nDelFlag)
{
PutInOrder( nCol1, nCol2 );
PutInOrder( nRow1, nRow2 );
if ( VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
{
bool bOldAutoCalc = GetAutoCalc();
SetAutoCalc( false ); // avoid multiple calculations
maTabs[nTab]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
SetAutoCalc( bOldAutoCalc );
}
}
void ScDocument::DeleteAreaTab( const ScRange& rRange, sal_uInt16 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;
rtl::OUString aString;
for (SCTAB nTab = 0; nTab <= rTabSelection.GetLastSelected(); nTab++)
if ( rTabSelection.GetTableSelect( nTab ) )
{
ScTable* pTable = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
if (nTab < static_cast<SCTAB>(maTabs.size()))
maTabs[nTab] = pTable;
else
maTabs.push_back(pTable);
}
else
{
if (nTab < static_cast<SCTAB>(maTabs.size()))
maTabs[nTab]=NULL;
else
maTabs.push_back(NULL);
}
}
else
{
OSL_FAIL("InitUndo");
}
}
void ScDocument::InitUndo( ScDocument* pSrcDoc, SCTAB nTab1, SCTAB nTab2,
bool bColInfo, bool bRowInfo )
{
if (bIsUndo)
{
Clear();
xPoolHelper = pSrcDoc->xPoolHelper;
if (pSrcDoc->pShell->GetMedium())
maFileURL = pSrcDoc->pShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DECODE_TO_IURI);
rtl::OUString aString;
if ( nTab2 >= static_cast<SCTAB>(maTabs.size()))
maTabs.resize(nTab2 + 1, NULL);
for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
{
ScTable* pTable = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
maTabs[nTab] = pTable;
}
}
else
{
OSL_FAIL("InitUndo");
}
}
void ScDocument::AddUndoTab( SCTAB nTab1, SCTAB nTab2, bool bColInfo, bool bRowInfo )
{
if (bIsUndo)
{
rtl::OUString aString;
if (nTab2 >= static_cast<SCTAB>(maTabs.size()))
{
maTabs.resize(nTab2+1,NULL);
}
for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
if (!maTabs[nTab])
{
maTabs[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
}
}
else
{
OSL_FAIL("InitUndo");
}
}
void ScDocument::SetCutMode( bool bVal )
{
if (bIsClip)
GetClipParam().mbCutMode = bVal;
else
{
OSL_FAIL("SetCutMode without bIsClip");
}
}
bool ScDocument::IsCutMode()
{
if (bIsClip)
return GetClipParam().mbCutMode;
else
{
OSL_FAIL("IsCutMode ohne bIsClip");
return false;
}
}
void ScDocument::CopyToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
sal_uInt16 nFlags, bool bOnlyMarked, ScDocument* pDestDoc,
const ScMarkData* pMarks, bool bColRowFlags )
{
PutInOrder( nCol1, nCol2 );
PutInOrder( nRow1, nRow2 );
PutInOrder( nTab1, nTab2 );
if( pDestDoc->aDocName.isEmpty() )
pDestDoc->aDocName = aDocName;
if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
{
bool bOldAutoCalc = pDestDoc->GetAutoCalc();
pDestDoc->SetAutoCalc( false ); // avoid multiple calculations
for (SCTAB i = nTab1; i <= nTab2 && i < static_cast<SCTAB>(maTabs.size()); i++)
{
if (maTabs[i] && i < static_cast<SCTAB>(pDestDoc->maTabs.size()) && pDestDoc->maTabs[i])
maTabs[i]->CopyToTable( nCol1, nRow1, nCol2, nRow2, nFlags,
bOnlyMarked, pDestDoc->maTabs[i], pMarks,
false, bColRowFlags );
}
pDestDoc->SetAutoCalc( bOldAutoCalc );
}
}
void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
sal_uInt16 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 ); // avoid multiple calculations
if (nTab1 > 0)
CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, false, pDestDoc, pMarks );
OSL_ASSERT( nTab2 < static_cast<SCTAB>(maTabs.size()) && nTab2 < static_cast<SCTAB>(pDestDoc->maTabs.size()));
for (SCTAB i = nTab1; i <= nTab2; i++)
{
if (maTabs[i] && pDestDoc->maTabs[i])
maTabs[i]->UndoToTable(nCol1, nRow1, nCol2, nRow2, nFlags,
bOnlyMarked, pDestDoc->maTabs[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,
sal_uInt16 nFlags, bool bOnlyMarked, ScDocument* pDestDoc,
const ScMarkData* pMarks, bool bColRowFlags)
{
ScRange aNewRange = rRange;
aNewRange.Justify();
if( pDestDoc->aDocName.isEmpty() )
pDestDoc->aDocName = aDocName;
bool bOldAutoCalc = pDestDoc->GetAutoCalc();
pDestDoc->SetAutoCalc( false ); // avoid multiple calculations
for (SCTAB i = aNewRange.aStart.Tab(); i <= aNewRange.aEnd.Tab() && i < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i] && i < static_cast<SCTAB>(pDestDoc->maTabs.size()) && pDestDoc->maTabs[i])
maTabs[i]->CopyToTable(aNewRange.aStart.Col(), aNewRange.aStart.Row(),
aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
nFlags, bOnlyMarked, pDestDoc->maTabs[i],
pMarks, false, bColRowFlags);
pDestDoc->SetAutoCalc( bOldAutoCalc );
}
void ScDocument::UndoToDocument(const ScRange& rRange,
sal_uInt16 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 ); // avoid multiple calculations
if (nTab1 > 0)
CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, false, pDestDoc, pMarks );
for (SCTAB i = nTab1; i <= nTab2 && i < static_cast<SCTAB>(maTabs.size()); i++)
{
if (maTabs[i] && i < static_cast<SCTAB>(pDestDoc->maTabs.size()) && pDestDoc->maTabs[i])
maTabs[i]->UndoToTable(aNewRange.aStart.Col(), aNewRange.aStart.Row(),
aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
nFlags, bOnlyMarked, pDestDoc->maTabs[i], pMarks);
}
if (nTab2 < static_cast<SCTAB>(maTabs.size()))
CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,maTabs.size(), IDF_FORMULA, false, pDestDoc, pMarks );
pDestDoc->SetAutoCalc( bOldAutoCalc );
}
// bUseRangeForVBA added for VBA api support to allow content of a specified
// range to be copied ( e.g. don't use marked data but the just the range
// specified by rClipParam
void ScDocument::CopyToClip(const ScClipParam& rClipParam,
ScDocument* pClipDoc, const ScMarkData* pMarks,
bool bAllTabs, bool bKeepScenarioFlags, bool bIncludeObjects, bool bCloneNoteCaptions, bool bUseRangeForVBA )
{
OSL_ENSURE( !bUseRangeForVBA && ( bAllTabs || pMarks ), "CopyToClip: ScMarkData fails" );
if (bIsClip)
return;
if (!pClipDoc)
{
OSL_TRACE("CopyToClip: no ClipDoc");
pClipDoc = SC_MOD()->GetClipDoc();
}
if (pShell->GetMedium())
{
pClipDoc->maFileURL = pShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DECODE_TO_IURI);
// for unsaved files use the title name and adjust during save of file
if (pClipDoc->maFileURL.isEmpty())
pClipDoc->maFileURL = pShell->GetName();
}
else
{
pClipDoc->maFileURL = pShell->GetName();
}
//init maTabNames
for (TableContainer::iterator itr = maTabs.begin(); itr != maTabs.end(); ++itr)
{
if( *itr )
{
rtl::OUString aTabName;
(*itr)->GetName(aTabName);
pClipDoc->maTabNames.push_back(aTabName);
}
else
pClipDoc->maTabNames.push_back(rtl::OUString());
}
pClipDoc->aDocName = aDocName;
pClipDoc->SetClipParam(rClipParam);
ScRange aClipRange = rClipParam.getWholeRange();
SCTAB nTab = aClipRange.aStart.Tab();
SCTAB i = 0;
SCTAB nEndTab = static_cast<SCTAB>(maTabs.size());
if ( bUseRangeForVBA )
{
pClipDoc->ResetClip( this, nTab );
i = nTab;
nEndTab = nTab + 1;
}
else
pClipDoc->ResetClip(this, pMarks);
if ( bUseRangeForVBA )
CopyRangeNamesToClip(pClipDoc, aClipRange, nTab );
else
CopyRangeNamesToClip(pClipDoc, aClipRange, pMarks, bAllTabs);
for ( ; i < nEndTab; ++i)
{
if (!maTabs[i] || i >= static_cast<SCTAB>(pClipDoc->maTabs.size()) || !pClipDoc->maTabs[i])
continue;
if ( !bUseRangeForVBA && ( pMarks && !pMarks->GetTableSelect(i) ) )
continue;
maTabs[i]->CopyToClip(rClipParam.maRanges, pClipDoc->maTabs[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)
{
if (pShell->GetMedium())
{
pClipDoc->maFileURL = pShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DECODE_TO_IURI);
// for unsaved files use the title name and adjust during save of file
if (pClipDoc->maFileURL.isEmpty())
pClipDoc->maFileURL = pShell->GetName();
}
else
{
pClipDoc->maFileURL = pShell->GetName();
}
//init maTabNames
for (TableContainer::iterator itr = maTabs.begin(); itr != maTabs.end(); ++itr)
{
if( *itr )
{
rtl::OUString aTabName;
(*itr)->GetName(aTabName);
pClipDoc->maTabNames.push_back(aTabName);
}
else
pClipDoc->maTabNames.push_back(rtl::OUString());
}
PutInOrder( nCol1, nCol2 );
PutInOrder( nRow1, nRow2 );
if (!pClipDoc)
{
OSL_TRACE("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 (nTab < static_cast<SCTAB>(maTabs.size()) && nTab < static_cast<SCTAB>(pClipDoc->maTabs.size()))
if (maTabs[nTab] && pClipDoc->maTabs[nTab])
maTabs[nTab]->CopyToClip(nCol1, nRow1, nCol2, nRow2, pClipDoc->maTabs[nTab], false, true);
pClipDoc->GetClipParam().mbCutMode = false;
}
}
void ScDocument::TransposeClip( ScDocument* pTransClip, sal_uInt16 nFlags, bool bAsLink )
{
OSL_ENSURE( bIsClip && pTransClip && pTransClip->bIsClip,
"TransposeClip with wrong Document" );
// initialisieren
// -> pTransClip muss vor dem Original-Dokument geloescht werden!
pTransClip->ResetClip(this, (ScMarkData*)NULL); // alle
// Bereiche uebernehmen
if (pRangeName)
{
pTransClip->GetRangeName()->clear();
ScRangeName::const_iterator itr = pRangeName->begin(), itrEnd = pRangeName->end();
for (; itr != itrEnd; ++itr)
{
sal_uInt16 nIndex = itr->second->GetIndex();
ScRangeData* pData = new ScRangeData(*itr->second);
if (pTransClip->pRangeName->insert(pData))
pData->SetIndex(nIndex);
}
}
// The data
ScRange aClipRange = GetClipParam().getWholeRange();
if ( ValidRow(aClipRange.aEnd.Row()-aClipRange.aStart.Row()) )
{
for (SCTAB i=0; i< static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i])
{
OSL_ENSURE( pTransClip->maTabs[i], "TransposeClip: Table not there" );
maTabs[i]->TransposeClip( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
aClipRange.aEnd.Col(), aClipRange.aEnd.Row(),
pTransClip->maTabs[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
{
OSL_TRACE("TransposeClip: Too big");
}
// Dies passiert erst beim Einfuegen...
GetClipParam().mbCutMode = false;
}
namespace {
void copyUsedNamesToClip(ScRangeName* pClipRangeName, ScRangeName* pRangeName, const std::set<sal_uInt16>& rUsedNames)
{
pClipRangeName->clear();
ScRangeName::const_iterator itr = pRangeName->begin(), itrEnd = pRangeName->end();
for (; itr != itrEnd; ++itr) //! DB-Bereiche Pivot-Bereiche auch !!!
{
sal_uInt16 nIndex = itr->second->GetIndex();
bool bInUse = (rUsedNames.count(nIndex) > 0);
if (!bInUse)
continue;
ScRangeData* pData = new ScRangeData(*itr->second);
if (pClipRangeName->insert(pData))
pData->SetIndex(nIndex);
}
}
}
void ScDocument::CopyRangeNamesToClip(ScDocument* pClipDoc, const ScRange& rClipRange, const ScMarkData* pMarks, bool bAllTabs)
{
if (!pRangeName || pRangeName->empty())
return;
std::set<sal_uInt16> aUsedNames; // indexes of named ranges that are used in the copied cells
for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); ++i)
if (maTabs[i] && i < static_cast<SCTAB>(pClipDoc->maTabs.size()) && pClipDoc->maTabs[i])
if ( bAllTabs || !pMarks || pMarks->GetTableSelect(i) )
maTabs[i]->FindRangeNamesInUse(
rClipRange.aStart.Col(), rClipRange.aStart.Row(),
rClipRange.aEnd.Col(), rClipRange.aEnd.Row(), aUsedNames);
copyUsedNamesToClip(pClipDoc->GetRangeName(), pRangeName, aUsedNames);
}
void ScDocument::CopyRangeNamesToClip(ScDocument* pClipDoc, const ScRange& rClipRange, SCTAB nTab)
{
if (!pRangeName || pRangeName->empty())
return;
// Indexes of named ranges that are used in the copied cells
std::set<sal_uInt16> aUsedNames;
if ( nTab < static_cast<SCTAB>(maTabs.size()) && nTab < static_cast<SCTAB>(pClipDoc->maTabs.size()) )
if ( maTabs[nTab] && pClipDoc->maTabs[nTab] )
{
maTabs[nTab]->FindRangeNamesInUse(
rClipRange.aStart.Col(), rClipRange.aStart.Row(),
rClipRange.aEnd.Col(), rClipRange.aEnd.Row(), aUsedNames );
}
copyUsedNamesToClip(pClipDoc->GetRangeName(), pRangeName, aUsedNames);
}
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->empty())
pFormatExchangeList = pExchangeList;
}
}
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.is() &&
xPoolHelper->GetDocPool() == pClipDoc->xPoolHelper->GetDocPool();
}
void ScDocument::StartListeningFromClip( SCCOL nCol1, SCROW nRow1,
SCCOL nCol2, SCROW nRow2,
const ScMarkData& rMark, sal_uInt16 nInsFlag )
{
if (nInsFlag & IDF_CONTENTS)
{
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
if (maTabs[*itr])
maTabs[*itr]->StartListeningInArea( nCol1, nRow1, nCol2, nRow2 );
}
}
void ScDocument::BroadcastFromClip( SCCOL nCol1, SCROW nRow1,
SCCOL nCol2, SCROW nRow2,
const ScMarkData& rMark, sal_uInt16 nInsFlag )
{
if (nInsFlag & IDF_CONTENTS)
{
ScBulkBroadcast aBulkBroadcast( GetBASM());
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
if (maTabs[*itr])
maTabs[*itr]->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 )
{
TableContainer& rClipTabs = pCBFCP->pClipDoc->maTabs;
SCTAB nTabEnd = pCBFCP->nTabEnd;
SCTAB nClipTab = 0;
for (SCTAB i = pCBFCP->nTabStart; i <= nTabEnd && i < static_cast<SCTAB>(maTabs.size()); i++)
{
if (maTabs[i] && rMark.GetTableSelect(i) )
{
while (!rClipTabs[nClipTab]) nClipTab = (nClipTab+1) % (static_cast<SCTAB>(rClipTabs.size()));
maTabs[i]->CopyFromClip( nCol1, nRow1, nCol2, nRow2, nDx, nDy,
pCBFCP->nInsFlag, pCBFCP->bAsLink, pCBFCP->bSkipAttrForEmpty, rClipTabs[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.)
OSL_ENSURE( 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) % (static_cast<SCTAB>(rClipTabs.size()));
}
}
if ( pCBFCP->nInsFlag & IDF_CONTENTS )
{
nClipTab = 0;
for (SCTAB i = pCBFCP->nTabStart; i <= nTabEnd && i < static_cast<SCTAB>(maTabs.size()); i++)
{
if (maTabs[i] && rMark.GetTableSelect(i) )
{
while (!rClipTabs[nClipTab]) nClipTab = (nClipTab+1) % (static_cast<SCTAB>(rClipTabs.size()));
SCsTAB nDz = ((SCsTAB)i) - nClipTab;
// 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
&& rClipTabs[(nClipTab + nFollow + 1) % static_cast<SCTAB>(rClipTabs.size())] )
++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, false );
SetInsertingFromOtherDoc( bOldInserting);
}
else
UpdateReference( URM_COPY,
nCol1, nRow1, i, nCol2, nRow2, i+nFollow,
nDx, nDy, nDz, pCBFCP->pRefUndoDoc, false );
nClipTab = (nClipTab+nFollow+1) % (static_cast<SCTAB>(rClipTabs.size()));
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;
TableContainer& rClipTabs = pCBFCP->pClipDoc->maTabs;
while ( nFlagTab < static_cast<SCTAB>(rClipTabs.size()) && !rClipTabs[nFlagTab] )
++nFlagTab;
SCROW nSourceRow = rClipStartRow;
SCROW nSourceEnd = 0;
if ( !pCBFCP->pClipDoc->GetClipParam().maRanges.empty() )
nSourceEnd = pCBFCP->pClipDoc->GetClipParam().maRanges.front()->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,
sal_uInt16 nInsFlag,
ScDocument* pRefUndoDoc, ScDocument* pClipDoc, bool bResetCut,
bool bAsLink, bool bIncludeFiltered, bool bSkipAttrForEmpty,
const ScRangeList * pDestRanges )
{
if (!bIsClip)
{
if (!pClipDoc)
{
OSL_FAIL("CopyFromClip: no ClipDoc");
pClipDoc = SC_MOD()->GetClipDoc();
}
if (pClipDoc->bIsClip && pClipDoc->GetTableCount())
{
bool bOldAutoCalc = GetAutoCalc();
SetAutoCalc( false ); // avoid multiple recalculations
NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
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 < static_cast<SCTAB>(pClipDoc->maTabs.size()); nTab++) // find largest merge overlap
if (pClipDoc->maTabs[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. */
sal_uInt16 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?
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
if (maTabs[*itr])
{
if ( *itr < aCBFCP.nTabStart )
aCBFCP.nTabStart = *itr;
aCBFCP.nTabEnd = *itr;
maTabs[*itr]->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();
SCROW nClipEndRow = aClipRange.aEnd.Row();
for ( size_t nRange = 0; nRange < pDestRanges->size(); ++nRange )
{
const ScRange* pRange = (*pDestRanges)[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 );
}
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;
itr = rMark.begin();
for (; itr != itrEnd && *itr < nMax; ++itr)
if (maTabs[*itr] )
maTabs[*itr]->DecRecalcLevel();
bInsertingFromOtherDoc = false;
// 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, sal_uInt8>& 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);
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;
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
{
if (maTabs[*itr])
{
if ( *itr < aCBFCP.nTabStart )
aCBFCP.nTabStart = *itr;
aCBFCP.nTabEnd = *itr;
maTabs[*itr]->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, sal_uInt8>& rFlags = GetRowFlagsArray(aCBFCP.nTabStart);
for ( size_t i = 0, n = rClipParam.maRanges.size(); i < n; ++i )
{
ScRange* p = rClipParam.maRanges[ i ];
// 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;
}
itr = rMark.begin();
for (; itr != itrEnd && *itr < nMax; ++itr)
if (maTabs[*itr])
maTabs[*itr]->DecRecalcLevel();
bInsertingFromOtherDoc = false;
ScRangeList aRanges;
aRanges.Append(aDestRange);
// 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
{
OSL_FAIL("SetClipArea: kein Clip");
}
}
void ScDocument::GetClipArea(SCCOL& nClipX, SCROW& nClipY, bool bIncludeFiltered)
{
if (!bIsClip)
{
OSL_FAIL("GetClipArea: kein Clip");
return;
}
ScRangeList& rClipRanges = GetClipParam().maRanges;
if (rClipRanges.empty())
// No clip range. Bail out.
return;
ScRange* p = rClipRanges.front();
SCCOL nStartCol = p->aStart.Col();
SCCOL nEndCol = p->aEnd.Col();
SCROW nStartRow = p->aStart.Row();
SCROW nEndRow = p->aEnd.Row();
for ( size_t i = 1, n = rClipRanges.size(); i < n; ++i )
{
p = rClipRanges[ i ];
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 < static_cast<SCTAB>(maTabs.size()) && !maTabs[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.empty() )
{
nClipX = rClipRanges.front()->aStart.Col();
nClipY = rClipRanges.front()->aStart.Row();
}
}
else
{
OSL_FAIL("GetClipStart: kein Clip");
}
}
bool ScDocument::HasClipFilteredRows()
{
// count on first used table in clipboard
SCTAB nCountTab = 0;
while ( nCountTab < static_cast<SCTAB>(maTabs.size()) && !maTabs[nCountTab] )
++nCountTab;
ScRangeList& rClipRanges = GetClipParam().maRanges;
if ( rClipRanges.empty() )
return false;
for ( size_t i = 0, n = rClipRanges.size(); i < n; ++i )
{
ScRange* p = rClipRanges[ i ];
bool bAnswer = maTabs[nCountTab]->HasFilteredRows(p->aStart.Row(), p->aEnd.Row());
if (bAnswer)
return true;
}
return false;
}
void ScDocument::MixDocument( const ScRange& rRange, sal_uInt16 nFunction, bool bSkipEmpty,
ScDocument* pSrcDoc )
{
SCTAB nTab1 = rRange.aStart.Tab();
SCTAB nTab2 = rRange.aEnd.Tab();
for (SCTAB i = nTab1; i <= nTab2 && i < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i] && i < static_cast<SCTAB>(pSrcDoc->maTabs.size()) && pSrcDoc->maTabs[i])
maTabs[i]->MixData( rRange.aStart.Col(), rRange.aStart.Row(),
rRange.aEnd.Col(), rRange.aEnd.Row(),
nFunction, bSkipEmpty, pSrcDoc->maTabs[i] );
}
void ScDocument::FillTab( const ScRange& rSrcArea, const ScMarkData& rMark,
sal_uInt16 nFlags, sal_uInt16 nFunction,
bool bSkipEmpty, bool bAsLink )
{
sal_uInt16 nDelFlags = nFlags;
if (nDelFlags & IDF_CONTENTS)
nDelFlags |= IDF_CONTENTS; // immer alle Inhalte oder keine loeschen!
SCTAB nSrcTab = rSrcArea.aStart.Tab();
if (ValidTab(nSrcTab) && nSrcTab < static_cast<SCTAB>(maTabs.size()) && maTabs[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 ); // avoid multiple calculations
SCTAB nCount = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nCount; ++itr)
if ( *itr!=nSrcTab && maTabs[*itr])
{
SCTAB i = *itr;
if (bDoMix)
{
if (!pMixDoc)
{
pMixDoc = new ScDocument( SCDOCMODE_UNDO );
pMixDoc->InitUndo( this, i, i );
}
else
pMixDoc->AddUndoTab( i, i );
maTabs[i]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
IDF_CONTENTS, false, pMixDoc->maTabs[i] );
}
maTabs[i]->DeleteArea( nStartCol,nStartRow, nEndCol,nEndRow, nDelFlags);
maTabs[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
nFlags, false, maTabs[i], NULL, bAsLink );
if (bDoMix)
maTabs[i]->MixData( nStartCol,nStartRow, nEndCol,nEndRow,
nFunction, bSkipEmpty, pMixDoc->maTabs[i] );
}
delete pMixDoc;
SetAutoCalc( bOldAutoCalc );
}
else
{
OSL_FAIL("falsche Tabelle");
}
}
void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
sal_uInt16 nFlags, sal_uInt16 nFunction,
bool bSkipEmpty, bool bAsLink )
{
sal_uInt16 nDelFlags = nFlags;
if (nDelFlags & IDF_CONTENTS)
nDelFlags |= IDF_CONTENTS; // immer alle Inhalte oder keine loeschen!
if (ValidTab(nSrcTab) && nSrcTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nSrcTab])
{
ScDocument* pMixDoc = NULL;
bool bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
bool bOldAutoCalc = GetAutoCalc();
SetAutoCalc( false ); // avoid multiple calculations
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 = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nCount; ++itr)
if ( *itr!=nSrcTab && maTabs[*itr] )
{
SCTAB i = *itr;
if (bDoMix)
{
if (!pMixDoc)
{
pMixDoc = new ScDocument( SCDOCMODE_UNDO );
pMixDoc->InitUndo( this, i, i );
}
else
pMixDoc->AddUndoTab( i, i );
maTabs[i]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
IDF_CONTENTS, true, pMixDoc->maTabs[i], &rMark );
}
maTabs[i]->DeleteSelection( nDelFlags, rMark );
maTabs[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
nFlags, true, maTabs[i], &rMark, bAsLink );
if (bDoMix)
maTabs[i]->MixMarked( rMark, nFunction, bSkipEmpty, pMixDoc->maTabs[i] );
}
delete pMixDoc;
SetAutoCalc( bOldAutoCalc );
}
else
{
OSL_FAIL("falsche Tabelle");
}
}
void ScDocument::PutCell( SCCOL nCol, SCROW nRow, SCTAB nTab, ScBaseCell* pCell, bool bForceTab )
{
if (VALIDTAB(nTab))
{
if ( bForceTab && ( nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab]) )
{
bool bExtras = !bIsUndo; // Spaltenbreiten, Zeilenhoehen, Flags
if (nTab >= static_cast<SCTAB>(maTabs.size()))
maTabs.resize(nTab + 1,NULL);
maTabs[nTab] = new ScTable(this, nTab,
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("temp")),
bExtras, bExtras);
}
if (maTabs[nTab])
maTabs[nTab]->PutCell( nCol, nRow, pCell );
}
}
void ScDocument::PutCell( const ScAddress& rPos, ScBaseCell* pCell, bool bForceTab )
{
SCTAB nTab = rPos.Tab();
if ( bForceTab && ( nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab]) )
{
bool bExtras = !bIsUndo; // Spaltenbreiten, Zeilenhoehen, Flags
if (nTab >= static_cast<SCTAB>(maTabs.size()))
maTabs.resize(nTab + 1,NULL);
maTabs[nTab] = new ScTable(this, nTab,
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("temp")),
bExtras, bExtras);
}
if (maTabs[nTab])
maTabs[nTab]->PutCell( rPos, pCell );
}
bool ScDocument::SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const rtl::OUString& rString,
ScSetStringParam* pParam )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->SetString( nCol, nRow, nTab, rString, pParam );
else
return false;
}
void ScDocument::SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal )
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
if (maTabs[nTab])
maTabs[nTab]->SetValue( nCol, nRow, rVal );
}
void ScDocument::GetString( SCCOL nCol, SCROW nRow, SCTAB nTab, rtl::OUString& rString )
{
if ( VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->GetString( nCol, nRow, rString );
else
rString = rtl::OUString();
}
void ScDocument::GetString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString )
{
rtl::OUString aString;
GetString( nCol, nRow, nTab, aString);
rString = aString;
}
void ScDocument::GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, rtl::OUString& rString )
{
if ( VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->GetInputString( nCol, nRow, rString );
else
rString = rtl::OUString();
}
void ScDocument::GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString )
{
rtl::OUString aString;
GetInputString( nCol, nRow, nTab, aString);
rString = aString;
}
sal_uInt16 ScDocument::GetStringForFormula( const ScAddress& rPos, rtl::OUString& rString )
{
// Used in formulas (add-in parameters etc), so it must use the same semantics as
// ScInterpreter::GetCellString: always format values as numbers.
// The return value is the error code.
sal_uInt16 nErr = 0;
String aStr;
ScBaseCell* pCell = GetCell( rPos );
if (pCell)
{
SvNumberFormatter* pFormatter = GetFormatTable();
switch (pCell->GetCellType())
{
case CELLTYPE_STRING:
aStr = static_cast<ScStringCell*>(pCell)->GetString();
break;
case CELLTYPE_EDIT:
aStr = static_cast<ScEditCell*>(pCell)->GetString();
break;
case CELLTYPE_FORMULA:
{
ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
nErr = pFCell->GetErrCode();
if (pFCell->IsValue())
{
double fVal = pFCell->GetValue();
sal_uLong nIndex = pFormatter->GetStandardFormat(
NUMBERFORMAT_NUMBER,
ScGlobal::eLnge);
pFormatter->GetInputLineString(fVal, nIndex, aStr);
}
else
aStr = pFCell->GetString();
}
break;
case CELLTYPE_VALUE:
{
double fVal = static_cast<ScValueCell*>(pCell)->GetValue();
sal_uLong nIndex = pFormatter->GetStandardFormat(
NUMBERFORMAT_NUMBER,
ScGlobal::eLnge);
pFormatter->GetInputLineString(fVal, nIndex, aStr);
}
break;
default:
;
}
}
rString = aStr;
return nErr;
}
void ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, double& rValue )
{
if ( VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
rValue = maTabs[nTab]->GetValue( nCol, nRow );
else
rValue = 0.0;
}
double ScDocument::GetValue( const ScAddress& rPos )
{
SCTAB nTab = rPos.Tab();
if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetValue( rPos );
return 0.0;
}
void ScDocument::GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab,
sal_uInt32& rFormat ) const
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
if (maTabs[nTab])
{
rFormat = maTabs[nTab]->GetNumberFormat( nCol, nRow );
return ;
}
rFormat = 0;
}
sal_uInt32 ScDocument::GetNumberFormat( const ScRange& rRange ) const
{
SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = rRange.aEnd.Tab();
SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
if (!ValidTab(nTab1) || !ValidTab(nTab2) || !maTabs[nTab1] || !maTabs[nTab2])
return 0;
sal_uInt32 nFormat = 0;
bool bFirstItem = true;
for (SCTAB nTab = nTab1; nTab <= nTab2 && nTab < static_cast<SCTAB>(maTabs.size()) ; ++nTab)
for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
{
sal_uInt32 nThisFormat = maTabs[nTab]->GetNumberFormat(nCol, nRow1, nRow2);
if (bFirstItem)
{
nFormat = nThisFormat;
bFirstItem = false;
}
else if (nThisFormat != nFormat)
return 0;
}
return nFormat;
}
sal_uInt32 ScDocument::GetNumberFormat( const ScAddress& rPos ) const
{
SCTAB nTab = rPos.Tab();
if ( maTabs[nTab] )
return maTabs[nTab]->GetNumberFormat( rPos );
return 0;
}
void ScDocument::GetNumberFormatInfo( short& nType, sal_uLong& nIndex,
const ScAddress& rPos, const ScBaseCell* pCell ) const
{
SCTAB nTab = rPos.Tab();
if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
{
nIndex = maTabs[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, rtl::OUString& rFormula ) const
{
if ( VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->GetFormula( nCol, nRow, rFormula );
else
rFormula = rtl::OUString();
}
void ScDocument::GetFormula( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rFormula ) const
{
rtl::OUString aString;
GetFormula( nCol, nRow, nTab, aString);
rFormula = aString;
}
CellType ScDocument::GetCellType( const ScAddress& rPos ) const
{
SCTAB nTab = rPos.Tab();
if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetCellType( rPos );
return CELLTYPE_NONE;
}
void ScDocument::GetCellType( SCCOL nCol, SCROW nRow, SCTAB nTab,
CellType& rCellType ) const
{
if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
rCellType = maTabs[nTab]->GetCellType( nCol, nRow );
else
rCellType = CELLTYPE_NONE;
}
void ScDocument::GetCell( SCCOL nCol, SCROW nRow, SCTAB nTab,
ScBaseCell*& rpCell ) const
{
if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
rpCell = maTabs[nTab]->GetCell( nCol, nRow );
else
{
OSL_FAIL("GetCell ohne Tabelle");
rpCell = NULL;
}
}
ScBaseCell* ScDocument::GetCell( const ScAddress& rPos ) const
{
SCTAB nTab = rPos.Tab();
if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
return maTabs[nTab]->GetCell( rPos );
OSL_FAIL("GetCell ohne Tabelle");
return NULL;
}
bool ScDocument::HasStringData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
{
if ( VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->HasStringData( nCol, nRow );
else
return false;
}
bool ScDocument::HasValueData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
{
if ( VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[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 < static_cast<SCTAB>(maTabs.size()); nTab++ )
if ( maTabs[nTab] && maTabs[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 ) );
}
void ScDocument::InitializeNoteCaptions( SCTAB nTab, bool bForced )
{
if( ValidTab( nTab ) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[ nTab ] )
maTabs[ nTab ]->InitializeNoteCaptions( bForced );
}
void ScDocument::SetDirty()
{
bool bOldAutoCalc = GetAutoCalc();
bAutoCalc = false; // keine Mehrfachberechnung
{ // scope for bulk broadcast
ScBulkBroadcast aBulkBroadcast( GetBASM());
TableContainer::iterator it = maTabs.begin();
for (;it != maTabs.end(); ++it)
if (*it)
(*it)->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 < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i]) maTabs[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 < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i]) maTabs[i]->SetTableOpDirty( rRange );
SetAutoCalc( bOldAutoCalc );
}
void ScDocument::InterpretDirtyCells( const ScRangeList& rRanges )
{
for (size_t nPos=0, nRangeCount = rRanges.size(); nPos < nRangeCount; nPos++)
{
ScCellIterator aIter( this, *rRanges[ 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 )
{
if ( !aTableOpList.empty() )
{
ScInterpreterTableOpParams* p = &aTableOpList.back();
if ( 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 );
TableContainer::iterator it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if (*it)
(*it)->SetDirtyVar();
for (it = maTabs.begin(); it != maTabs.end(); ++it)
if (*it)
(*it)->CalcAll();
ClearFormulaTree();
SetAutoCalc( bOldAutoCalc );
}
void ScDocument::CompileAll()
{
TableContainer::iterator it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if (*it)
(*it)->CompileAll();
SetDirty();
}
void ScDocument::CompileXML()
{
bool bOldAutoCalc = GetAutoCalc();
SetAutoCalc( false );
ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(
STR_PROGRESS_CALCULATING ), GetXMLImportedFormulaCount() );
// set AutoNameCache to speed up automatic name lookup
OSL_ENSURE( !pAutoNameCache, "AutoNameCache already set" );
pAutoNameCache = new ScAutoNameCache( this );
if (pRangeName)
pRangeName->CompileUnresolvedXML();
TableContainer::iterator it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if (*it)
(*it)->CompileXML( aProgress );
DELETEZ( pAutoNameCache ); // valid only during CompileXML, where cell contents don't change
if ( pValidationList )
pValidationList->CompileXML();
SetAutoCalc( bOldAutoCalc );
}
void ScDocument::CalcAfterLoad()
{
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;
{
TableContainer::iterator it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if (*it)
(*it)->CalcAfterLoad();
for (it = maTabs.begin(); it != maTabs.end(); ++it)
if (*it)
(*it)->SetDirtyAfterLoad();
}
bCalcingAfterLoad = false;
SetDetectiveDirty(false); // noch keine wirklichen Aenderungen
// #i112436# If formula cells are already dirty, they don't broadcast further changes.
// So the source ranges of charts must be interpreted even if they are not visible,
// similar to ScMyShapeResizer::CreateChartListener for loading own files (i104899).
if (pChartListenerCollection)
{
const ScChartListenerCollection::ListenersType& rListeners = pChartListenerCollection->getListeners();
ScChartListenerCollection::ListenersType::const_iterator it = rListeners.begin(), itEnd = rListeners.end();
for (; it != itEnd; ++it)
{
const ScChartListener* p = it->second;
InterpretDirtyCells(*p->GetRangeList());
}
}
}
sal_uInt16 ScDocument::GetErrCode( const ScAddress& rPos ) const
{
SCTAB nTab = rPos.Tab();
if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetErrCode( rPos );
return 0;
}
void ScDocument::ResetChanged( const ScRange& rRange )
{
SCTAB nTabSize = static_cast<SCTAB>(maTabs.size());
SCTAB nTab1 = rRange.aStart.Tab();
SCTAB nTab2 = rRange.aEnd.Tab();
for (SCTAB nTab = nTab1; nTab1 <= nTab2 && nTab < nTabSize; ++nTab)
if (maTabs[nTab])
maTabs[nTab]->ResetChanged(rRange);
}
//
// Spaltenbreiten / Zeilenhoehen --------------------------------------
//
void ScDocument::SetColWidth( SCCOL nCol, SCTAB nTab, sal_uInt16 nNewWidth )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->SetColWidth( nCol, nNewWidth );
}
void ScDocument::SetColWidthOnly( SCCOL nCol, SCTAB nTab, sal_uInt16 nNewWidth )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->SetColWidthOnly( nCol, nNewWidth );
}
void ScDocument::SetRowHeight( SCROW nRow, SCTAB nTab, sal_uInt16 nNewHeight )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->SetRowHeight( nRow, nNewHeight );
}
void ScDocument::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->SetRowHeightRange
( nStartRow, nEndRow, nNewHeight, 1.0, 1.0 );
}
void ScDocument::SetRowHeightOnly( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->SetRowHeightOnly( nStartRow, nEndRow, nNewHeight );
}
void ScDocument::SetManualHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bManual )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->SetManualHeight( nStartRow, nEndRow, bManual );
}
sal_uInt16 ScDocument::GetColWidth( SCCOL nCol, SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetColWidth( nCol );
OSL_FAIL("Falsche Tabellennummer");
return 0;
}
sal_uInt16 ScDocument::GetOriginalWidth( SCCOL nCol, SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetOriginalWidth( nCol );
OSL_FAIL("Falsche Tabellennummer");
return 0;
}
sal_uInt16 ScDocument::GetCommonWidth( SCCOL nEndCol, SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetCommonWidth( nEndCol );
OSL_FAIL("Wrong table number");
return 0;
}
sal_uInt16 ScDocument::GetOriginalHeight( SCROW nRow, SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetOriginalHeight( nRow );
OSL_FAIL("Wrong table number");
return 0;
}
sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, bool bHiddenAsZero ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetRowHeight( nRow, NULL, NULL, bHiddenAsZero );
OSL_FAIL("Wrong sheet number");
return 0;
}
sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, SCROW* pStartRow, SCROW* pEndRow, bool bHiddenAsZero ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetRowHeight( nRow, pStartRow, pEndRow, bHiddenAsZero );
OSL_FAIL("Wrong sheet number");
return 0;
}
sal_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) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetRowHeight( nStartRow, nEndRow);
OSL_FAIL("wrong sheet number");
return 0;
}
SCROW ScDocument::GetRowForHeight( SCTAB nTab, sal_uLong nHeight ) const
{
return maTabs[nTab]->GetRowForHeight(nHeight);
}
sal_uLong ScDocument::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow,
SCTAB nTab, double fScale ) const
{
// faster for a single row
if (nStartRow == nEndRow)
return (sal_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) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetScaledRowHeight( nStartRow, nEndRow, fScale);
OSL_FAIL("wrong sheet number");
return 0;
}
SCROW ScDocument::GetHiddenRowCount( SCROW nRow, SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetHiddenRowCount( nRow );
OSL_FAIL("Falsche Tabellennummer");
return 0;
}
sal_uLong ScDocument::GetColOffset( SCCOL nCol, SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetColOffset( nCol );
OSL_FAIL("Falsche Tabellennummer");
return 0;
}
sal_uLong ScDocument::GetRowOffset( SCROW nRow, SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetRowOffset( nRow );
OSL_FAIL("Falsche Tabellennummer");
return 0;
}
sal_uInt16 ScDocument::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, OutputDevice* pDev,
double nPPTX, double nPPTY,
const Fraction& rZoomX, const Fraction& rZoomY,
bool bFormula, const ScMarkData* pMarkData,
const ScColWidthParam* pParam )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetOptimalColWidth( nCol, pDev, nPPTX, nPPTY,
rZoomX, rZoomY, bFormula, pMarkData, pParam );
OSL_FAIL("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) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetNeededSize
( nCol, nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, bTotalSize );
OSL_FAIL("Falsche Tabellennummer");
return 0;
}
bool ScDocument::SetOptimalHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nExtra,
OutputDevice* pDev,
double nPPTX, double nPPTY,
const Fraction& rZoomX, const Fraction& rZoomY,
bool bShrink )
{
//! MarkToMulti();
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->SetOptimalHeight( nStartRow, nEndRow, nExtra,
pDev, nPPTX, nPPTY, rZoomX, rZoomY, bShrink );
OSL_FAIL("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
sal_uLong nCellCount = 0;
for ( SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()); nTab++ )
if ( maTabs[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
nCellCount += maTabs[nTab]->GetWeightedCount();
ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), nCellCount );
sal_uLong nProgressStart = 0;
for ( SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()); nTab++ )
if ( maTabs[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
{
maTabs[nTab]->SetOptimalHeightOnly( 0, MAXROW, 0,
pDev, nPPTX, nPPTY, rZoomX, rZoomY, false, &aProgress, nProgressStart );
maTabs[nTab]->SetDrawPageSize(true, true);
nProgressStart += maTabs[nTab]->GetWeightedCount();
}
}
//
// Spalten-/Zeilen-Flags ----------------------------------------------
//
void ScDocument::ShowCol(SCCOL nCol, SCTAB nTab, bool bShow)
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->ShowCol( nCol, bShow );
}
void ScDocument::ShowRow(SCROW nRow, SCTAB nTab, bool bShow)
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->ShowRow( nRow, bShow );
}
void ScDocument::ShowRows(SCROW nRow1, SCROW nRow2, SCTAB nTab, bool bShow)
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->ShowRows( nRow1, nRow2, bShow );
}
void ScDocument::SetRowFlags( SCROW nRow, SCTAB nTab, sal_uInt8 nNewFlags )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->SetRowFlags( nRow, nNewFlags );
}
void ScDocument::SetRowFlags( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt8 nNewFlags )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->SetRowFlags( nStartRow, nEndRow, nNewFlags );
}
sal_uInt8 ScDocument::GetColFlags( SCCOL nCol, SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetColFlags( nCol );
OSL_FAIL("Falsche Tabellennummer");
return 0;
}
sal_uInt8 ScDocument::GetRowFlags( SCROW nRow, SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetRowFlags( nRow );
OSL_FAIL("Falsche Tabellennummer");
return 0;
}
const ScBitMaskCompressedArray< SCROW, sal_uInt8> & ScDocument::GetRowFlagsArray(
SCTAB nTab ) const
{
const ScBitMaskCompressedArray< SCROW, sal_uInt8> * pFlags;
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
pFlags = maTabs[nTab]->GetRowFlagsArray();
else
{
OSL_FAIL("wrong sheet number");
pFlags = 0;
}
if (!pFlags)
{
OSL_FAIL("no row flags at sheet");
static ScBitMaskCompressedArray< SCROW, sal_uInt8> aDummy( MAXROW, 0);
pFlags = &aDummy;
}
return *pFlags;
}
void ScDocument::GetAllRowBreaks(set<SCROW>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return;
maTabs[nTab]->GetAllRowBreaks(rBreaks, bPage, bManual);
}
void ScDocument::GetAllColBreaks(set<SCCOL>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
{
if (!ValidTab(nTab) || !maTabs[nTab])
return;
maTabs[nTab]->GetAllColBreaks(rBreaks, bPage, bManual);
}
ScBreakType ScDocument::HasRowBreak(SCROW nRow, SCTAB nTab) const
{
ScBreakType nType = BREAK_NONE;
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
return nType;
if (maTabs[nTab]->HasRowPageBreak(nRow))
nType |= BREAK_PAGE;
if (maTabs[nTab]->HasRowManualBreak(nRow))
nType |= BREAK_MANUAL;
return nType;
}
ScBreakType ScDocument::HasColBreak(SCCOL nCol, SCTAB nTab) const
{
ScBreakType nType = BREAK_NONE;
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
return nType;
if (maTabs[nTab]->HasColPageBreak(nCol))
nType |= BREAK_PAGE;
if (maTabs[nTab]->HasColManualBreak(nCol))
nType |= BREAK_MANUAL;
return nType;
}
void ScDocument::SetRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
return;
maTabs[nTab]->SetRowBreak(nRow, bPage, bManual);
}
void ScDocument::SetColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
return;
maTabs[nTab]->SetColBreak(nCol, bPage, bManual);
}
void ScDocument::RemoveRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
return;
maTabs[nTab]->RemoveRowBreak(nRow, bPage, bManual);
}
void ScDocument::RemoveColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
return;
maTabs[nTab]->RemoveColBreak(nCol, bPage, bManual);
}
Sequence<TablePageBreakData> ScDocument::GetRowBreakData(SCTAB nTab) const
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return Sequence<TablePageBreakData>();
return maTabs[nTab]->GetRowBreakData();
}
bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return false;
return maTabs[nTab]->RowHidden(nRow, pFirstRow, pLastRow);
}
bool ScDocument::HasHiddenRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return false;
return maTabs[nTab]->HasHiddenRows(nStartRow, nEndRow);
}
bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
{
if (pFirstCol)
*pFirstCol = nCol;
if (pLastCol)
*pLastCol = nCol;
return false;
}
return maTabs[nTab]->ColHidden(nCol, pFirstCol, pLastCol);
}
void ScDocument::SetRowHidden(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHidden)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return;
maTabs[nTab]->SetRowHidden(nStartRow, nEndRow, bHidden);
}
void ScDocument::SetColHidden(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bHidden)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return;
maTabs[nTab]->SetColHidden(nStartCol, nEndCol, bHidden);
}
SCROW ScDocument::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return ::std::numeric_limits<SCROW>::max();;
return maTabs[nTab]->FirstVisibleRow(nStartRow, nEndRow);
}
SCROW ScDocument::LastVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return ::std::numeric_limits<SCROW>::max();;
return maTabs[nTab]->LastVisibleRow(nStartRow, nEndRow);
}
SCROW ScDocument::CountVisibleRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return 0;
return maTabs[nTab]->CountVisibleRows(nStartRow, nEndRow);
}
bool ScDocument::RowFiltered(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return false;
return maTabs[nTab]->RowFiltered(nRow, pFirstRow, pLastRow);
}
bool ScDocument::HasFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return false;
return maTabs[nTab]->HasFilteredRows(nStartRow, nEndRow);
}
bool ScDocument::ColFiltered(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return false;
return maTabs[nTab]->ColFiltered(nCol, pFirstCol, pLastCol);
}
void ScDocument::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bFiltered)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return;
maTabs[nTab]->SetRowFiltered(nStartRow, nEndRow, bFiltered);
}
SCROW ScDocument::FirstNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return ::std::numeric_limits<SCROW>::max();;
return maTabs[nTab]->FirstNonFilteredRow(nStartRow, nEndRow);
}
SCROW ScDocument::LastNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return ::std::numeric_limits<SCROW>::max();;
return maTabs[nTab]->LastNonFilteredRow(nStartRow, nEndRow);
}
SCROW ScDocument::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return 0;
return maTabs[nTab]->CountNonFilteredRows(nStartRow, nEndRow);
}
bool ScDocument::IsManualRowHeight(SCROW nRow, SCTAB nTab) const
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return false;
return maTabs[nTab]->IsManualRowHeight(nRow);
}
void ScDocument::SyncColRowFlags()
{
TableContainer::iterator it = maTabs.begin();
for (; it != maTabs.end(); ++it)
{
if (*it)
(*it)->SyncColRowFlags();
}
}
SCROW ScDocument::GetLastFlaggedRow( SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetLastFlaggedRow();
return 0;
}
SCCOL ScDocument::GetLastChangedCol( SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetLastChangedCol();
return 0;
}
SCROW ScDocument::GetLastChangedRow( SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetLastChangedRow();
return 0;
}
SCCOL ScDocument::GetNextDifferentChangedCol( SCTAB nTab, SCCOL nStart) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
{
sal_uInt8 nStartFlags = maTabs[nTab]->GetColFlags(nStart);
sal_uInt16 nStartWidth = maTabs[nTab]->GetOriginalWidth(nStart);
for (SCCOL nCol = nStart + 1; nCol <= MAXCOL; nCol++)
{
if (((nStartFlags & CR_MANUALBREAK) != (maTabs[nTab]->GetColFlags(nCol) & CR_MANUALBREAK)) ||
(nStartWidth != maTabs[nTab]->GetOriginalWidth(nCol)) ||
((nStartFlags & CR_HIDDEN) != (maTabs[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) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return 0;
const ScBitMaskCompressedArray<SCROW, sal_uInt8>* pRowFlagsArray = maTabs[nTab]->GetRowFlagsArray();
if (!pRowFlagsArray)
return 0;
if (!maTabs[nTab]->mpRowHeights || !maTabs[nTab]->mpHiddenRows)
return 0;
size_t nIndex; // ignored
SCROW nFlagsEndRow;
SCROW nHiddenEndRow;
SCROW nHeightEndRow;
sal_uInt8 nFlags;
bool bHidden;
sal_uInt16 nHeight;
sal_uInt8 nStartFlags = nFlags = pRowFlagsArray->GetValue( nStart, nIndex, nFlagsEndRow);
bool bStartHidden = bHidden = maTabs[nTab]->RowHidden( nStart, NULL, &nHiddenEndRow);
sal_uInt16 nStartHeight = nHeight = maTabs[nTab]->GetRowHeight( nStart, NULL, &nHeightEndRow, false);
SCROW nRow;
while ((nRow = std::min( nHiddenEndRow, std::min( nFlagsEndRow, nHeightEndRow)) + 1) <= MAXROW)
{
if (nFlagsEndRow < nRow)
nFlags = pRowFlagsArray->GetValue( nRow, nIndex, nFlagsEndRow);
if (nHiddenEndRow < nRow)
bHidden = maTabs[nTab]->RowHidden( nRow, NULL, &nHiddenEndRow);
if (nHeightEndRow < nRow)
nHeight = maTabs[nTab]->GetRowHeight( nRow, NULL, &nHeightEndRow, false);
if (((nStartFlags & CR_MANUALBREAK) != (nFlags & CR_MANUALBREAK)) ||
((nStartFlags & CR_MANUALSIZE) != (nFlags & CR_MANUALSIZE)) ||
(bStartHidden != bHidden) ||
(bCareManualSize && (nStartFlags & CR_MANUALSIZE) && (nStartHeight != nHeight)) ||
(!bCareManualSize && ((nStartHeight != nHeight))))
return nRow;
}
return MAXROW+1;
}
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 */ )
{
return false;
}
void ScDocument::StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->StripHidden( rX1, rY1, rX2, rY2 );
}
void ScDocument::ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
{
if ( ValidTab(nTab) && maTabs[nTab] )
maTabs[nTab]->ExtendHidden( rX1, rY1, rX2, rY2 );
}
//
// Attribute ----------------------------------------------------------
//
const SfxPoolItem* ScDocument::GetAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
{
const SfxPoolItem* pTemp = maTabs[nTab]->GetAttr( nCol, nRow, nWhich );
if (pTemp)
return pTemp;
else
{
OSL_FAIL( "Attribut Null" );
}
}
return &xPoolHelper->GetDocPool()->GetDefaultItem( nWhich );
}
const ScPatternAttr* ScDocument::GetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetPattern( nCol, nRow );
return NULL;
}
const ScPatternAttr* ScDocument::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetMostUsedPattern( nCol, nStartRow, nEndRow );
return NULL;
}
void ScDocument::ApplyAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem& rAttr )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->ApplyAttr( nCol, nRow, rAttr );
}
void ScDocument::ApplyPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->ApplyPattern( nCol, nRow, rAttr );
}
void ScDocument::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow,
SCCOL nEndCol, SCROW nEndRow,
const ScMarkData& rMark,
const ScPatternAttr& rAttr,
ScEditDataArray* pDataArray )
{
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
if (maTabs[*itr])
maTabs[*itr]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr, pDataArray );
}
void ScDocument::ApplyPatternAreaTab( SCCOL nStartCol, SCROW nStartRow,
SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScPatternAttr& rAttr )
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
if (maTabs[nTab])
maTabs[nTab]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
}
bool ScDocument::SetAttrEntries(SCCOL nCol, SCTAB nTab, ScAttrEntry* pData, SCSIZE nSize)
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return false;
return maTabs[nTab]->SetAttrEntries(nCol, pData, nSize);
}
void ScDocument::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
const ScMarkData& rMark, const ScPatternAttr& rPattern, short nNewType )
{
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
if (maTabs[*itr])
maTabs[*itr]->ApplyPatternIfNumberformatIncompatible( rRange, rPattern, nNewType );
}
void ScDocument::ApplyStyle( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScStyleSheet& rStyle)
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
if (maTabs[nTab])
maTabs[nTab]->ApplyStyle( nCol, nRow, rStyle );
}
void ScDocument::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow,
SCCOL nEndCol, SCROW nEndRow,
const ScMarkData& rMark,
const ScStyleSheet& rStyle)
{
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
if (maTabs[*itr])
maTabs[*itr]->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) && nTab < static_cast<SCTAB>(maTabs.size()))
if (maTabs[nTab])
maTabs[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
{
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
if ( maTabs[*itr] )
maTabs[*itr]->ApplySelectionStyle( rStyle, rMark );
}
}
void ScDocument::ApplySelectionLineStyle( const ScMarkData& rMark,
const SvxBorderLine* pLine, bool bColorOnly )
{
if ( bColorOnly && !pLine )
return;
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
if (maTabs[*itr])
maTabs[*itr]->ApplySelectionLineStyle( rMark, pLine, bColorOnly );
}
const ScStyleSheet* ScDocument::GetStyle( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
{
if ( VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[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() )
{
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
if (maTabs[*itr])
{
pNewStyle = maTabs[*itr]->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 < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i] && rMark.GetTableSelect(i))
{
pNewStyle = maTabs[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 )
{
TableContainer::iterator it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if (*it)
(*it)->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;
TableContainer::const_iterator it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if (*it)
{
if ( (*it)->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, sal_Int16 nFlags )
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
if (maTabs[nTab])
return maTabs[nTab]->ApplyFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
OSL_FAIL("ApplyFlags: falsche Tabelle");
return false;
}
bool ScDocument::RemoveFlagsTab( SCCOL nStartCol, SCROW nStartRow,
SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, sal_Int16 nFlags )
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
if (maTabs[nTab])
return maTabs[nTab]->RemoveFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
OSL_FAIL("RemoveFlags: falsche Tabelle");
return false;
}
void ScDocument::SetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr,
bool bPutToPool )
{
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
if (maTabs[nTab])
maTabs[nTab]->SetPattern( nCol, nRow, rAttr, bPutToPool );
}
void ScDocument::SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr,
bool bPutToPool )
{
SCTAB nTab = rPos.Tab();
if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
maTabs[nTab]->SetPattern( rPos, rAttr, bPutToPool );
}
ScPatternAttr* ScDocument::CreateSelectionPattern( const ScMarkData& rMark, bool bDeep )
{
ScMergePatternState aState;
if ( rMark.IsMultiMarked() ) // multi selection
{
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
if (maTabs[*itr])
maTabs[*itr]->MergeSelectionPattern( aState, rMark, bDeep );
}
if ( rMark.IsMarked() ) // simle selection
{
ScRange aRange;
rMark.GetMarkArea(aRange);
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
if (maTabs[*itr])
maTabs[*itr]->MergePatternArea( aState,
aRange.aStart.Col(), aRange.aStart.Row(),
aRange.aEnd.Col(), aRange.aEnd.Row(), bDeep );
}
OSL_ENSURE( 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() );
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
if (maTabs[*itr])
maTabs[*itr]->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, sal_uInt16 nMask ) const
{
if ( nMask & HASATTR_ROTATE )
{
// Attribut im Dokument ueberhaupt verwendet?
// (wie in fillinfo)
ScDocumentPool* pPool = xPoolHelper->GetDocPool();
bool bAnyItem = false;
sal_uInt32 nRotCount = pPool->GetItemCount2( ATTR_ROTATE_VALUE );
for (sal_uInt32 nItem=0; nItem<nRotCount; nItem++)
{
const SfxPoolItem* pItem = pPool->GetItem2( ATTR_ROTATE_VALUE, nItem );
if ( pItem )
{
// 90 or 270 degrees is former SvxOrientationItem - only look for other values
// (see ScPatternAttr::GetCellOrientation)
sal_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;
sal_uInt32 nDirCount = pPool->GetItemCount2( ATTR_WRITINGDIR );
for (sal_uInt32 nItem=0; nItem<nDirCount; nItem++)
{
const SfxPoolItem* pItem = pPool->GetItem2( 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 < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[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 = maTabs[i]->HasAttrib( nCol1, nRow1, nCol2, nRow2, nMask );
}
return bFound;
}
bool ScDocument::HasAttrib( const ScRange& rRange, sal_uInt16 nMask ) const
{
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) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->FindMaxRotCol( pRowInfo, nArrCount, nX1, nX2 );
else
{
OSL_FAIL("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 );
OSL_ENSURE(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) && nTab < static_cast<SCTAB>(maTabs.size()))
if (maTabs[nTab])
return maTabs[nTab]->IsBlockEmpty( nStartCol, nStartRow, nEndCol, nEndRow, bIgnoreNotes );
OSL_FAIL("Falsche Tabellennummer");
return false;
}
void ScDocument::LockTable(SCTAB nTab)
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->LockTable();
else
{
OSL_FAIL("Falsche Tabellennummer");
}
}
void ScDocument::UnlockTable(SCTAB nTab)
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->UnlockTable();
else
{
OSL_FAIL("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
// TODO: come up with a clean solution for the testing problem
if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && (pShell->IsReadOnly()&&!mbIsInTest) )
{
if ( pOnlyNotBecauseOfMatrix )
*pOnlyNotBecauseOfMatrix = false;
return false;
}
if (VALIDTAB(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
if (maTabs[nTab])
return maTabs[nTab]->IsBlockEditable( nStartCol, nStartRow, nEndCol,
nEndRow, pOnlyNotBecauseOfMatrix );
OSL_FAIL("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 );
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax && (bOk || bMatrix); ++itr)
{
if ( maTabs[*itr] )
{
if (rMark.IsMarked())
{
if ( !maTabs[*itr]->IsBlockEditable( aRange.aStart.Col(),
aRange.aStart.Row(), aRange.aEnd.Col(),
aRange.aEnd.Row(), pOnlyNotBecauseOfMatrix ) )
{
bOk = false;
if ( pOnlyNotBecauseOfMatrix )
bMatrix = *pOnlyNotBecauseOfMatrix;
}
}
if (rMark.IsMultiMarked())
{
if ( !maTabs[*itr]->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;
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax && bOk; ++itr)
if (maTabs[*itr])
if (maTabs[*itr]->HasBlockMatrixFragment( nStartCol, nStartRow, nEndCol, nEndRow ))
bOk = false;
return !bOk;
}
bool ScDocument::HasSelectedBlockMatrixFragment( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, SCTAB nTab ) const
{
bool bOk = true;
if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->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 ) const
{
bool bFound = false;
if ( ValidColRow(rStartCol,rStartRow) && ValidColRow(nEndCol,nEndRow) && ValidTab(nTab) )
{
if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[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 = maTabs[nTab]->aCol[nOldCol].pAttrArray;
SCSIZE nIndex;
pAttrArray->Search( nOldRow, nIndex );
SCROW nAttrPos = nOldRow;
while (nAttrPos<=nEndRow)
{
OSL_ENSURE( 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
{
OSL_FAIL("ExtendOverlapped: falscher Bereich");
}
return bFound;
}
bool ScDocument::ExtendMergeSel( SCCOL nStartCol, SCROW nStartRow,
SCCOL& rEndCol, SCROW& rEndRow,
const ScMarkData& rMark, bool bRefresh )
{
// use all selected sheets from rMark
bool bFound = false;
SCCOL nOldEndCol = rEndCol;
SCROW nOldEndRow = rEndRow;
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
if ( maTabs[*itr] )
{
SCCOL nThisEndCol = nOldEndCol;
SCROW nThisEndRow = nOldEndRow;
if ( ExtendMerge( nStartCol, nStartRow, nThisEndCol, nThisEndRow, *itr, bRefresh ) )
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 bFound = false;
if ( ValidColRow(nStartCol,nStartRow) && ValidColRow(rEndCol,rEndRow) && ValidTab(nTab) )
{
if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
bFound = maTabs[nTab]->ExtendMerge( nStartCol, nStartRow, rEndCol, rEndRow, bRefresh );
if (bRefresh)
RefreshAutoFilter( nStartCol, nStartRow, rEndCol, rEndRow, nTab );
}
else
{
OSL_FAIL("ExtendMerge: falscher Bereich");
}
return bFound;
}
bool ScDocument::ExtendMerge( ScRange& rRange, bool bRefresh )
{
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 < static_cast<SCTAB>(maTabs.size()); nTab++ )
{
SCCOL nExtendCol = rRange.aEnd.Col();
SCROW nExtendRow = rRange.aEnd.Row();
if (ExtendMerge( rRange.aStart.Col(), rRange.aStart.Row(),
nExtendCol, nExtendRow,
nTab, bRefresh ) )
{
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 ) const
{
// Bereich genau dann auf zusammengefasste Zellen erweitern, wenn
// dadurch keine neuen nicht-ueberdeckten Zellen getroffen werden
bool bRet = false;
ScRange aExt = rRange;
// ExtendMerge() is non-const, but called withouth refresh.
if (const_cast<ScDocument*>(this)->ExtendMerge( aExt, false))
{
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 ) const
{
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 < static_cast<SCTAB>(maTabs.size()); 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 )
{
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
const ScDBData* pData = NULL;
ScDBCollection::NamedDBs& rDBs = pDBCollection->getNamedDBs();
ScDBCollection::NamedDBs::const_iterator itr = rDBs.begin(), itrEnd = rDBs.end();
for (; itr != itrEnd; ++itr)
{
pData = &(*itr);
if (itr->HasAutoFilter())
{
itr->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;
}
}
}
if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
pData = maTabs[nTab]->GetAnonymousDBData();
else
pData=NULL;
if (pData)
{
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;
}
void ScDocument::SkipOverlapped( SCCOL& rCol, SCROW& rRow, SCTAB nTab ) const
{
while (IsHorOverlapped(rCol, rRow, nTab))
--rCol;
while (IsVerOverlapped(rCol, rRow, nTab))
--rRow;
}
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
{
OSL_FAIL("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
{
OSL_FAIL("Overlapped: Attr==0");
return false;
}
}
void ScDocument::ApplySelectionFrame( const ScMarkData& rMark,
const SvxBoxItem* pLineOuter,
const SvxBoxInfoItem* pLineInner )
{
ScRangeList aRangeList;
rMark.FillRangeListWithMarks( &aRangeList, false );
size_t nRangeCount = aRangeList.size();
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
{
if (maTabs[*itr])
{
for ( size_t j=0; j < nRangeCount; j++ )
{
ScRange aRange = *aRangeList[ j ];
maTabs[*itr]->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 < static_cast<SCTAB>(maTabs.size()); nTab++)
if (maTabs[nTab])
maTabs[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, ScEditDataArray* pDataArray )
{
const SfxItemSet* pSet = &rAttr.GetItemSet();
bool bSet = false;
sal_uInt16 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, pDataArray );
}
else
{
SfxItemPoolCache aCache( xPoolHelper->GetDocPool(), pSet );
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
if (maTabs[*itr])
maTabs[*itr]->ApplySelectionCache( &aCache, rMark, pDataArray );
}
}
}
void ScDocument::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
{
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
if (maTabs[*itr])
maTabs[*itr]->ChangeSelectionIndent( bIncrement, rMark );
}
void ScDocument::ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark )
{
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
if (maTabs[*itr])
maTabs[*itr]->ClearSelectionItems( pWhich, rMark );
}
void ScDocument::DeleteSelection( sal_uInt16 nDelFlag, const ScMarkData& rMark )
{
SCTAB nMax = static_cast<SCTAB>(maTabs.size());
ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
for (; itr != itrEnd && *itr < nMax; ++itr)
if (maTabs[*itr])
maTabs[*itr]->DeleteSelection( nDelFlag, rMark );
}
void ScDocument::DeleteSelectionTab( SCTAB nTab, sal_uInt16 nDelFlag, const ScMarkData& rMark )
{
if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
maTabs[nTab]->DeleteSelection( nDelFlag, rMark );
else
{
OSL_FAIL("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) && nStartTab < static_cast<SCTAB>(maTabs.size()))
{
if (maTabs[nStartTab])
return maTabs[nStartTab]->GetEmptyLinesInBlock(nStartCol, nStartRow, nEndCol, nEndRow, eDir);
else
return 0;
}
else
return 0;
}
void ScDocument::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, ScMoveDirection eDirection ) const
{
if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
maTabs[nTab]->FindAreaPos( rCol, rRow, eDirection );
}
void ScDocument::GetNextPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY,
bool bMarked, bool bUnprotected, const ScMarkData& rMark ) const
{
OSL_ENSURE( !nMovX || !nMovY, "GetNextPos: nur X oder Y" );
ScMarkData aCopyMark = rMark;
aCopyMark.SetMarking(false);
aCopyMark.MarkToMulti();
if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
maTabs[nTab]->GetNextPos( rCol, rRow, nMovX, nMovY, bMarked, bUnprotected, aCopyMark );
}
//
// Datei-Operationen
//
void ScDocument::UpdStlShtPtrsFrmNms()
{
ScPatternAttr::pDoc = this;
ScDocumentPool* pPool = xPoolHelper->GetDocPool();
sal_uInt32 nCount = pPool->GetItemCount2(ATTR_PATTERN);
ScPatternAttr* pPattern;
for (sal_uInt32 i=0; i<nCount; i++)
{
pPattern = (ScPatternAttr*)pPool->GetItem2(ATTR_PATTERN, i);
if (pPattern)
pPattern->UpdateStyleSheet();
}
((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).UpdateStyleSheet();
}
void ScDocument::StylesToNames()
{
ScPatternAttr::pDoc = this;
ScDocumentPool* pPool = xPoolHelper->GetDocPool();
sal_uInt32 nCount = pPool->GetItemCount2(ATTR_PATTERN);
ScPatternAttr* pPattern;
for (sal_uInt32 i=0; i<nCount; i++)
{
pPattern = (ScPatternAttr*)pPool->GetItem2(ATTR_PATTERN, i);
if (pPattern)
pPattern->StyleToName();
}
((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).StyleToName();
}
sal_uLong ScDocument::GetCellCount() const
{
sal_uLong nCellCount = 0L;
TableContainer::const_iterator it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if ( *it )
nCellCount += (*it)->GetCellCount();
return nCellCount;
}
SCSIZE ScDocument::GetCellCount(SCTAB nTab, SCCOL nCol) const
{
if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
return 0;
return maTabs[nTab]->GetCellCount(nCol);
}
sal_uLong ScDocument::GetCodeCount() const
{
sal_uLong nCodeCount = 0;
TableContainer::const_iterator it = maTabs.begin();
for (; it != maTabs.end(); ++it)
if ( *it )
nCodeCount += (*it)->GetCodeCount();
return nCodeCount;
}
void ScDocument::PageStyleModified( SCTAB nTab, const rtl::OUString& rNewName )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->PageStyleModified( rNewName );
}
void ScDocument::SetPageStyle( SCTAB nTab, const rtl::OUString& rName )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->SetPageStyle( rName );
}
const rtl::OUString ScDocument::GetPageStyle( SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetPageStyle();
return rtl::OUString();
}
void ScDocument::SetPageSize( SCTAB nTab, const Size& rSize )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->SetPageSize( rSize );
}
Size ScDocument::GetPageSize( SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->GetPageSize();
OSL_FAIL("falsche Tab");
return Size();
}
void ScDocument::SetRepeatArea( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->SetRepeatArea( nStartCol, nEndCol, nStartRow, nEndRow );
}
void ScDocument::InvalidatePageBreaks(SCTAB nTab)
{
if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
maTabs[nTab]->InvalidatePageBreaks();
}
void ScDocument::UpdatePageBreaks( SCTAB nTab, const ScRange* pUserArea )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->UpdatePageBreaks( pUserArea );
}
void ScDocument::RemoveManualBreaks( SCTAB nTab )
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
maTabs[nTab]->RemoveManualBreaks();
}
bool ScDocument::HasManualBreaks( SCTAB nTab ) const
{
if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
return maTabs[nTab]->HasManualBreaks();
OSL_FAIL("falsche Tab");
return false;
}
void ScDocument::GetDocStat( ScDocStat& rDocStat )
{
rDocStat.nTableCount = GetTableCount();
rDocStat.aDocName = aDocName;
rDocStat.nCellCount = GetCellCount();
}
bool ScDocument::HasPrintRange()
{
bool bResult = false;
TableContainer::iterator it = maTabs.begin();
for (; it != maTabs.end() && !bResult; ++it)
if ( *it )
bResult = (*it)->IsPrintEntireSheet() || ((*it)->GetPrintRangeCount() > 0);
return bResult;
}
bool ScDocument::IsPrintEntireSheet( SCTAB nTab ) const
{
return (ValidTab(nTab) ) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsPrintEntireSheet();
}
sal_uInt16 ScDocument::GetPrintRangeCount( SCTAB nTab )
{
if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
return maTabs[nTab]->GetPrintRangeCount();
return 0;
}
const ScRange* ScDocument::GetPrintRange( SCTAB nTab, sal_uInt16 nPos )
{
if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
return maTabs[nTab]->GetPrintRange(nPos);
return NULL;
}
const ScRange* ScDocument::GetRepeatColRange( SCTAB nTab )
{
if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
return maTabs[nTab]->GetRepeatColRange();
return NULL;
}
const ScRange* ScDocument::GetRepeatRowRange( SCTAB nTab )
{
if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
return maTabs[nTab]->GetRepeatRowRange();
return NULL;
}
void ScDocument::ClearPrintRanges( SCTAB nTab )
{
if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
maTabs[nTab]->ClearPrintRanges();
}
void ScDocument::AddPrintRange( SCTAB nTab, const ScRange& rNew )
{
if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
maTabs[nTab]->AddPrintRange( rNew );
}
void ScDocument::SetPrintEntireSheet( SCTAB nTab )
{
if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
maTabs[nTab]->SetPrintEntireSheet();
}
void ScDocument::SetRepeatColRange( SCTAB nTab, const ScRange* pNew )
{
if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
maTabs[nTab]->SetRepeatColRange( pNew );
}
void ScDocument::SetRepeatRowRange( SCTAB nTab, const ScRange* pNew )
{
if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
maTabs[nTab]->SetRepeatRowRange( pNew );
}
ScPrintRangeSaver* ScDocument::CreatePrintRangeSaver() const
{
SCTAB nCount = static_cast<SCTAB>(maTabs.size());
ScPrintRangeSaver* pNew = new ScPrintRangeSaver( nCount );
for (SCTAB i=0; i<nCount; i++)
if (maTabs[i])
maTabs[i]->FillPrintSaver( pNew->GetTabData(i) );
return pNew;
}
void ScDocument::RestorePrintRanges( const ScPrintRangeSaver& rSaver )
{
SCTAB nCount = rSaver.GetTabCount();
for (SCTAB i=0; i<nCount && i < static_cast<SCTAB>(maTabs.size()); i++)
if (maTabs[i])
maTabs[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 + 1 < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab+1] )
{
rtl::OUString aNew = maTabs[nTab+1]->GetPageStyle();
if ( aNew != maTabs[nTab]->GetPageStyle() )
{
SfxStyleSheetBase* pStyle = xPoolHelper->GetStylePool()->Find( aNew, SFX_STYLE_FAMILY_PAGE );
if ( pStyle )
{
const SfxItemSet& rSet = pStyle->GetItemSet();
sal_uInt16 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) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
return new ScRowBreakIterator(maTabs[nTab]->maRowPageBreaks);
return NULL;
}
void ScDocument::AddSubTotalCell(ScFormulaCell* pCell)
{
maSubTotalCells.insert(pCell);
}
void ScDocument::RemoveSubTotalCell(ScFormulaCell* pCell)
{
maSubTotalCells.erase(pCell);
}
namespace {
bool lcl_hasDirtyRange(ScFormulaCell* pCell, const ScRange& rDirtyRange)
{
ScDetectiveRefIter aRefIter(pCell);
ScRange aRange;
while (aRefIter.GetNextRef(aRange))
{
if (aRange.Intersects(rDirtyRange))
return true;
}
return false;
}
}
void ScDocument::SetSubTotalCellsDirty(const ScRange& rDirtyRange)
{
// to update the list by skipping cells that no longer contain subtotal function.
set<ScFormulaCell*> aNewSet;
bool bOldRecalc = GetAutoCalc();
SetAutoCalc(false);
set<ScFormulaCell*>::iterator itr = maSubTotalCells.begin(), itrEnd = maSubTotalCells.end();
for (; itr != itrEnd; ++itr)
{
ScFormulaCell* pCell = *itr;
if (pCell->IsSubTotal())
{
aNewSet.insert(pCell);
if (lcl_hasDirtyRange(pCell, rDirtyRange))
pCell->SetDirty();
}
}
SetAutoCalc(bOldRecalc);
maSubTotalCells.swap(aNewSet); // update the list.
}
void ScDocument::EnableUndo( bool bVal )
{
// The undo manager increases lock count every time undo is disabled.
// Because of this, we shouldn't disable undo unless it's currently
// enabled, or else re-enabling it may not actually re-enable undo unless
// the lock count becomes zero.
if (bVal != GetUndoManager()->IsUndoEnabled())
GetUndoManager()->EnableUndo(bVal);
mbUndoEnabled = bVal;
}
bool ScDocument::IsInVBAMode() const
{
if (!pShell)
return false;
try
{
uno::Reference<script::vba::XVBACompatibility> xVBA(
pShell->GetBasicContainer(), uno::UNO_QUERY);
return xVBA.is() && xVBA->getVBACompatibilityMode();
}
catch (const lang::NotInitializedException&) {}
return false;
}
ScNotes* ScDocument::GetNotes(SCTAB nTab)
{
if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
return maTabs[nTab]->GetNotes();
return NULL;
}
void ScDocument::SetAutoNameCache( ScAutoNameCache* pCache )
{
delete pAutoNameCache;
pAutoNameCache = pCache;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */