blob: 3260cc6fcfed31e0aad9d713c4011c31549ced3c [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"
// INCLUDE ---------------------------------------------------------------
#include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
#include "scitems.hxx"
#include <editeng/langitem.hxx>
#include <svl/srchitem.hxx>
#include <sfx2/linkmgr.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/objsh.hxx>
#include <svl/zforlist.hxx>
#include <svl/PasswordHelper.hxx>
#include <vcl/svapp.hxx>
#include "document.hxx"
#include "attrib.hxx"
#include "cell.hxx"
#include "table.hxx"
#include "rangenam.hxx"
#include "dbcolect.hxx"
#include "pivot.hxx"
#include "docpool.hxx"
#include "poolhelp.hxx"
#include "autoform.hxx"
#include "rangelst.hxx"
#include "chartarr.hxx"
#include "chartlock.hxx"
#include "refupdat.hxx"
#include "docoptio.hxx"
#include "viewopti.hxx"
#include "scextopt.hxx"
#include "brdcst.hxx"
#include "bcaslot.hxx"
#include "tablink.hxx"
#include "externalrefmgr.hxx"
#include "markdata.hxx"
#include "validat.hxx"
#include "dociter.hxx"
#include "detdata.hxx"
#include "detfunc.hxx"
#include "scmod.hxx" // SC_MOD
#include "inputopt.hxx" // GetExpandRefs
#include "chartlis.hxx"
#include "sc.hrc" // SID_LINK
#include "hints.hxx"
#include "dpobject.hxx"
#include "unoguard.hxx"
#include "drwlayer.hxx"
#include "unoreflist.hxx"
#include "listenercalls.hxx"
// Wang Xu Ming -- 2009-8-17
// DataPilot Migration - Cache&&Performance
#include "dpshttab.hxx"
#include "dptablecache.hxx"
// End Comments
#include "tabprotection.hxx"
#include "formulaparserpool.hxx"
#include "clipparam.hxx"
#include "sheetevents.hxx"
#include <memory>
using namespace com::sun::star;
//------------------------------------------------------------------------
ScRangeName* ScDocument::GetRangeName()
{
return pRangeName;
}
void ScDocument::SetRangeName( ScRangeName* pNewRangeName )
{
if (pRangeName == pNewRangeName)
return;
if (pRangeName)
delete pRangeName;
pRangeName = pNewRangeName;
}
//UNUSED2008-05 ScRangeData* ScDocument::GetRangeAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab,
//UNUSED2008-05 sal_Bool bStartOnly) const
//UNUSED2008-05 {
//UNUSED2008-05 if ( pRangeName )
//UNUSED2008-05 return pRangeName->GetRangeAtCursor( ScAddress( nCol, nRow, nTab ), bStartOnly );
//UNUSED2008-05 else
//UNUSED2008-05 return NULL;
//UNUSED2008-05 }
ScRangeData* ScDocument::GetRangeAtBlock( const ScRange& rBlock, String* pName ) const
{
ScRangeData* pData = NULL;
if ( pRangeName )
{
pData = pRangeName->GetRangeAtBlock( rBlock );
if (pData && pName)
*pName = pData->GetName();
}
return pData;
}
ScDBCollection* ScDocument::GetDBCollection() const
{
return pDBCollection;
}
void ScDocument::SetDBCollection( ScDBCollection* pNewDBCollection, sal_Bool bRemoveAutoFilter )
{
if ( bRemoveAutoFilter )
{
// remove auto filter attribute if new db data don't contain auto filter flag
// start position is also compared, so bRemoveAutoFilter must not be set from ref-undo!
if ( pDBCollection )
{
sal_uInt16 nOldCount = pDBCollection->GetCount();
for (sal_uInt16 nOld=0; nOld<nOldCount; nOld++)
{
ScDBData* pOldData = (*pDBCollection)[nOld];
if ( pOldData->HasAutoFilter() )
{
ScRange aOldRange;
pOldData->GetArea( aOldRange );
sal_Bool bFound = sal_False;
sal_uInt16 nNewIndex = 0;
if ( pNewDBCollection &&
pNewDBCollection->SearchName( pOldData->GetName(), nNewIndex ) )
{
ScDBData* pNewData = (*pNewDBCollection)[nNewIndex];
if ( pNewData->HasAutoFilter() )
{
ScRange aNewRange;
pNewData->GetArea( aNewRange );
if ( aOldRange.aStart == aNewRange.aStart )
bFound = sal_True;
}
}
if ( !bFound )
{
aOldRange.aEnd.SetRow( aOldRange.aStart.Row() );
RemoveFlagsTab( aOldRange.aStart.Col(), aOldRange.aStart.Row(),
aOldRange.aEnd.Col(), aOldRange.aEnd.Row(),
aOldRange.aStart.Tab(), SC_MF_AUTO );
RepaintRange( aOldRange );
}
}
}
}
}
if (pDBCollection)
delete pDBCollection;
pDBCollection = pNewDBCollection;
}
ScDBData* ScDocument::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_Bool bStartOnly) const
{
if (pDBCollection)
return pDBCollection->GetDBAtCursor(nCol, nRow, nTab, bStartOnly);
else
return NULL;
}
ScDBData* ScDocument::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
{
if (pDBCollection)
return pDBCollection->GetDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2);
else
return NULL;
}
ScDBData* ScDocument::GetFilterDBAtTable(SCTAB nTab) const
{
if (pDBCollection)
return pDBCollection->GetFilterDBAtTable(nTab);
else
return NULL;
}
ScDPCollection* ScDocument::GetDPCollection()
{
if (!pDPCollection)
pDPCollection = new ScDPCollection(this);
return pDPCollection;
}
ScDPObject* ScDocument::GetDPAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab) const
{
if (!pDPCollection)
return NULL;
sal_uInt16 nCount = pDPCollection->GetCount();
ScAddress aPos( nCol, nRow, nTab );
for (sal_uInt16 i=0; i<nCount; i++)
if ( (*pDPCollection)[i]->GetOutRange().In( aPos ) )
return (*pDPCollection)[i];
return NULL;
}
ScDPObject* ScDocument::GetDPAtBlock( const ScRange & rBlock ) const
{
if (!pDPCollection)
return NULL;
/* Walk the collection in reverse order to get something of an
* approximation of MS Excels 'most recent' effect. */
sal_uInt16 i = pDPCollection->GetCount();
while ( i-- > 0 )
if ( (*pDPCollection)[i]->GetOutRange().In( rBlock ) )
return (*pDPCollection)[i];
return NULL;
}
ScChartCollection* ScDocument::GetChartCollection() const
{
return pChartCollection;
}
void ScDocument::StopTemporaryChartLock()
{
if( apTemporaryChartLock.get() )
apTemporaryChartLock->StopLocking();
}
void ScDocument::SetChartListenerCollection(
ScChartListenerCollection* pNewChartListenerCollection,
sal_Bool bSetChartRangeLists )
{
ScChartListenerCollection* pOld = pChartListenerCollection;
pChartListenerCollection = pNewChartListenerCollection;
if ( pChartListenerCollection )
{
if ( pOld )
pChartListenerCollection->SetDiffDirty( *pOld, bSetChartRangeLists );
pChartListenerCollection->StartAllListeners();
}
delete pOld;
}
void ScDocument::SetScenario( SCTAB nTab, sal_Bool bFlag )
{
if (ValidTab(nTab) && pTab[nTab])
pTab[nTab]->SetScenario(bFlag);
}
sal_Bool ScDocument::IsScenario( SCTAB nTab ) const
{
return ValidTab(nTab) && pTab[nTab] &&pTab[nTab]->IsScenario();
//if (ValidTab(nTab) && pTab[nTab])
// return pTab[nTab]->IsScenario();
//return sal_False;
}
void ScDocument::SetScenarioData( SCTAB nTab, const String& rComment,
const Color& rColor, sal_uInt16 nFlags )
{
if (ValidTab(nTab) && pTab[nTab] && pTab[nTab]->IsScenario())
{
pTab[nTab]->SetScenarioComment( rComment );
pTab[nTab]->SetScenarioColor( rColor );
pTab[nTab]->SetScenarioFlags( nFlags );
}
}
Color ScDocument::GetTabBgColor( SCTAB nTab ) const
{
if (ValidTab(nTab) && pTab[nTab])
return pTab[nTab]->GetTabBgColor();
return Color(COL_AUTO);
}
void ScDocument::SetTabBgColor( SCTAB nTab, const Color& rColor )
{
if (ValidTab(nTab) && pTab[nTab])
pTab[nTab]->SetTabBgColor(rColor);
}
bool ScDocument::IsDefaultTabBgColor( SCTAB nTab ) const
{
if (ValidTab(nTab) && pTab[nTab])
return pTab[nTab]->GetTabBgColor() == COL_AUTO;
return true;
}
void ScDocument::GetScenarioData( SCTAB nTab, String& rComment,
Color& rColor, sal_uInt16& rFlags ) const
{
if (ValidTab(nTab) && pTab[nTab] && pTab[nTab]->IsScenario())
{
pTab[nTab]->GetScenarioComment( rComment );
rColor = pTab[nTab]->GetScenarioColor();
rFlags = pTab[nTab]->GetScenarioFlags();
}
}
void ScDocument::GetScenarioFlags( SCTAB nTab, sal_uInt16& rFlags ) const
{
if (VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->IsScenario())
rFlags = pTab[nTab]->GetScenarioFlags();
}
sal_Bool ScDocument::IsLinked( SCTAB nTab ) const
{
return ValidTab(nTab) && pTab[nTab] && pTab[nTab]->IsLinked();
// euqivalent to
//if (ValidTab(nTab) && pTab[nTab])
// return pTab[nTab]->IsLinked();
//return sal_False;
}
formula::FormulaGrammar::AddressConvention ScDocument::GetAddressConvention() const
{
return formula::FormulaGrammar::extractRefConvention(eGrammar);
}
formula::FormulaGrammar::Grammar ScDocument::GetGrammar() const
{
return eGrammar;
}
void ScDocument::SetGrammar( formula::FormulaGrammar::Grammar eGram )
{
eGrammar = eGram;
}
sal_Bool ScDocument::GetLinkMode( SCTAB nTab ) const
{
if (ValidTab(nTab) && pTab[nTab])
return pTab[nTab]->GetLinkMode();
return SC_LINK_NONE;
}
const String& ScDocument::GetLinkDoc( SCTAB nTab ) const
{
if (ValidTab(nTab) && pTab[nTab])
return pTab[nTab]->GetLinkDoc();
return EMPTY_STRING;
}
const String& ScDocument::GetLinkFlt( SCTAB nTab ) const
{
if (ValidTab(nTab) && pTab[nTab])
return pTab[nTab]->GetLinkFlt();
return EMPTY_STRING;
}
const String& ScDocument::GetLinkOpt( SCTAB nTab ) const
{
if (ValidTab(nTab) && pTab[nTab])
return pTab[nTab]->GetLinkOpt();
return EMPTY_STRING;
}
const String& ScDocument::GetLinkTab( SCTAB nTab ) const
{
if (ValidTab(nTab) && pTab[nTab])
return pTab[nTab]->GetLinkTab();
return EMPTY_STRING;
}
sal_uLong ScDocument::GetLinkRefreshDelay( SCTAB nTab ) const
{
if (ValidTab(nTab) && pTab[nTab])
return pTab[nTab]->GetLinkRefreshDelay();
return 0;
}
void ScDocument::SetLink( SCTAB nTab, sal_uInt8 nMode, const String& rDoc,
const String& rFilter, const String& rOptions,
const String& rTabName, sal_uLong nRefreshDelay )
{
if (ValidTab(nTab) && pTab[nTab])
pTab[nTab]->SetLink( nMode, rDoc, rFilter, rOptions, rTabName, nRefreshDelay );
}
sal_Bool ScDocument::HasLink( const String& rDoc,
const String& rFilter, const String& rOptions ) const
{
SCTAB nCount = GetTableCount();
for (SCTAB i=0; i<nCount; i++)
if (pTab[i]->IsLinked()
&& pTab[i]->GetLinkDoc() == rDoc
&& pTab[i]->GetLinkFlt() == rFilter
&& pTab[i]->GetLinkOpt() == rOptions)
return sal_True;
return sal_False;
}
sal_Bool ScDocument::LinkExternalTab( SCTAB& rTab, const String& aDocTab,
const String& aFileName, const String& aTabName )
{
if ( IsClipboard() )
{
DBG_ERRORFILE( "LinkExternalTab in Clipboard" );
return sal_False;
}
rTab = 0;
String aFilterName; // wird vom Loader gefuellt
String aOptions; // Filter-Optionen
sal_uInt32 nLinkCnt = pExtDocOptions ? pExtDocOptions->GetDocSettings().mnLinkCnt : 0;
ScDocumentLoader aLoader( aFileName, aFilterName, aOptions, nLinkCnt + 1 );
if ( aLoader.IsError() )
return sal_False;
ScDocument* pSrcDoc = aLoader.GetDocument();
// Tabelle kopieren
SCTAB nSrcTab;
if ( pSrcDoc->GetTable( aTabName, nSrcTab ) )
{
if ( !InsertTab( SC_TAB_APPEND, aDocTab, sal_True ) )
{
DBG_ERRORFILE("can't insert external document table");
return sal_False;
}
rTab = GetTableCount() - 1;
// nicht neu einfuegen, nur Ergebnisse
TransferTab( pSrcDoc, nSrcTab, rTab, sal_False, sal_True );
}
else
return sal_False;
sal_uLong nRefreshDelay = 0;
sal_Bool bWasThere = HasLink( aFileName, aFilterName, aOptions );
SetLink( rTab, SC_LINK_VALUE, aFileName, aFilterName, aOptions, aTabName, nRefreshDelay );
if ( !bWasThere ) // Link pro Quelldokument nur einmal eintragen
{
ScTableLink* pLink = new ScTableLink( pShell, aFileName, aFilterName, aOptions, nRefreshDelay );
pLink->SetInCreate( sal_True );
GetLinkManager()->InsertFileLink( *pLink, OBJECT_CLIENT_FILE, aFileName,
&aFilterName );
pLink->Update();
pLink->SetInCreate( sal_False );
SfxBindings* pBindings = GetViewBindings();
if (pBindings)
pBindings->Invalidate( SID_LINKS );
}
return sal_True;
}
ScExternalRefManager* ScDocument::GetExternalRefManager() const
{
ScDocument* pThis = const_cast<ScDocument*>(this);
if (!pExternalRefMgr.get())
pThis->pExternalRefMgr.reset( new ScExternalRefManager( pThis));
return pExternalRefMgr.get();
}
bool ScDocument::IsInExternalReferenceMarking() const
{
return pExternalRefMgr.get() && pExternalRefMgr->isInReferenceMarking();
}
void ScDocument::MarkUsedExternalReferences()
{
if (!pExternalRefMgr.get())
return;
if (!pExternalRefMgr->hasExternalData())
return;
// Charts.
bool bAllMarked = pExternalRefMgr->markUsedByLinkListeners();
// Formula cells.
bAllMarked = pExternalRefMgr->markUsedExternalRefCells();
/* NOTE: Conditional formats and validation objects are marked when
* collecting them during export. */
}
ScFormulaParserPool& ScDocument::GetFormulaParserPool() const
{
if( !mxFormulaParserPool.get() )
mxFormulaParserPool.reset( new ScFormulaParserPool( *this ) );
return *mxFormulaParserPool;
}
const ScSheetEvents* ScDocument::GetSheetEvents( SCTAB nTab ) const
{
if (VALIDTAB(nTab) && pTab[nTab])
return pTab[nTab]->GetSheetEvents();
return NULL;
}
void ScDocument::SetSheetEvents( SCTAB nTab, const ScSheetEvents* pNew )
{
if (VALIDTAB(nTab) && pTab[nTab])
pTab[nTab]->SetSheetEvents( pNew );
}
bool ScDocument::HasSheetEventScript( SCTAB nTab, sal_Int32 nEvent, bool bWithVbaEvents ) const
{
if (pTab[nTab])
{
// check if any event handler script has been configured
const ScSheetEvents* pEvents = pTab[nTab]->GetSheetEvents();
if ( pEvents && pEvents->GetScript( nEvent ) )
return true;
// check if VBA event handlers exist
if (bWithVbaEvents && mxVbaEvents.is()) try
{
uno::Sequence< uno::Any > aArgs( 1 );
aArgs[ 0 ] <<= nTab;
if (mxVbaEvents->hasVbaEventHandler( ScSheetEvents::GetVbaSheetEventId( nEvent ), aArgs ) ||
mxVbaEvents->hasVbaEventHandler( ScSheetEvents::GetVbaDocumentEventId( nEvent ), uno::Sequence< uno::Any >() ))
return true;
}
catch( uno::Exception& )
{
}
}
return false;
}
bool ScDocument::HasAnySheetEventScript( sal_Int32 nEvent, bool bWithVbaEvents ) const
{
for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
if (HasSheetEventScript( nTab, nEvent, bWithVbaEvents ))
return true;
return false;
}
bool ScDocument::HasAnyCalcNotification() const
{
for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
if (pTab[nTab] && pTab[nTab]->GetCalcNotification())
return true;
return false;
}
sal_Bool ScDocument::HasCalcNotification( SCTAB nTab ) const
{
if (VALIDTAB(nTab) && pTab[nTab])
return pTab[nTab]->GetCalcNotification();
return sal_False;
}
void ScDocument::SetCalcNotification( SCTAB nTab )
{
// set only if not set before
if (VALIDTAB(nTab) && pTab[nTab] && !pTab[nTab]->GetCalcNotification())
pTab[nTab]->SetCalcNotification(sal_True);
}
void ScDocument::ResetCalcNotifications()
{
for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
if (pTab[nTab] && pTab[nTab]->GetCalcNotification())
pTab[nTab]->SetCalcNotification(sal_False);
}
ScOutlineTable* ScDocument::GetOutlineTable( SCTAB nTab, sal_Bool bCreate )
{
ScOutlineTable* pVal = NULL;
if (VALIDTAB(nTab))
if (pTab[nTab])
{
pVal = pTab[nTab]->GetOutlineTable();
if (!pVal)
if (bCreate)
{
pTab[nTab]->StartOutlineTable();
pVal = pTab[nTab]->GetOutlineTable();
}
}
return pVal;
}
sal_Bool ScDocument::SetOutlineTable( SCTAB nTab, const ScOutlineTable* pNewOutline )
{
return VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->SetOutlineTable(pNewOutline);
//if (VALIDTAB(nTab))
// if (pTab[nTab])
// return pTab[nTab]->SetOutlineTable(pNewOutline);
//return sal_False;
}
void ScDocument::DoAutoOutline( SCCOL nStartCol, SCROW nStartRow,
SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
{
if (VALIDTAB(nTab) && pTab[nTab])
pTab[nTab]->DoAutoOutline( nStartCol, nStartRow, nEndCol, nEndRow );
}
sal_Bool ScDocument::TestRemoveSubTotals( SCTAB nTab, const ScSubTotalParam& rParam )
{
return VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->TestRemoveSubTotals( rParam );
//if (VALIDTAB(nTab) && pTab[nTab] )
// return pTab[nTab]->TestRemoveSubTotals( rParam );
//return sal_False;
}
void ScDocument::RemoveSubTotals( SCTAB nTab, ScSubTotalParam& rParam )
{
if ( VALIDTAB(nTab) && pTab[nTab] )
pTab[nTab]->RemoveSubTotals( rParam );
}
sal_Bool ScDocument::DoSubTotals( SCTAB nTab, ScSubTotalParam& rParam )
{
return VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->DoSubTotals( rParam );
//if (VALIDTAB(nTab))
// if (pTab[nTab])
// return pTab[nTab]->DoSubTotals( rParam );
//return sal_False;
}
sal_Bool ScDocument::HasSubTotalCells( const ScRange& rRange )
{
ScCellIterator aIter( this, rRange );
ScBaseCell* pCell = aIter.GetFirst();
while (pCell)
{
if ( pCell->GetCellType() == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell)->IsSubTotal() )
return sal_True;
pCell = aIter.GetNext();
}
return sal_False; // none found
}
// kopiert aus diesem Dokument die Zellen von Positionen, an denen in pPosDoc
// auch Zellen stehen, nach pDestDoc
void ScDocument::CopyUpdated( ScDocument* pPosDoc, ScDocument* pDestDoc )
{
SCTAB nCount = GetTableCount();
for (SCTAB nTab=0; nTab<nCount; nTab++)
if (pTab[nTab] && pPosDoc->pTab[nTab] && pDestDoc->pTab[nTab])
pTab[nTab]->CopyUpdated( pPosDoc->pTab[nTab], pDestDoc->pTab[nTab] );
}
void ScDocument::CopyScenario( SCTAB nSrcTab, SCTAB nDestTab, sal_Bool bNewScenario )
{
if (ValidTab(nSrcTab) && ValidTab(nDestTab) && pTab[nSrcTab] && pTab[nDestTab])
{
// Flags fuer aktive Szenarios richtig setzen
// und aktuelle Werte in bisher aktive Szenarios zurueckschreiben
ScRangeList aRanges = *pTab[nSrcTab]->GetScenarioRanges();
const sal_uLong nRangeCount = aRanges.Count();
// nDestTab ist die Zieltabelle
for ( SCTAB nTab = nDestTab+1;
nTab<=MAXTAB && pTab[nTab] && pTab[nTab]->IsScenario();
nTab++ )
{
if ( pTab[nTab]->IsActiveScenario() ) // auch wenn's dasselbe Szenario ist
{
sal_Bool bTouched = sal_False;
for ( sal_uLong nR=0; nR<nRangeCount && !bTouched; nR++)
{
const ScRange* pRange = aRanges.GetObject(nR);
if ( pTab[nTab]->HasScenarioRange( *pRange ) )
bTouched = sal_True;
}
if (bTouched)
{
pTab[nTab]->SetActiveScenario(sal_False);
if ( pTab[nTab]->GetScenarioFlags() & SC_SCENARIO_TWOWAY )
pTab[nTab]->CopyScenarioFrom( pTab[nDestTab] );
}
}
}
pTab[nSrcTab]->SetActiveScenario(sal_True); // da kommt's her...
if (!bNewScenario) // Daten aus dem ausgewaehlten Szenario kopieren
{
sal_Bool bOldAutoCalc = GetAutoCalc();
SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden
pTab[nSrcTab]->CopyScenarioTo( pTab[nDestTab] );
SetDirty();
SetAutoCalc( bOldAutoCalc );
}
}
}
void ScDocument::MarkScenario( SCTAB nSrcTab, SCTAB nDestTab, ScMarkData& rDestMark,
sal_Bool bResetMark, sal_uInt16 nNeededBits ) const
{
if (bResetMark)
rDestMark.ResetMark();
if (ValidTab(nSrcTab) && pTab[nSrcTab])
pTab[nSrcTab]->MarkScenarioIn( rDestMark, nNeededBits );
rDestMark.SetAreaTab( nDestTab );
}
sal_Bool ScDocument::HasScenarioRange( SCTAB nTab, const ScRange& rRange ) const
{
return ValidTab(nTab) && pTab[nTab] && pTab[nTab]->HasScenarioRange( rRange );
//if (ValidTab(nTab) && pTab[nTab])
// return pTab[nTab]->HasScenarioRange( rRange );
//return sal_False;
}
const ScRangeList* ScDocument::GetScenarioRanges( SCTAB nTab ) const
{
if (ValidTab(nTab) && pTab[nTab])
return pTab[nTab]->GetScenarioRanges();
return NULL;
}
sal_Bool ScDocument::IsActiveScenario( SCTAB nTab ) const
{
return ValidTab(nTab) && pTab[nTab] && pTab[nTab]->IsActiveScenario( );
//if (ValidTab(nTab) && pTab[nTab])
// return pTab[nTab]->IsActiveScenario();
//return sal_False;
}
void ScDocument::SetActiveScenario( SCTAB nTab, sal_Bool bActive )
{
if (ValidTab(nTab) && pTab[nTab])
pTab[nTab]->SetActiveScenario( bActive );
}
sal_Bool ScDocument::TestCopyScenario( SCTAB nSrcTab, SCTAB nDestTab ) const
{
if (ValidTab(nSrcTab) && ValidTab(nDestTab))
return pTab[nSrcTab]->TestCopyScenarioTo( pTab[nDestTab] );
DBG_ERROR("falsche Tabelle bei TestCopyScenario");
return sal_False;
}
void ScDocument::AddUnoObject( SfxListener& rObject )
{
if (!pUnoBroadcaster)
pUnoBroadcaster = new SfxBroadcaster;
rObject.StartListening( *pUnoBroadcaster );
}
void ScDocument::RemoveUnoObject( SfxListener& rObject )
{
if (pUnoBroadcaster)
{
rObject.EndListening( *pUnoBroadcaster );
if ( bInUnoBroadcast )
{
// #107294# Broadcasts from ScDocument::BroadcastUno are the only way that
// uno object methods are called without holding a reference.
//
// If RemoveUnoObject is called from an object dtor in the finalizer thread
// while the main thread is calling BroadcastUno, the dtor thread must wait
// (or the object's Notify might try to access a deleted object).
// The SolarMutex can't be locked here because if a component is called from
// a VCL event, the main thread has the SolarMutex locked all the time.
//
// This check is done after calling EndListening, so a later BroadcastUno call
// won't touch this object.
vos::IMutex& rSolarMutex = Application::GetSolarMutex();
if ( rSolarMutex.tryToAcquire() )
{
// BroadcastUno is always called with the SolarMutex locked, so if it
// can be acquired, this is within the same thread (should not happen)
DBG_ERRORFILE( "RemoveUnoObject called from BroadcastUno" );
rSolarMutex.release();
}
else
{
// let the thread that called BroadcastUno continue
while ( bInUnoBroadcast )
{
vos::OThread::yield();
}
}
}
}
else
{
DBG_ERROR("No Uno broadcaster");
}
}
void ScDocument::BroadcastUno( const SfxHint &rHint )
{
if (pUnoBroadcaster)
{
bInUnoBroadcast = sal_True;
pUnoBroadcaster->Broadcast( rHint );
bInUnoBroadcast = sal_False;
// During Broadcast notification, Uno objects can add to pUnoListenerCalls.
// The listener calls must be processed after completing the broadcast,
// because they can add or remove objects from pUnoBroadcaster.
if ( pUnoListenerCalls && rHint.ISA( SfxSimpleHint ) &&
((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DATACHANGED &&
!bInUnoListenerCall )
{
// Listener calls may lead to BroadcastUno calls again. The listener calls
// are not nested, instead the calls are collected in the list, and the
// outermost call executes them all.
ScChartLockGuard aChartLockGuard(this);
bInUnoListenerCall = sal_True;
pUnoListenerCalls->ExecuteAndClear();
bInUnoListenerCall = sal_False;
}
}
}
void ScDocument::AddUnoListenerCall( const uno::Reference<util::XModifyListener>& rListener,
const lang::EventObject& rEvent )
{
DBG_ASSERT( bInUnoBroadcast, "AddUnoListenerCall is supposed to be called from BroadcastUno only" );
if ( !pUnoListenerCalls )
pUnoListenerCalls = new ScUnoListenerCalls;
pUnoListenerCalls->Add( rListener, rEvent );
}
void ScDocument::BeginUnoRefUndo()
{
DBG_ASSERT( !pUnoRefUndoList, "BeginUnoRefUndo twice" );
delete pUnoRefUndoList;
pUnoRefUndoList = new ScUnoRefList;
}
ScUnoRefList* ScDocument::EndUnoRefUndo()
{
ScUnoRefList* pRet = pUnoRefUndoList;
pUnoRefUndoList = NULL;
return pRet; // must be deleted by caller!
}
void ScDocument::AddUnoRefChange( sal_Int64 nId, const ScRangeList& rOldRanges )
{
if ( pUnoRefUndoList )
pUnoRefUndoList->Add( nId, rOldRanges );
}
sal_Int64 ScDocument::GetNewUnoId()
{
return ++nUnoObjectId;
}
void ScDocument::UpdateReference( UpdateRefMode eUpdateRefMode,
SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
ScDocument* pUndoDoc, sal_Bool bIncludeDraw,
bool bUpdateNoteCaptionPos )
{
PutInOrder( nCol1, nCol2 );
PutInOrder( nRow1, nRow2 );
PutInOrder( nTab1, nTab2 );
if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
{
sal_Bool bExpandRefsOld = IsExpandRefs();
if ( eUpdateRefMode == URM_INSDEL && (nDx > 0 || nDy > 0 || nDz > 0) )
SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() );
SCTAB i;
SCTAB iMax;
if ( eUpdateRefMode == URM_COPY )
{
i = nTab1;
iMax = nTab2;
}
else
{
ScRange aRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
xColNameRanges->UpdateReference( eUpdateRefMode, this, aRange, nDx, nDy, nDz );
xRowNameRanges->UpdateReference( eUpdateRefMode, this, aRange, nDx, nDy, nDz );
pDBCollection->UpdateReference( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz );
pRangeName->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
if ( pDPCollection )
pDPCollection->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
UpdateChartRef( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz );
UpdateRefAreaLinks( eUpdateRefMode, aRange, nDx, nDy, nDz );
if ( pCondFormList )
pCondFormList->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
if ( pValidationList )
pValidationList->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
if ( pDetOpList )
pDetOpList->UpdateReference( this, eUpdateRefMode, aRange, nDx, nDy, nDz );
if ( pUnoBroadcaster )
pUnoBroadcaster->Broadcast( ScUpdateRefHint(
eUpdateRefMode, aRange, nDx, nDy, nDz ) );
i = 0;
iMax = MAXTAB;
}
for ( ; i<=iMax; i++)
if (pTab[i])
pTab[i]->UpdateReference(
eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2,
nDx, nDy, nDz, pUndoDoc, bIncludeDraw, bUpdateNoteCaptionPos );
if ( bIsEmbedded )
{
SCCOL theCol1;
SCROW theRow1;
SCTAB theTab1;
SCCOL theCol2;
SCROW theRow2;
SCTAB theTab2;
theCol1 = aEmbedRange.aStart.Col();
theRow1 = aEmbedRange.aStart.Row();
theTab1 = aEmbedRange.aStart.Tab();
theCol2 = aEmbedRange.aEnd.Col();
theRow2 = aEmbedRange.aEnd.Row();
theTab2 = aEmbedRange.aEnd.Tab();
if ( ScRefUpdate::Update( this, eUpdateRefMode, nCol1,nRow1,nTab1, nCol2,nRow2,nTab2,
nDx,nDy,nDz, theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) )
{
aEmbedRange = ScRange( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
}
}
SetExpandRefs( bExpandRefsOld );
// #30428# after moving, no clipboard move ref-updates are possible
if ( eUpdateRefMode != URM_COPY && IsClipboardSource() )
{
ScDocument* pClipDoc = SC_MOD()->GetClipDoc();
if (pClipDoc)
pClipDoc->GetClipParam().mbCutMode = false;
}
}
}
void ScDocument::UpdateTranspose( const ScAddress& rDestPos, ScDocument* pClipDoc,
const ScMarkData& rMark, ScDocument* pUndoDoc )
{
DBG_ASSERT(pClipDoc->bIsClip, "UpdateTranspose: kein Clip");
ScRange aSource;
ScClipParam& rClipParam = GetClipParam();
if (rClipParam.maRanges.Count())
aSource = *rClipParam.maRanges.First();
ScAddress aDest = rDestPos;
SCTAB nClipTab = 0;
for (SCTAB nDestTab=0; nDestTab<=MAXTAB && pTab[nDestTab]; nDestTab++)
if (rMark.GetTableSelect(nDestTab))
{
while (!pClipDoc->pTab[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
aSource.aStart.SetTab( nClipTab );
aSource.aEnd.SetTab( nClipTab );
aDest.SetTab( nDestTab );
// wie UpdateReference
pRangeName->UpdateTranspose( aSource, aDest ); // vor den Zellen!
for (SCTAB i=0; i<=MAXTAB; i++)
if (pTab[i])
pTab[i]->UpdateTranspose( aSource, aDest, pUndoDoc );
nClipTab = (nClipTab+1) % (MAXTAB+1);
}
}
void ScDocument::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
{
//! pDBCollection
//! pPivotCollection
//! UpdateChartRef
pRangeName->UpdateGrow( rArea, nGrowX, nGrowY );
for (SCTAB i=0; i<=MAXTAB && pTab[i]; i++)
pTab[i]->UpdateGrow( rArea, nGrowX, nGrowY );
}
void ScDocument::Fill(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const ScMarkData& rMark,
sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
double nStepValue, double nMaxValue)
{
PutInOrder( nCol1, nCol2 );
PutInOrder( nRow1, nRow2 );
for (SCTAB i=0; i <= MAXTAB; i++)
if (pTab[i])
if (rMark.GetTableSelect(i))
pTab[i]->Fill(nCol1, nRow1, nCol2, nRow2,
nFillCount, eFillDir, eFillCmd, eFillDateCmd,
nStepValue, nMaxValue);
}
String ScDocument::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW nEndY )
{
SCTAB nTab = rSource.aStart.Tab();
if (pTab[nTab])
return pTab[nTab]->GetAutoFillPreview( rSource, nEndX, nEndY );
return EMPTY_STRING;
}
void ScDocument::AutoFormat( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
sal_uInt16 nFormatNo, const ScMarkData& rMark )
{
PutInOrder( nStartCol, nEndCol );
PutInOrder( nStartRow, nEndRow );
for (SCTAB i=0; i <= MAXTAB; i++)
if (pTab[i])
if (rMark.GetTableSelect(i))
pTab[i]->AutoFormat( nStartCol, nStartRow, nEndCol, nEndRow, nFormatNo );
}
void ScDocument::GetAutoFormatData(SCTAB nTab, SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
ScAutoFormatData& rData)
{
if (VALIDTAB(nTab))
{
if (pTab[nTab])
{
PutInOrder(nStartCol, nEndCol);
PutInOrder(nStartRow, nEndRow);
pTab[nTab]->GetAutoFormatData(nStartCol, nStartRow, nEndCol, nEndRow, rData);
}
}
}
// static
void ScDocument::GetSearchAndReplaceStart( const SvxSearchItem& rSearchItem,
SCCOL& rCol, SCROW& rRow )
{
sal_uInt16 nCommand = rSearchItem.GetCommand();
sal_Bool bReplace = ( nCommand == SVX_SEARCHCMD_REPLACE ||
nCommand == SVX_SEARCHCMD_REPLACE_ALL );
if ( rSearchItem.GetBackward() )
{
if ( rSearchItem.GetRowDirection() )
{
if ( rSearchItem.GetPattern() )
{
rCol = MAXCOL;
rRow = MAXROW+1;
}
else if ( bReplace )
{
rCol = MAXCOL;
rRow = MAXROW;
}
else
{
rCol = MAXCOL+1;
rRow = MAXROW;
}
}
else
{
if ( rSearchItem.GetPattern() )
{
rCol = MAXCOL+1;
rRow = MAXROW;
}
else if ( bReplace )
{
rCol = MAXCOL;
rRow = MAXROW;
}
else
{
rCol = MAXCOL;
rRow = MAXROW+1;
}
}
}
else
{
if ( rSearchItem.GetRowDirection() )
{
if ( rSearchItem.GetPattern() )
{
rCol = 0;
rRow = (SCROW) -1;
}
else if ( bReplace )
{
rCol = 0;
rRow = 0;
}
else
{
rCol = (SCCOL) -1;
rRow = 0;
}
}
else
{
if ( rSearchItem.GetPattern() )
{
rCol = (SCCOL) -1;
rRow = 0;
}
else if ( bReplace )
{
rCol = 0;
rRow = 0;
}
else
{
rCol = 0;
rRow = (SCROW) -1;
}
}
}
}
sal_Bool ScDocument::SearchAndReplace(const SvxSearchItem& rSearchItem,
SCCOL& rCol, SCROW& rRow, SCTAB& rTab,
ScMarkData& rMark,
String& rUndoStr, ScDocument* pUndoDoc)
{
//! getrennte Markierungen pro Tabelle verwalten !!!!!!!!!!!!!
rMark.MarkToMulti();
sal_Bool bFound = sal_False;
if (VALIDTAB(rTab))
{
SCCOL nCol;
SCROW nRow;
SCTAB nTab;
sal_uInt16 nCommand = rSearchItem.GetCommand();
if ( nCommand == SVX_SEARCHCMD_FIND_ALL ||
nCommand == SVX_SEARCHCMD_REPLACE_ALL )
{
for (nTab = 0; nTab <= MAXTAB; nTab++)
if (pTab[nTab])
{
if (rMark.GetTableSelect(nTab))
{
nCol = 0;
nRow = 0;
bFound |= pTab[nTab]->SearchAndReplace(
rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc );
}
}
// Markierung wird innen schon komplett gesetzt
}
else
{
nCol = rCol;
nRow = rRow;
if (rSearchItem.GetBackward())
{
for (nTab = rTab; ((SCsTAB)nTab >= 0) && !bFound; nTab--)
if (pTab[nTab])
{
if (rMark.GetTableSelect(nTab))
{
bFound = pTab[nTab]->SearchAndReplace(
rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc );
if (bFound)
{
rCol = nCol;
rRow = nRow;
rTab = nTab;
}
else
ScDocument::GetSearchAndReplaceStart(
rSearchItem, nCol, nRow );
}
}
}
else
{
for (nTab = rTab; (nTab <= MAXTAB) && !bFound; nTab++)
if (pTab[nTab])
{
if (rMark.GetTableSelect(nTab))
{
bFound = pTab[nTab]->SearchAndReplace(
rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc );
if (bFound)
{
rCol = nCol;
rRow = nRow;
rTab = nTab;
}
else
ScDocument::GetSearchAndReplaceStart(
rSearchItem, nCol, nRow );
}
}
}
}
}
return bFound;
}
// Outline anpassen
sal_Bool ScDocument::UpdateOutlineCol( SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, sal_Bool bShow )
{
if ( ValidTab(nTab) && pTab[nTab] )
return pTab[nTab]->UpdateOutlineCol( nStartCol, nEndCol, bShow );
DBG_ERROR("missing tab");
return sal_False;
}
sal_Bool ScDocument::UpdateOutlineRow( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_Bool bShow )
{
if ( ValidTab(nTab) && pTab[nTab] )
return pTab[nTab]->UpdateOutlineRow( nStartRow, nEndRow, bShow );
DBG_ERROR("missing tab");
return sal_False;
}
void ScDocument::Sort(SCTAB nTab, const ScSortParam& rSortParam, sal_Bool bKeepQuery)
{
if ( ValidTab(nTab) && pTab[nTab] )
{
sal_Bool bOldDisableIdle = IsIdleDisabled();
DisableIdle( sal_True );
pTab[nTab]->Sort(rSortParam, bKeepQuery);
DisableIdle( bOldDisableIdle );
}
}
SCSIZE ScDocument::Query(SCTAB nTab, const ScQueryParam& rQueryParam, sal_Bool bKeepSub)
{
if ( ValidTab(nTab) && pTab[nTab] )
return pTab[nTab]->Query((ScQueryParam&)rQueryParam, bKeepSub);
DBG_ERROR("missing tab");
return 0;
}
sal_Bool ScDocument::ValidQuery( SCROW nRow, SCTAB nTab, const ScQueryParam& rQueryParam, sal_Bool* pSpecial )
{
if ( ValidTab(nTab) && pTab[nTab] )
return pTab[nTab]->ValidQuery( nRow, rQueryParam, pSpecial );
DBG_ERROR("missing tab");
return sal_False;
}
void ScDocument::GetUpperCellString(SCCOL nCol, SCROW nRow, SCTAB nTab, String& rStr)
{
if ( ValidTab(nTab) && pTab[nTab] )
pTab[nTab]->GetUpperCellString( nCol, nRow, rStr );
else
rStr.Erase();
}
sal_Bool ScDocument::CreateQueryParam(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCTAB nTab, ScQueryParam& rQueryParam)
{
if ( ValidTab(nTab) && pTab[nTab] )
return pTab[nTab]->CreateQueryParam(nCol1, nRow1, nCol2, nRow2, rQueryParam);
DBG_ERROR("missing tab");
return sal_False;
}
sal_Bool ScDocument::HasAutoFilter(
const SCCOL nCurCol,
const SCROW nCurRow,
const SCTAB nCurTab )
{
ScDBData* pDBData = GetDBAtCursor( nCurCol, nCurRow, nCurTab );
sal_Bool bHasAutoFilter = ( pDBData != NULL );
if ( pDBData )
{
if ( pDBData->HasHeader() )
{
SCCOL nCol;
SCROW nRow;
sal_Int16 nFlag;
ScQueryParam aParam;
pDBData->GetQueryParam( aParam );
nRow = aParam.nRow1;
for ( nCol=aParam.nCol1; nCol<=aParam.nCol2 && bHasAutoFilter; nCol++ )
{
nFlag = ((ScMergeFlagAttr*)
GetAttr( nCol, nRow, nCurTab, ATTR_MERGE_FLAG ))->
GetValue();
if ( (nFlag & SC_MF_AUTO) == 0 )
bHasAutoFilter = sal_False;
}
}
else
bHasAutoFilter = sal_False;
}
return bHasAutoFilter;
}
sal_Bool ScDocument::HasColHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
SCTAB nTab )
{
return VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->HasColHeader( nStartCol, nStartRow, nEndCol, nEndRow );
//if (VALIDTAB(nTab))
// if (pTab[nTab])
// return pTab[nTab]->HasColHeader( nStartCol, nStartRow, nEndCol, nEndRow );
//return sal_False;
}
sal_Bool ScDocument::HasRowHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
SCTAB nTab )
{
return VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->HasRowHeader( nStartCol, nStartRow, nEndCol, nEndRow );
//if (VALIDTAB(nTab))
// if (pTab[nTab])
// return pTab[nTab]->HasRowHeader( nStartCol, nStartRow, nEndCol, nEndRow );
//return sal_False;
}
//
// GetFilterEntries - Eintraege fuer AutoFilter-Listbox
//
sal_Bool ScDocument::GetFilterEntries(
SCCOL nCol, SCROW nRow, SCTAB nTab, bool bFilter, TypedScStrCollection& rStrings, bool& rHasDates)
{
if ( ValidTab(nTab) && pTab[nTab] && pDBCollection )
{
ScDBData* pDBData = pDBCollection->GetDBAtCursor(nCol, nRow, nTab, sal_False); //!??
if (pDBData)
{
SCTAB nAreaTab;
SCCOL nStartCol;
SCROW nStartRow;
SCCOL nEndCol;
SCROW nEndRow;
pDBData->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow );
//Add for i85305
SCCOL nTmpStartCol = nCol;
SCROW nTmpStartRow = nRow;
SCCOL nTmpEndCol = nCol;
SCROW nTmpEndRow = nRow;
GetDataArea( nTab, nTmpStartCol, nTmpStartRow, nTmpEndCol, nTmpEndRow, sal_False, false);
if (nTmpEndRow > nEndRow)
{
nEndRow = nTmpEndRow;
pDBData->SetArea(nAreaTab, nStartCol,nStartRow, nEndCol,nEndRow);
}
//End of i85305
if (pDBData->HasHeader())
++nStartRow;
ScQueryParam aParam;
pDBData->GetQueryParam( aParam );
rStrings.SetCaseSensitive( aParam.bCaseSens );
// return all filter entries, if a filter condition is connected with a boolean OR
if ( bFilter )
{
SCSIZE nEntryCount = aParam.GetEntryCount();
for ( SCSIZE i = 0; i < nEntryCount && aParam.GetEntry(i).bDoQuery; ++i )
{
ScQueryEntry& rEntry = aParam.GetEntry(i);
if ( rEntry.eConnect != SC_AND )
{
bFilter = false;
break;
}
}
}
if ( bFilter )
{
pTab[nTab]->GetFilteredFilterEntries( nCol, nStartRow, nEndRow, aParam, rStrings, rHasDates );
}
else
{
pTab[nTab]->GetFilterEntries( nCol, nStartRow, nEndRow, rStrings, rHasDates );
}
return sal_True;
}
}
return sal_False;
}
//
// GetFilterEntriesArea - Eintraege fuer Filter-Dialog
//
sal_Bool ScDocument::GetFilterEntriesArea( SCCOL nCol, SCROW nStartRow, SCROW nEndRow,
SCTAB nTab, TypedScStrCollection& rStrings, bool& rHasDates )
{
if ( ValidTab(nTab) && pTab[nTab] )
{
pTab[nTab]->GetFilterEntries( nCol, nStartRow, nEndRow, rStrings, rHasDates );
return sal_True;
}
return sal_False;
}
//
// GetDataEntries - Eintraege fuer Auswahlliste-Listbox (keine Zahlen / Formeln)
//
sal_Bool ScDocument::GetDataEntries( SCCOL nCol, SCROW nRow, SCTAB nTab,
TypedScStrCollection& rStrings, sal_Bool bLimit )
{
if( !bLimit )
{
/* Try to generate the list from list validation. This part is skipped,
if bLimit==sal_True, because in that case this function is called to get
cell values for auto completion on input. */
sal_uInt32 nValidation = static_cast< const SfxUInt32Item* >( GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA ) )->GetValue();
if( nValidation )
{
const ScValidationData* pData = GetValidationEntry( nValidation );
if( pData && pData->FillSelectionList( rStrings, ScAddress( nCol, nRow, nTab ) ) )
return sal_True;
}
}
return ValidTab(nTab) && pTab[nTab] && pTab[nTab]->GetDataEntries( nCol, nRow, rStrings, bLimit );
//if (ValidTab(nTab) && pTab[nTab])
// return pTab[nTab]->GetDataEntries( nCol, nRow, rStrings, bLimit );
//return sal_False;
}
//
// GetFormulaEntries - Eintraege fuer Formel-AutoEingabe
//
// Funktionen werden als 1 schon vom InputHandler eingefuegt
#define SC_STRTYPE_NAMES 2
#define SC_STRTYPE_DBNAMES 3
#define SC_STRTYPE_HEADERS 4
sal_Bool ScDocument::GetFormulaEntries( TypedScStrCollection& rStrings )
{
sal_uInt16 i;
//
// Bereichsnamen
//
if ( pRangeName )
{
sal_uInt16 nRangeCount = pRangeName->GetCount();
for ( i=0; i<nRangeCount; i++ )
{
ScRangeData* pData = (*pRangeName)[i];
if (pData)
{
TypedStrData* pNew = new TypedStrData( pData->GetName(), 0.0, SC_STRTYPE_NAMES );
if ( !rStrings.Insert(pNew) )
delete pNew;
}
}
}
//
// Datenbank-Bereiche
//
if ( pDBCollection )
{
sal_uInt16 nDBCount = pDBCollection->GetCount();
for ( i=0; i<nDBCount; i++ )
{
ScDBData* pData = (*pDBCollection)[i];
if (pData)
{
TypedStrData* pNew = new TypedStrData( pData->GetName(), 0.0, SC_STRTYPE_DBNAMES );
if ( !rStrings.Insert(pNew) )
delete pNew;
}
}
}
//
// Inhalte von Beschriftungsbereichen
//
ScRangePairList* pLists[2];
pLists[0] = GetColNameRanges();
pLists[1] = GetRowNameRanges();
for (sal_uInt16 nListNo=0; nListNo<2; nListNo++)
{
ScRangePairList* pList = pLists[nListNo];
if (pList)
for ( ScRangePair* pPair = pList->First(); pPair; pPair = pList->Next() )
{
ScRange aRange = pPair->GetRange(0);
ScCellIterator aIter( this, aRange );
for ( ScBaseCell* pCell = aIter.GetFirst(); pCell; pCell = aIter.GetNext() )
if ( pCell->HasStringData() )
{
String aStr = pCell->GetStringData();
TypedStrData* pNew = new TypedStrData( aStr, 0.0, SC_STRTYPE_HEADERS );
if ( !rStrings.Insert(pNew) )
delete pNew;
}
}
}
return sal_True;
}
sal_Bool ScDocument::IsEmbedded() const
{
return bIsEmbedded;
}
void ScDocument::GetEmbedded( ScRange& rRange ) const
{
rRange = aEmbedRange;
}
Rectangle ScDocument::GetEmbeddedRect() const // 1/100 mm
{
Rectangle aRect;
ScTable* pTable = pTab[aEmbedRange.aStart.Tab()];
if (!pTable)
{
DBG_ERROR("GetEmbeddedRect ohne Tabelle");
}
else
{
SCCOL i;
for (i=0; i<aEmbedRange.aStart.Col(); i++)
aRect.Left() += pTable->GetColWidth(i);
aRect.Top() += pTable->GetRowHeight( 0, aEmbedRange.aStart.Row() - 1);
aRect.Right() = aRect.Left();
for (i=aEmbedRange.aStart.Col(); i<=aEmbedRange.aEnd.Col(); i++)
aRect.Right() += pTable->GetColWidth(i);
aRect.Bottom() = aRect.Top();
aRect.Bottom() += pTable->GetRowHeight( aEmbedRange.aStart.Row(), aEmbedRange.aEnd.Row());
aRect.Left() = (long) ( aRect.Left() * HMM_PER_TWIPS );
aRect.Right() = (long) ( aRect.Right() * HMM_PER_TWIPS );
aRect.Top() = (long) ( aRect.Top() * HMM_PER_TWIPS );
aRect.Bottom() = (long) ( aRect.Bottom() * HMM_PER_TWIPS );
}
return aRect;
}
void ScDocument::SetEmbedded( const ScRange& rRange )
{
bIsEmbedded = sal_True;
aEmbedRange = rRange;
}
void ScDocument::ResetEmbedded()
{
bIsEmbedded = sal_False;
aEmbedRange = ScRange();
}
/** Similar to ScViewData::AddPixelsWhile(), but add height twips and only
while result is less than nStopTwips.
@return sal_True if advanced at least one row.
*/
bool lcl_AddTwipsWhile( long & rTwips, long nStopTwips, SCROW & rPosY, SCROW nEndRow, const ScTable * pTable )
{
SCROW nRow = rPosY;
bool bAdded = false;
bool bStop = false;
while (rTwips < nStopTwips && nRow <= nEndRow && !bStop)
{
SCROW nHeightEndRow;
sal_uInt16 nHeight = pTable->GetRowHeight( nRow, NULL, &nHeightEndRow);
if (nHeightEndRow > nEndRow)
nHeightEndRow = nEndRow;
if (!nHeight)
nRow = nHeightEndRow + 1;
else
{
SCROW nRows = nHeightEndRow - nRow + 1;
sal_Int64 nAdd = static_cast<sal_Int64>(nHeight) * nRows;
if (nAdd + rTwips >= nStopTwips)
{
sal_Int64 nDiff = nAdd + rTwips - nStopTwips;
nRows -= static_cast<SCROW>(nDiff / nHeight);
nAdd = nHeight * nRows;
// We're looking for a value that satisfies loop condition.
if (nAdd + rTwips >= nStopTwips)
{
--nRows;
nAdd -= nHeight;
}
bStop = true;
}
rTwips += static_cast<long>(nAdd);
nRow += nRows;
}
}
if (nRow > rPosY)
{
--nRow;
bAdded = true;
}
rPosY = nRow;
return bAdded;
}
ScRange ScDocument::GetRange( SCTAB nTab, const Rectangle& rMMRect )
{
ScTable* pTable = pTab[nTab];
if (!pTable)
{
DBG_ERROR("GetRange ohne Tabelle");
return ScRange();
}
Rectangle aPosRect = rMMRect;
if ( IsNegativePage( nTab ) )
ScDrawLayer::MirrorRectRTL( aPosRect ); // always with positive (LTR) values
long nSize;
long nTwips;
long nAdd;
sal_Bool bEnd;
nSize = 0;
nTwips = (long) (aPosRect.Left() / HMM_PER_TWIPS);
SCCOL nX1 = 0;
bEnd = sal_False;
while (!bEnd)
{
nAdd = (long) pTable->GetColWidth(nX1);
if (nSize+nAdd <= nTwips+1 && nX1<MAXCOL)
{
nSize += nAdd;
++nX1;
}
else
bEnd = sal_True;
}
nTwips = (long) (aPosRect.Right() / HMM_PER_TWIPS);
SCCOL nX2 = nX1;
bEnd = sal_False;
while (!bEnd)
{
nAdd = (long) pTable->GetColWidth(nX2);
if (nSize+nAdd < nTwips && nX2<MAXCOL)
{
nSize += nAdd;
++nX2;
}
else
bEnd = sal_True;
}
nSize = 0;
nTwips = (long) (aPosRect.Top() / HMM_PER_TWIPS);
SCROW nY1 = 0;
// Was if(nSize+nAdd<=nTwips+1) inside loop => if(nSize+nAdd<nTwips+2)
if (lcl_AddTwipsWhile( nSize, nTwips+2, nY1, MAXROW, pTable) && nY1 < MAXROW)
++nY1; // original loop ended on last matched +1 unless that was MAXROW
nTwips = (long) (aPosRect.Bottom() / HMM_PER_TWIPS);
SCROW nY2 = nY1;
// Was if(nSize+nAdd<nTwips) inside loop => if(nSize+nAdd<nTwips)
if (lcl_AddTwipsWhile( nSize, nTwips, nY2, MAXROW, pTable) && nY2 < MAXROW)
++nY2; // original loop ended on last matched +1 unless that was MAXROW
return ScRange( nX1,nY1,nTab, nX2,nY2,nTab );
}
void ScDocument::SetEmbedded( const Rectangle& rRect ) // aus VisArea (1/100 mm)
{
bIsEmbedded = sal_True;
aEmbedRange = GetRange( nVisibleTab, rRect );
}
// VisArea auf Zellgrenzen anpassen
void lcl_SnapHor( ScTable* pTable, long& rVal, SCCOL& rStartCol )
{
SCCOL nCol = 0;
long nTwips = (long) (rVal / HMM_PER_TWIPS);
long nSnap = 0;
while ( nCol<MAXCOL )
{
long nAdd = pTable->GetColWidth(nCol);
if ( nSnap + nAdd/2 < nTwips || nCol < rStartCol )
{
nSnap += nAdd;
++nCol;
}
else
break;
}
rVal = (long) ( nSnap * HMM_PER_TWIPS );
rStartCol = nCol;
}
void lcl_SnapVer( ScTable* pTable, long& rVal, SCROW& rStartRow )
{
SCROW nRow = 0;
long nTwips = (long) (rVal / HMM_PER_TWIPS);
long nSnap = 0;
bool bFound = false;
for (SCROW i = nRow; i <= MAXROW; ++i)
{
SCROW nLastRow;
if (pTable->RowHidden(i, NULL, &nLastRow))
{
i = nLastRow;
continue;
}
nRow = i;
long nAdd = pTable->GetRowHeight(i);
if ( nSnap + nAdd/2 < nTwips || nRow < rStartRow )
{
nSnap += nAdd;
++nRow;
}
else
{
bFound = true;
break;
}
}
if (!bFound)
nRow = MAXROW; // all hidden down to the bottom
rVal = (long) ( nSnap * HMM_PER_TWIPS );
rStartRow = nRow;
}
void ScDocument::SnapVisArea( Rectangle& rRect ) const
{
ScTable* pTable = pTab[nVisibleTab];
if (!pTable)
{
DBG_ERROR("SetEmbedded ohne Tabelle");
return;
}
sal_Bool bNegativePage = IsNegativePage( nVisibleTab );
if ( bNegativePage )
ScDrawLayer::MirrorRectRTL( rRect ); // calculate with positive (LTR) values
SCCOL nCol = 0;
lcl_SnapHor( pTable, rRect.Left(), nCol );
++nCol; // mindestens eine Spalte
lcl_SnapHor( pTable, rRect.Right(), nCol );
SCROW nRow = 0;
lcl_SnapVer( pTable, rRect.Top(), nRow );
++nRow; // mindestens eine Zeile
lcl_SnapVer( pTable, rRect.Bottom(), nRow );
if ( bNegativePage )
ScDrawLayer::MirrorRectRTL( rRect ); // back to real rectangle
}
ScDocProtection* ScDocument::GetDocProtection() const
{
return pDocProtection.get();
}
void ScDocument::SetDocProtection(const ScDocProtection* pProtect)
{
if (pProtect)
pDocProtection.reset(new ScDocProtection(*pProtect));
else
pDocProtection.reset();
}
sal_Bool ScDocument::IsDocProtected() const
{
return pDocProtection.get() && pDocProtection->isProtected();
}
sal_Bool ScDocument::IsDocEditable() const
{
// import into read-only document is possible
return !IsDocProtected() && ( bImportingXML || mbChangeReadOnlyEnabled || !pShell || !pShell->IsReadOnly() );
}
sal_Bool ScDocument::IsTabProtected( SCTAB nTab ) const
{
if (VALIDTAB(nTab) && pTab[nTab])
return pTab[nTab]->IsProtected();
DBG_ERROR("Falsche Tabellennummer");
return sal_False;
}
ScTableProtection* ScDocument::GetTabProtection( SCTAB nTab ) const
{
if (VALIDTAB(nTab) && pTab[nTab])
return pTab[nTab]->GetProtection();
return NULL;
}
void ScDocument::SetTabProtection(SCTAB nTab, const ScTableProtection* pProtect)
{
if (!ValidTab(nTab))
return;
pTab[nTab]->SetProtection(pProtect);
}
void ScDocument::CopyTabProtection(SCTAB nTabSrc, SCTAB nTabDest)
{
if (!ValidTab(nTabSrc) || !ValidTab(nTabDest))
return;
pTab[nTabDest]->SetProtection( pTab[nTabSrc]->GetProtection() );
}
const ScDocOptions& ScDocument::GetDocOptions() const
{
DBG_ASSERT( pDocOptions, "No DocOptions! :-(" );
return *pDocOptions;
}
void ScDocument::SetDocOptions( const ScDocOptions& rOpt )
{
DBG_ASSERT( pDocOptions, "No DocOptions! :-(" );
*pDocOptions = rOpt;
xPoolHelper->SetFormTableOpt(rOpt);
}
const ScViewOptions& ScDocument::GetViewOptions() const
{
DBG_ASSERT( pViewOptions, "No ViewOptions! :-(" );
return *pViewOptions;
}
void ScDocument::SetViewOptions( const ScViewOptions& rOpt )
{
DBG_ASSERT( pViewOptions, "No ViewOptions! :-(" );
*pViewOptions = rOpt;
}
void ScDocument::GetLanguage( LanguageType& rLatin, LanguageType& rCjk, LanguageType& rCtl ) const
{
rLatin = eLanguage;
rCjk = eCjkLanguage;
rCtl = eCtlLanguage;
}
void ScDocument::SetLanguage( LanguageType eLatin, LanguageType eCjk, LanguageType eCtl )
{
eLanguage = eLatin;
eCjkLanguage = eCjk;
eCtlLanguage = eCtl;
if ( xPoolHelper.isValid() )
{
ScDocumentPool* pPool = xPoolHelper->GetDocPool();
pPool->SetPoolDefaultItem( SvxLanguageItem( eLanguage, ATTR_FONT_LANGUAGE ) );
pPool->SetPoolDefaultItem( SvxLanguageItem( eCjkLanguage, ATTR_CJK_FONT_LANGUAGE ) );
pPool->SetPoolDefaultItem( SvxLanguageItem( eCtlLanguage, ATTR_CTL_FONT_LANGUAGE ) );
}
UpdateDrawLanguages(); // set edit engine defaults in drawing layer pool
}
Rectangle ScDocument::GetMMRect( SCCOL nStartCol, SCROW nStartRow,
SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
{
if (!ValidTab(nTab) || !pTab[nTab])
{
DBG_ERROR("GetMMRect: falsche Tabelle");
return Rectangle(0,0,0,0);
}
SCCOL i;
Rectangle aRect;
for (i=0; i<nStartCol; i++)
aRect.Left() += GetColWidth(i,nTab);
aRect.Top() += GetRowHeight( 0, nStartRow-1, nTab);
aRect.Right() = aRect.Left();
aRect.Bottom() = aRect.Top();
for (i=nStartCol; i<=nEndCol; i++)
aRect.Right() += GetColWidth(i,nTab);
aRect.Bottom() += GetRowHeight( nStartRow, nEndRow, nTab);
aRect.Left() = (long)(aRect.Left() * HMM_PER_TWIPS);
aRect.Right() = (long)(aRect.Right() * HMM_PER_TWIPS);
aRect.Top() = (long)(aRect.Top() * HMM_PER_TWIPS);
aRect.Bottom() = (long)(aRect.Bottom() * HMM_PER_TWIPS);
if ( IsNegativePage( nTab ) )
ScDrawLayer::MirrorRectRTL( aRect );
return aRect;
}
void ScDocument::SetExtDocOptions( ScExtDocOptions* pNewOptions )
{
delete pExtDocOptions;
pExtDocOptions = pNewOptions;
}
void ScDocument::DoMergeContents( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
SCCOL nEndCol, SCROW nEndRow )
{
String aEmpty;
String aTotal;
String aCellStr;
SCCOL nCol;
SCROW nRow;
for (nRow=nStartRow; nRow<=nEndRow; nRow++)
for (nCol=nStartCol; nCol<=nEndCol; nCol++)
{
GetString(nCol,nRow,nTab,aCellStr);
if (aCellStr.Len())
{
if (aTotal.Len())
aTotal += ' ';
aTotal += aCellStr;
}
if (nCol != nStartCol || nRow != nStartRow)
SetString(nCol,nRow,nTab,aEmpty);
}
SetString(nStartCol,nStartRow,nTab,aTotal);
}
void ScDocument::DoMerge( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
SCCOL nEndCol, SCROW nEndRow, bool bDeleteCaptions )
{
ScMergeAttr aAttr( nEndCol-nStartCol+1, nEndRow-nStartRow+1 );
ApplyAttr( nStartCol, nStartRow, nTab, aAttr );
if ( nEndCol > nStartCol )
ApplyFlagsTab( nStartCol+1, nStartRow, nEndCol, nStartRow, nTab, SC_MF_HOR );
if ( nEndRow > nStartRow )
ApplyFlagsTab( nStartCol, nStartRow+1, nStartCol, nEndRow, nTab, SC_MF_VER );
if ( nEndCol > nStartCol && nEndRow > nStartRow )
ApplyFlagsTab( nStartCol+1, nStartRow+1, nEndCol, nEndRow, nTab, SC_MF_HOR | SC_MF_VER );
// remove all covered notes (removed captions are collected by drawing undo if active)
sal_uInt16 nDelFlag = IDF_NOTE | (bDeleteCaptions ? 0 : IDF_NOCAPTIONS);
if( nStartCol < nEndCol )
DeleteAreaTab( nStartCol + 1, nStartRow, nEndCol, nStartRow, nTab, nDelFlag );
if( nStartRow < nEndRow )
DeleteAreaTab( nStartCol, nStartRow + 1, nEndCol, nEndRow, nTab, nDelFlag );
}
void ScDocument::RemoveMerge( SCCOL nCol, SCROW nRow, SCTAB nTab )
{
const ScMergeAttr* pAttr = (const ScMergeAttr*)
GetAttr( nCol, nRow, nTab, ATTR_MERGE );
if ( pAttr->GetColMerge() <= 1 && pAttr->GetRowMerge() <= 1 )
return;
SCCOL nEndCol = nCol + pAttr->GetColMerge() - 1;
SCROW nEndRow = nRow + pAttr->GetRowMerge() - 1;
RemoveFlagsTab( nCol, nRow, nEndCol, nEndRow, nTab, SC_MF_HOR | SC_MF_VER );
const ScMergeAttr* pDefAttr = (const ScMergeAttr*)
&xPoolHelper->GetDocPool()->GetDefaultItem( ATTR_MERGE );
ApplyAttr( nCol, nRow, nTab, *pDefAttr );
}
void ScDocument::ExtendPrintArea( OutputDevice* pDev, SCTAB nTab,
SCCOL nStartCol, SCROW nStartRow, SCCOL& rEndCol, SCROW nEndRow )
{
if ( ValidTab(nTab) && pTab[nTab] )
pTab[nTab]->ExtendPrintArea( pDev, nStartCol, nStartRow, rEndCol, nEndRow );
}
void ScDocument::IncSizeRecalcLevel( SCTAB nTab )
{
if ( ValidTab(nTab) && pTab[nTab] )
pTab[nTab]->IncRecalcLevel();
}
void ScDocument::DecSizeRecalcLevel( SCTAB nTab, bool bUpdateNoteCaptionPos )
{
if ( ValidTab(nTab) && pTab[nTab] )
pTab[nTab]->DecRecalcLevel( bUpdateNoteCaptionPos );
}
// Wang Xu Ming -- 2009-8-17
// DataPilot Migration - Cache&&Performance
ScDPTableDataCache* ScDocument::GetDPObjectCache( long nID )
{
for ( std::list<ScDPTableDataCache*>::iterator iter = m_listDPObjectsCaches.begin(); iter!=m_listDPObjectsCaches.end(); iter++ )
{ //
if ( nID == (*iter)->GetId() )
return *iter;
}
return NULL;
}
ScDPTableDataCache* ScDocument::GetUsedDPObjectCache ( ScRange rRange )
{
ScDPTableDataCache* pCache = NULL;
sal_uInt16 nCount = GetDPCollection()->GetCount();
for ( short i=nCount-1; i>=0 ; i--)
{
if ( const ScSheetSourceDesc* pUsedSheetDesc = (*pDPCollection)[i]->GetSheetDesc() )
if ( rRange == pUsedSheetDesc->aSourceRange )
{
long nID = (*pDPCollection)[i]->GetCacheId();
if ( nID >= 0 )
pCache= GetDPObjectCache( nID );
if ( pCache )
return pCache;
}
}
return pCache;
}
long ScDocument::AddDPObjectCache( ScDPTableDataCache* pData )
{
if ( pData->GetId() < 0 )
{ //create a id for it
pData->SetId( GetNewDPObjectCacheId() );
}
m_listDPObjectsCaches.push_back( pData );
return pData->GetId();
}
long ScDocument::GetNewDPObjectCacheId()
{
long nID = 0;
bool bFound = false;
std::list<ScDPTableDataCache*>::iterator iter;
do {
for ( iter = m_listDPObjectsCaches.begin(); iter!=m_listDPObjectsCaches.end(); iter++ )
{ //Get a new Id
if ( nID == (*iter)->GetId() )
{
nID++;
bFound = true;
break;
}
}
if ( iter == m_listDPObjectsCaches.end() )
bFound = false;
} while ( bFound );
return nID;
}
void ScDocument::RemoveDPObjectCache( long nID )
{
for ( std::list<ScDPTableDataCache*>::iterator iter = m_listDPObjectsCaches.begin(); iter!=m_listDPObjectsCaches.end(); iter++ )
{
if ( nID == (*iter)->GetId() )
{
ScDPTableDataCache* pCache = *iter;
m_listDPObjectsCaches.erase( iter );
delete pCache;
break;
}
}
}
void ScDocument::RemoveUnusedDPObjectCaches()
{
for ( std::list<ScDPTableDataCache*>::iterator iter = m_listDPObjectsCaches.begin(); iter!=m_listDPObjectsCaches.end(); )
{
long nID = (*iter)->GetId();
sal_uInt16 nCount = GetDPCollection()->GetCount();
sal_uInt16 i ;
for ( i=0; i<nCount; i++)
{
if ( nID == (*pDPCollection)[i]->GetCacheId() )
break;
}
if ( i == nCount )
{
ScDPTableDataCache* pCache = *iter;
iter = m_listDPObjectsCaches.erase( iter );
delete pCache;
continue;
}
++iter;
}
}
void ScDocument::GetUsedDPObjectCache( std::list<ScDPTableDataCache*>& usedlist )
{
for ( std::list<ScDPTableDataCache*>::iterator iter = m_listDPObjectsCaches.begin(); iter!=m_listDPObjectsCaches.end(); iter++ )
{
long nID = (*iter)->GetId();
sal_uInt16 nCount = GetDPCollection()->GetCount();
sal_uInt16 i=0;
for ( i=0; i<nCount; i++)
if ( nID == (*pDPCollection)[i]->GetCacheId() )
break;
if ( i != nCount )
usedlist.push_back( *iter );
}
}
// End Comments
SCSIZE ScDocument::GetPatternCount( SCTAB nTab, SCCOL nCol )
{
if( ValidTab(nTab) && pTab[nTab] )
return pTab[nTab]->GetPatternCount( nCol );
else
return 0;
}
SCSIZE ScDocument::GetPatternCount( SCTAB nTab, SCCOL nCol, SCROW nRw1, SCROW nRw2 )
{
if( ValidTab(nTab) && pTab[nTab] )
return pTab[nTab]->GetPatternCount( nCol, nRw1, nRw2 );
else
return 0;
}
bool ScDocument::ReservedPatternCount( SCTAB nTab, SCCOL nCol, SCSIZE nReserved )
{
if( ValidTab(nTab) && pTab[nTab] )
return pTab[nTab]->ReservedPatternCount( nCol, nReserved );
else
return false;
}