diff options
Diffstat (limited to 'sc/source/core/data/documen2.cxx')
-rw-r--r-- | sc/source/core/data/documen2.cxx | 1471 |
1 files changed, 1471 insertions, 0 deletions
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx new file mode 100644 index 000000000..c29025f43 --- /dev/null +++ b/sc/source/core/data/documen2.cxx @@ -0,0 +1,1471 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <scextopt.hxx> +#include <autonamecache.hxx> + +#include <o3tl/safeint.hxx> +#include <osl/thread.h> +#include <svx/xtable.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/printer.hxx> +#include <svl/asiancfg.hxx> +#include <vcl/virdev.hxx> +#include <svl/sharedstringpool.hxx> +#include <tools/urlobj.hxx> +#include <rtl/crc.h> +#include <basic/basmgr.hxx> +#include <comphelper/threadpool.hxx> +#include <sal/log.hxx> +#include <osl/diagnose.h> +#include <unotools/configmgr.hxx> + +#include <scmod.hxx> +#include <document.hxx> +#include <table.hxx> +#include <patattr.hxx> +#include <rangenam.hxx> +#include <dbdata.hxx> +#include <chartlock.hxx> +#include <rechead.hxx> +#include <global.hxx> +#include <bcaslot.hxx> +#include <adiasync.hxx> +#include <addinlis.hxx> +#include <chartlis.hxx> +#include <markdata.hxx> +#include <validat.hxx> +#include <detdata.hxx> +#include <defaultsoptions.hxx> +#include <ddelink.hxx> +#include <chgtrack.hxx> +#include <chgviset.hxx> +#include <editutil.hxx> +#include <hints.hxx> +#include <dpobject.hxx> +#include <scrdata.hxx> +#include <poolhelp.hxx> +#include <unoreflist.hxx> +#include <listenercalls.hxx> +#include <recursionhelper.hxx> +#include <lookupcache.hxx> +#include <rangecache.hxx> +#include <externalrefmgr.hxx> +#include <viewdata.hxx> +#include <viewutil.hxx> +#include <tabprotection.hxx> +#include <formulaparserpool.hxx> +#include <clipparam.hxx> +#include <macromgr.hxx> +#include <formulacell.hxx> +#include <clipcontext.hxx> +#include <refupdatecontext.hxx> +#include <refreshtimerprotector.hxx> +#include <scopetools.hxx> +#include <documentlinkmgr.hxx> +#include <interpre.hxx> +#include <tokenstringcontext.hxx> +#include <docsh.hxx> +#include <clipoptions.hxx> +#include <listenercontext.hxx> +#include <datamapper.hxx> +#include <drwlayer.hxx> +#include <sharedstringpoolpurge.hxx> +#include <dociter.hxx> +#include <config_features.h> + +using namespace com::sun::star; + +const sal_uInt16 ScDocument::nSrcVer = SC_CURRENT_VERSION; + +ScSheetLimits ScSheetLimits::CreateDefault() +{ +#if HAVE_FEATURE_JUMBO_SHEETS + bool jumboSheets = false; + if( SC_MOD()) + jumboSheets = SC_MOD()->GetDefaultsOptions().GetInitJumboSheets(); + else + assert( getenv("LO_TESTNAME") != nullptr ); // in unittests + if (jumboSheets) + return ScSheetLimits(MAXCOL_JUMBO, MAXROW_JUMBO); + else +#endif + return ScSheetLimits(MAXCOL, MAXROW); +} + +ScDocument::ScDocument( ScDocumentMode eMode, SfxObjectShell* pDocShell ) : + mpCellStringPool(std::make_shared<svl::SharedStringPool>(ScGlobal::getCharClass())), + mpDocLinkMgr(new sc::DocumentLinkManager(pDocShell)), + mbFormulaGroupCxtBlockDiscard(false), + maCalcConfig( ScInterpreter::GetGlobalConfig()), + mpUndoManager( nullptr ), + mpShell( pDocShell ), + mpPrinter( nullptr ), + mpVirtualDevice_100th_mm( nullptr ), + pFormatExchangeList( nullptr ), + mxSheetLimits(new ScSheetLimits(ScSheetLimits::CreateDefault())), + pFormulaTree( nullptr ), + pEOFormulaTree( nullptr ), + pFormulaTrack( nullptr ), + pEOFormulaTrack( nullptr ), + pPreviewCellStyle( nullptr ), + maPreviewSelection(*mxSheetLimits), + nUnoObjectId( 0 ), + nRangeOverflowType( 0 ), + aCurTextWidthCalcPos(MaxCol(),0,0), + aTrackIdle("sc ScDocument Track Idle"), + nFormulaCodeInTree(0), + nXMLImportedFormulaCount( 0 ), + nInterpretLevel(0), + nMacroInterpretLevel(0), + nInterpreterTableOpLevel(0), + maInterpreterContext( *this, nullptr ), + mxScSortedRangeCache(new ScSortedRangeCacheMap), + nFormulaTrackCount(0), + eHardRecalcState(HardRecalcState::OFF), + nVisibleTab( 0 ), + nPosLeft( 0 ), + nPosTop( 0 ), + eLinkMode(LM_UNKNOWN), + bAutoCalc( eMode == SCDOCMODE_DOCUMENT || eMode == SCDOCMODE_FUNCTIONACCESS ), + bAutoCalcShellDisabled( false ), + bForcedFormulaPending( false ), + bCalculatingFormulaTree( false ), + bIsClip( eMode == SCDOCMODE_CLIP ), + bIsUndo( eMode == SCDOCMODE_UNDO ), + bIsFunctionAccess( eMode == SCDOCMODE_FUNCTIONACCESS ), + bIsVisible( false ), + bIsEmbedded( false ), + bInsertingFromOtherDoc( false ), + bLoadingMedium( false ), + bImportingXML( false ), + bCalcingAfterLoad( false ), + bNoListening( false ), + mbIdleEnabled(true), + bInLinkUpdate( false ), + bChartListenerCollectionNeedsUpdate( false ), + bHasForcedFormulas( false ), + bInDtorClear( false ), + bExpandRefs( false ), + bDetectiveDirty( false ), + bDelayedDeletingBroadcasters( false ), + bLinkFormulaNeedingCheck( false ), + nAsianCompression(CharCompressType::Invalid), + nAsianKerning(SC_ASIANKERNING_INVALID), + bPastingDrawFromOtherDoc( false ), + nInDdeLinkUpdate( 0 ), + bInUnoBroadcast( false ), + bInUnoListenerCall( false ), + nAdjustHeightLock(0), + eGrammar( formula::FormulaGrammar::GRAM_NATIVE ), + bStyleSheetUsageInvalid( true ), + mbUndoEnabled( true ), + mbExecuteLinkEnabled( true ), + mbChangeReadOnlyEnabled( false ), + mbStreamValidLocked( false ), + mbUserInteractionEnabled(true), + mnNamedRangesLockCount(0), + mbEmbedFonts(false), + mbEmbedUsedFontsOnly(false), + mbEmbedFontScriptLatin(true), + mbEmbedFontScriptAsian(true), + mbEmbedFontScriptComplex(true), + mnImagePreferredDPI(0), + mbTrackFormulasPending(false), + mbFinalTrackFormulas(false), + mbDocShellRecalc(false), + mbLayoutStrings(false), + mnMutationGuardFlags(0) +{ + maPreviewSelection = { *mxSheetLimits }; + aCurTextWidthCalcPos = { MaxCol(), 0, 0 }; + + SetStorageGrammar( formula::FormulaGrammar::GRAM_STORAGE_DEFAULT); + + eSrcSet = osl_getThreadTextEncoding(); + + /* TODO: for SCDOCMODE_FUNCTIONACCESS it might not even be necessary to + * have all of these available. */ + if ( eMode == SCDOCMODE_DOCUMENT || eMode == SCDOCMODE_FUNCTIONACCESS ) + { + mxPoolHelper = new ScPoolHelper( *this ); + if (!utl::ConfigManager::IsFuzzing()) //just too slow + pBASM.reset( new ScBroadcastAreaSlotMachine( this ) ); + pChartListenerCollection.reset( new ScChartListenerCollection( *this ) ); + pRefreshTimerControl.reset( new ScRefreshTimerControl ); + } + else + { + pChartListenerCollection = nullptr; + } + pDBCollection.reset( new ScDBCollection(*this) ); + pSelectionAttr = nullptr; + apTemporaryChartLock.reset( new ScTemporaryChartLock(this) ); + xColNameRanges = new ScRangePairList; + xRowNameRanges = new ScRangePairList; + ImplCreateOptions(); + // languages for a visible document are set by docshell later (from options) + SetLanguage( ScGlobal::eLnge, ScGlobal::eLnge, ScGlobal::eLnge ); + + aTrackIdle.SetInvokeHandler( LINK( this, ScDocument, TrackTimeHdl ) ); +} + +sfx2::LinkManager* ScDocument::GetLinkManager() +{ + return GetDocLinkManager().getLinkManager(); +} + +const sfx2::LinkManager* ScDocument::GetLinkManager() const +{ + return GetDocLinkManager().getExistingLinkManager(); +} + +sc::DocumentLinkManager& ScDocument::GetDocLinkManager() +{ + return *mpDocLinkMgr; +} + +const sc::DocumentLinkManager& ScDocument::GetDocLinkManager() const +{ + return const_cast<ScDocument*>(this)->GetDocLinkManager(); +} + +void ScDocument::SetStorageGrammar( formula::FormulaGrammar::Grammar eGram ) +{ + OSL_PRECOND( + eGram == formula::FormulaGrammar::GRAM_ODFF || + eGram == formula::FormulaGrammar::GRAM_PODF, + "ScDocument::SetStorageGrammar: wrong storage grammar"); + + eStorageGrammar = eGram; +} + +void ScDocument::SetDocVisible( bool bSet ) +{ + // called from view ctor - only for a visible document, + // each new sheet's RTL flag is initialized from the locale + bIsVisible = bSet; +} + +sal_uInt32 ScDocument::GetDocumentID() const +{ + const ScDocument* pThis = this; + sal_uInt32 nCrc = rtl_crc32( 0, &pThis, sizeof(ScDocument*) ); + // the this pointer only might not be sufficient + nCrc = rtl_crc32( nCrc, &mpShell, sizeof(SfxObjectShell*) ); + return nCrc; +} + +void ScDocument::StartChangeTracking() +{ + if (!pChangeTrack) + pChangeTrack.reset( new ScChangeTrack( *this ) ); +} + +void ScDocument::EndChangeTracking() +{ + pChangeTrack.reset(); +} + +void ScDocument::SetChangeTrack( std::unique_ptr<ScChangeTrack> pTrack ) +{ + OSL_ENSURE( &pTrack->GetDocument() == this, "SetChangeTrack: different documents" ); + if ( !pTrack || pTrack == pChangeTrack || &pTrack->GetDocument() != this ) + return ; + EndChangeTracking(); + pChangeTrack = std::move(pTrack); +} + +IMPL_LINK_NOARG(ScDocument, TrackTimeHdl, Timer *, void) +{ + if ( ScDdeLink::IsInUpdate() ) // do not nest + { + aTrackIdle.Start(); // try again later + } + else if (mpShell) // execute + { + TrackFormulas(); + mpShell->Broadcast( SfxHint( SfxHintId::ScDataChanged ) ); + + if (!mpShell->IsModified()) + { + mpShell->SetModified(); + SfxBindings* pBindings = GetViewBindings(); + if (pBindings) + { + pBindings->Invalidate( SID_SAVEDOC ); + pBindings->Invalidate( SID_DOC_MODIFIED ); + } + } + } +} + +void ScDocument::SetExpandRefs( bool bVal ) +{ + bExpandRefs = bVal; +} + +void ScDocument::StartTrackTimer() +{ + if (!aTrackIdle.IsActive()) // do not postpone for forever + aTrackIdle.Start(); +} + +void ScDocument::ClosingClipboardSource() +{ + if (!bIsClip) + return; + + ForgetNoteCaptions( ScRangeList( ScRange( 0,0,0, MaxCol(), MaxRow(), GetTableCount()-1)), true); +} + +ScDocument::~ScDocument() +{ + OSL_PRECOND( !bInLinkUpdate, "bInLinkUpdate in dtor" ); + + // Join any pending(recalc) threads in global threadpool + comphelper::ThreadPool::getSharedOptimalPool().joinThreadsIfIdle(); + + bInDtorClear = true; + + // first of all disable all refresh timers by deleting the control + if ( pRefreshTimerControl ) + { // To be sure there isn't anything running do it with a protector, + // this ensures also that nothing needs the control anymore. + ScRefreshTimerProtector aProt( GetRefreshTimerControlAddress() ); + pRefreshTimerControl.reset(); + } + + mxFormulaParserPool.reset(); + // Destroy the external ref mgr instance here because it has a timer + // which needs to be stopped before the app closes. + pExternalRefMgr.reset(); + + ScAddInAsync::RemoveDocument( this ); + ScAddInListener::RemoveDocument( this ); + pChartListenerCollection.reset(); // before pBASM because of potential Listener! + + ClearLookupCaches(); // before pBASM because of listeners + + // destroy BroadcastAreas first to avoid un-needed Single-EndListenings of Formula-Cells + pBASM.reset(); // BroadcastAreaSlotMachine + + pUnoBroadcaster.reset(); // broadcasts SfxHintId::Dying again + + pUnoRefUndoList.reset(); + pUnoListenerCalls.reset(); + + Clear( true ); // true = from destructor (needed for SdrModel::ClearModel) + + pValidationList.reset(); + pRangeName.reset(); + pDBCollection.reset(); + pSelectionAttr.reset(); + apTemporaryChartLock.reset(); + DeleteDrawLayer(); + mpPrinter.disposeAndClear(); + ImplDeleteOptions(); + pConsolidateDlgData.reset(); + pClipData.reset(); + pDetOpList.reset(); // also deletes entries + pChangeTrack.reset(); + mpEditEngine.reset(); + mpNoteEngine.reset(); + pChangeViewSettings.reset(); // and delete + mpVirtualDevice_100th_mm.disposeAndClear(); + + pDPCollection.reset(); + mpAnonymousDBData.reset(); + + // delete the EditEngine before destroying the mxPoolHelper + pCacheFieldEditEngine.reset(); + + if ( mxPoolHelper.is() && !bIsClip && !bIsUndo) + mxPoolHelper->SourceDocumentGone(); + mxPoolHelper.clear(); + + pScriptTypeData.reset(); + maNonThreaded.xRecursionHelper.reset(); + assert(!maThreadSpecific.xRecursionHelper); + + pPreviewFont.reset(); + SAL_WARN_IF( pAutoNameCache, "sc.core", "AutoNameCache still set in dtor" ); + + mpFormulaGroupCxt.reset(); + // Purge unused items if the string pool will be still used (e.g. by undo history). + if(mpCellStringPool.use_count() > 1) + { + // Calling purge() may be somewhat expensive with large documents, so + // try to delay and compress it for temporary documents. + if(IsClipOrUndo()) + ScGlobal::GetSharedStringPoolPurge().delayedPurge(mpCellStringPool); + else + mpCellStringPool->purge(); + } + mpCellStringPool.reset(); + + assert( pDelayedFormulaGrouping == nullptr ); + assert( pDelayedStartListeningFormulaCells.empty()); +} + +void ScDocument::InitClipPtrs( ScDocument* pSourceDoc ) +{ + OSL_ENSURE(bIsClip, "InitClipPtrs and not bIsClip"); + + ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE); + + pValidationList.reset(); + + Clear(); + + SharePooledResources(pSourceDoc); + + // conditional Formats / validations + // TODO: Copy Templates? + const ScValidationDataList* pSourceValid = pSourceDoc->pValidationList.get(); + if ( pSourceValid ) + pValidationList.reset(new ScValidationDataList(*this, *pSourceValid)); + + // store Links in Stream + pClipData.reset(); + if (pSourceDoc->GetDocLinkManager().hasDdeLinks()) + { + pClipData.reset( new SvMemoryStream ); + pSourceDoc->SaveDdeLinks(*pClipData); + } + + // Options pointers exist (ImplCreateOptions) for any document. + // Must be copied for correct results in OLE objects (#i42666#). + SetDocOptions( pSourceDoc->GetDocOptions() ); + SetViewOptions( pSourceDoc->GetViewOptions() ); +} + +SvNumberFormatter* ScDocument::GetFormatTable() const +{ + assert(!IsThreadedGroupCalcInProgress()); + return mxPoolHelper->GetFormTable(); +} + +SfxItemPool* ScDocument::GetEditPool() const +{ + return mxPoolHelper->GetEditPool(); +} + +SfxItemPool* ScDocument::GetEnginePool() const +{ + return mxPoolHelper->GetEnginePool(); +} + +ScFieldEditEngine& ScDocument::GetEditEngine() +{ + if ( !mpEditEngine ) + { + mpEditEngine.reset( new ScFieldEditEngine(this, GetEnginePool(), GetEditPool()) ); + mpEditEngine->SetUpdateLayout( false ); + mpEditEngine->EnableUndo( false ); + mpEditEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM)); + ApplyAsianEditSettings( *mpEditEngine ); + } + return *mpEditEngine; +} + +ScNoteEditEngine& ScDocument::GetNoteEngine() +{ + if ( !mpNoteEngine ) + { + ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE); + mpNoteEngine.reset( new ScNoteEditEngine( GetEnginePool(), GetEditPool() ) ); + mpNoteEngine->SetUpdateLayout( false ); + mpNoteEngine->EnableUndo( false ); + mpNoteEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM)); + ApplyAsianEditSettings( *mpNoteEngine ); + const SfxItemSet& rItemSet = GetDefPattern()->GetItemSet(); + SfxItemSet aEEItemSet( mpNoteEngine->GetEmptyItemSet() ); + ScPatternAttr::FillToEditItemSet( aEEItemSet, rItemSet ); + mpNoteEngine->SetDefaults( std::move(aEEItemSet) ); // edit engine takes ownership + } + return *mpNoteEngine; +} + +void ScDocument::ResetClip( ScDocument* pSourceDoc, const ScMarkData* pMarks ) +{ + if (bIsClip) + { + InitClipPtrs(pSourceDoc); + + for (SCTAB i = 0; i < static_cast<SCTAB>(pSourceDoc->maTabs.size()); i++) + if (pSourceDoc->maTabs[i]) + if (!pMarks || pMarks->GetTableSelect(i)) + { + OUString aString = pSourceDoc->maTabs[i]->GetName(); + if ( i < static_cast<SCTAB>(maTabs.size()) ) + { + maTabs[i].reset( new ScTable(*this, i, aString) ); + + } + else + { + if( i > static_cast<SCTAB>(maTabs.size()) ) + { + maTabs.resize(i); + } + maTabs.emplace_back(new ScTable(*this, i, aString)); + } + maTabs[i]->SetLayoutRTL( pSourceDoc->maTabs[i]->IsLayoutRTL() ); + } + } + else + { + OSL_FAIL("ResetClip"); + } +} + +void ScDocument::ResetClip( ScDocument* pSourceDoc, SCTAB nTab ) +{ + if (bIsClip) + { + InitClipPtrs(pSourceDoc); + if (nTab >= static_cast<SCTAB>(maTabs.size())) + { + maTabs.resize(nTab+1); + } + maTabs[nTab].reset( new ScTable(*this, nTab, "baeh") ); + if (nTab < static_cast<SCTAB>(pSourceDoc->maTabs.size()) && pSourceDoc->maTabs[nTab]) + maTabs[nTab]->SetLayoutRTL( pSourceDoc->maTabs[nTab]->IsLayoutRTL() ); + } + else + { + OSL_FAIL("ResetClip"); + } +} + +void ScDocument::EnsureTable( SCTAB nTab ) +{ + bool bExtras = !bIsUndo; // Column-Widths, Row-Heights, Flags + if (o3tl::make_unsigned(nTab) >= maTabs.size()) + maTabs.resize(nTab+1); + + if (!maTabs[nTab]) + maTabs[nTab].reset( new ScTable(*this, nTab, "temp", bExtras, bExtras) ); +} + +ScRefCellValue ScDocument::GetRefCellValue( const ScAddress& rPos ) +{ + if (!TableExists(rPos.Tab())) + return ScRefCellValue(); // empty + + return maTabs[rPos.Tab()]->GetRefCellValue(rPos.Col(), rPos.Row()); +} + +ScRefCellValue ScDocument::GetRefCellValue( const ScAddress& rPos, sc::ColumnBlockPosition& rBlockPos ) +{ + if (!TableExists(rPos.Tab())) + return ScRefCellValue(); // empty + + return maTabs[rPos.Tab()]->GetRefCellValue(rPos.Col(), rPos.Row(), rBlockPos); +} + +svl::SharedStringPool& ScDocument::GetSharedStringPool() +{ + return *mpCellStringPool; +} + +const svl::SharedStringPool& ScDocument::GetSharedStringPool() const +{ + return *mpCellStringPool; +} + +bool ScDocument::GetPrintArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow, + bool bNotes) const +{ + if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab]) + { + bool bAny = maTabs[nTab]->GetPrintArea( rEndCol, rEndRow, bNotes, /*bCalcHiddens*/false); + if (mpDrawLayer) + { + ScRange aDrawRange(0,0,nTab, MaxCol(),MaxRow(),nTab); + if (DrawGetPrintArea( aDrawRange, true, true )) + { + if (aDrawRange.aEnd.Col()>rEndCol) rEndCol=aDrawRange.aEnd.Col(); + if (aDrawRange.aEnd.Row()>rEndRow) rEndRow=aDrawRange.aEnd.Row(); + bAny = true; + } + } + return bAny; + } + + rEndCol = 0; + rEndRow = 0; + return false; +} + +bool ScDocument::GetPrintAreaHor( SCTAB nTab, SCROW nStartRow, SCROW nEndRow, + SCCOL& rEndCol ) const +{ + if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab]) + { + bool bAny = maTabs[nTab]->GetPrintAreaHor( nStartRow, nEndRow, rEndCol ); + if (mpDrawLayer) + { + ScRange aDrawRange(0,nStartRow,nTab, MaxCol(),nEndRow,nTab); + if (DrawGetPrintArea( aDrawRange, true, false )) + { + if (aDrawRange.aEnd.Col()>rEndCol) rEndCol=aDrawRange.aEnd.Col(); + bAny = true; + } + } + return bAny; + } + + rEndCol = 0; + return false; +} + +bool ScDocument::GetPrintAreaVer( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol, + SCROW& rEndRow, bool bNotes ) const +{ + if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab]) + { + bool bAny = maTabs[nTab]->GetPrintAreaVer( nStartCol, nEndCol, rEndRow, bNotes ); + if (mpDrawLayer) + { + ScRange aDrawRange(nStartCol,0,nTab, nEndCol,MaxRow(),nTab); + if (DrawGetPrintArea( aDrawRange, false, true )) + { + if (aDrawRange.aEnd.Row()>rEndRow) rEndRow=aDrawRange.aEnd.Row(); + bAny = true; + } + } + return bAny; + } + + rEndRow = 0; + return false; +} + +bool ScDocument::GetDataStart( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow ) const +{ + if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab]) + { + bool bAny = maTabs[nTab]->GetDataStart( rStartCol, rStartRow ); + if (mpDrawLayer) + { + ScRange aDrawRange(0,0,nTab, MaxCol(),MaxRow(),nTab); + if (DrawGetPrintArea( aDrawRange, true, true )) + { + if (aDrawRange.aStart.Col()<rStartCol) rStartCol=aDrawRange.aStart.Col(); + if (aDrawRange.aStart.Row()<rStartRow) rStartRow=aDrawRange.aStart.Row(); + bAny = true; + } + } + return bAny; + } + + rStartCol = 0; + rStartRow = 0; + return false; +} + +void ScDocument::GetTiledRenderingArea(SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow) const +{ + bool bHasPrintArea = GetPrintArea(nTab, rEndCol, rEndRow, false); + + // we need some reasonable minimal document size + ScViewData* pViewData = ScDocShell::GetViewData(); + if (!pViewData) + { + if (!bHasPrintArea) + { + rEndCol = 20; + rEndRow = 50; + } + else + { + rEndCol += 20; + rEndRow += 50; + } + } + else if (!bHasPrintArea) + { + rEndCol = pViewData->GetMaxTiledCol(); + rEndRow = pViewData->GetMaxTiledRow(); + } + else + { + rEndCol = std::max(rEndCol, pViewData->GetMaxTiledCol()); + rEndRow = std::max(rEndRow, pViewData->GetMaxTiledRow()); + } +} + +bool ScDocument::MoveTab( SCTAB nOldPos, SCTAB nNewPos, ScProgress* pProgress ) +{ + if (nOldPos == nNewPos) + return false; + + SCTAB nTabCount = static_cast<SCTAB>(maTabs.size()); + if(nTabCount < 2) + return false; + + bool bValid = false; + if (ValidTab(nOldPos) && nOldPos < nTabCount ) + { + if (maTabs[nOldPos]) + { + sc::AutoCalcSwitch aACSwitch(*this, false); + sc::DelayDeletingBroadcasters delayDeletingBroadcasters(*this); + + SetNoListening( true ); + if (nNewPos == SC_TAB_APPEND || nNewPos >= nTabCount) + nNewPos = nTabCount-1; + + // Update Reference + // TODO: combine with UpdateReference! + + sc::RefUpdateMoveTabContext aCxt( *this, nOldPos, nNewPos); + + SCTAB nDz = nNewPos - nOldPos; + ScRange aSourceRange( 0,0,nOldPos, MaxCol(),MaxRow(),nOldPos ); + if (pRangeName) + pRangeName->UpdateMoveTab(aCxt); + + pDBCollection->UpdateMoveTab( nOldPos, nNewPos ); + xColNameRanges->UpdateReference( URM_REORDER, this, aSourceRange, 0,0,nDz ); + xRowNameRanges->UpdateReference( URM_REORDER, this, aSourceRange, 0,0,nDz ); + if (pDPCollection) + pDPCollection->UpdateReference( URM_REORDER, aSourceRange, 0,0,nDz ); + if (pDetOpList) + pDetOpList->UpdateReference( this, URM_REORDER, aSourceRange, 0,0,nDz ); + UpdateChartRef( URM_REORDER, + 0,0,nOldPos, MaxCol(),MaxRow(),nOldPos, 0,0,nDz ); + UpdateRefAreaLinks( URM_REORDER, aSourceRange, 0,0,nDz ); + if ( pValidationList ) + pValidationList->UpdateMoveTab(aCxt); + if ( pUnoBroadcaster ) + pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_REORDER, + aSourceRange, 0,0,nDz ) ); + + ScTableUniquePtr pSaveTab = std::move(maTabs[nOldPos]); + maTabs.erase(maTabs.begin()+nOldPos); + maTabs.insert(maTabs.begin()+nNewPos, std::move(pSaveTab)); + for (SCTAB i = 0; i < nTabCount; i++) + if (maTabs[i]) + maTabs[i]->UpdateMoveTab(aCxt, i, pProgress); + for (auto& rxTab : maTabs) + if (rxTab) + rxTab->UpdateCompile(); + SetNoListening( false ); + StartAllListeners(); + + sc::SetFormulaDirtyContext aFormulaDirtyCxt; + SetAllFormulasDirty(aFormulaDirtyCxt); + + if (mpDrawLayer) + mpDrawLayer->ScMovePage( static_cast<sal_uInt16>(nOldPos), static_cast<sal_uInt16>(nNewPos) ); + + bValid = true; + } + } + return bValid; +} + +bool ScDocument::CopyTab( SCTAB nOldPos, SCTAB nNewPos, const ScMarkData* pOnlyMarked ) +{ + if (SC_TAB_APPEND == nNewPos || nNewPos >= static_cast<SCTAB>(maTabs.size())) + nNewPos = static_cast<SCTAB>(maTabs.size()); + OUString aName; + GetName(nOldPos, aName); + + // check first if Prefix is valid; if not, then only avoid duplicates + bool bPrefix = ValidTabName( aName ); + OSL_ENSURE(bPrefix, "invalid table name"); + SCTAB nDummy; + + CreateValidTabName(aName); + + bool bValid; + if (bPrefix) + bValid = ValidNewTabName(aName); + else + bValid = !GetTable( aName, nDummy ); + + sc::AutoCalcSwitch aACSwitch(*this, false); + sc::RefUpdateInsertTabContext aCxt( *this, nNewPos, 1); + + if (bValid) + { + if (nNewPos >= static_cast<SCTAB>(maTabs.size())) + { + nNewPos = static_cast<SCTAB>(maTabs.size()); + maTabs.emplace_back(new ScTable(*this, nNewPos, aName)); + } + else + { + if (ValidTab(nNewPos) && (nNewPos < static_cast<SCTAB>(maTabs.size()))) + { + SetNoListening( true ); + + ScRange aRange( 0,0,nNewPos, MaxCol(),MaxRow(),MAXTAB ); + xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 ); + xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 ); + if (pRangeName) + pRangeName->UpdateInsertTab(aCxt); + + pDBCollection->UpdateReference( + URM_INSDEL, 0,0,nNewPos, 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,nNewPos, MaxCol(),MaxRow(),MAXTAB, 0,0,1 ); + UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,1 ); + if ( pUnoBroadcaster ) + pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,1 ) ); + + for (TableContainer::iterator it = maTabs.begin(); it != maTabs.end(); ++it) + if (*it && it != (maTabs.begin() + nOldPos)) + (*it)->UpdateInsertTab(aCxt); + if (nNewPos <= nOldPos) + nOldPos++; + maTabs.emplace(maTabs.begin() + nNewPos, new ScTable(*this, nNewPos, aName)); + bValid = true; + for (TableContainer::iterator it = maTabs.begin(); it != maTabs.end(); ++it) + if (*it && it != maTabs.begin()+nOldPos && it != maTabs.begin() + nNewPos) + (*it)->UpdateCompile(); + SetNoListening( false ); + sc::StartListeningContext aSLCxt(*this); + for (TableContainer::iterator it = maTabs.begin(); it != maTabs.end(); ++it) + if (*it && it != maTabs.begin()+nOldPos && it != maTabs.begin()+nNewPos) + (*it)->StartListeners(aSLCxt, true); + + if (pValidationList) + pValidationList->UpdateInsertTab(aCxt); + } + else + bValid = false; + } + } + + if (bValid) + { + SetNoListening( true ); // not yet at CopyToTable/Insert + + const bool bGlobalNamesToLocal = true; + const SCTAB nRealOldPos = (nNewPos < nOldPos) ? nOldPos - 1 : nOldPos; + const ScRangeName* pNames = GetRangeName( nOldPos); + if (pNames) + pNames->CopyUsedNames( nOldPos, nRealOldPos, nNewPos, *this, *this, bGlobalNamesToLocal); + GetRangeName()->CopyUsedNames( -1, nRealOldPos, nNewPos, *this, *this, bGlobalNamesToLocal); + + sc::CopyToDocContext aCopyDocCxt(*this); + pDBCollection->CopyToTable(nOldPos, nNewPos); + maTabs[nOldPos]->CopyToTable(aCopyDocCxt, 0, 0, MaxCol(), MaxRow(), InsertDeleteFlags::ALL, + (pOnlyMarked != nullptr), maTabs[nNewPos].get(), pOnlyMarked, + false /*bAsLink*/, true /*bColRowFlags*/, bGlobalNamesToLocal, false /*bCopyCaptions*/ ); + maTabs[nNewPos]->SetTabBgColor(maTabs[nOldPos]->GetTabBgColor()); + + SCTAB nDz = nNewPos - nOldPos; + sc::RefUpdateContext aRefCxt(*this); + aRefCxt.meMode = URM_COPY; + aRefCxt.maRange = ScRange(0, 0, nNewPos, MaxCol(), MaxRow(), nNewPos); + aRefCxt.mnTabDelta = nDz; + maTabs[nNewPos]->UpdateReference(aRefCxt); + + maTabs[nNewPos]->UpdateInsertTabAbs(nNewPos); // move all paragraphs up by one!! + maTabs[nOldPos]->UpdateInsertTab(aCxt); + + maTabs[nOldPos]->UpdateCompile(); + maTabs[nNewPos]->UpdateCompile( true ); // maybe already compiled in Clone, but used names need recompilation + SetNoListening( false ); + sc::StartListeningContext aSLCxt(*this); + maTabs[nOldPos]->StartListeners(aSLCxt, true); + maTabs[nNewPos]->StartListeners(aSLCxt, true); + + sc::SetFormulaDirtyContext aFormulaDirtyCxt; + SetAllFormulasDirty(aFormulaDirtyCxt); + + if (mpDrawLayer) // Skip cloning Note caption object + // page is already created in ScTable ctor + mpDrawLayer->ScCopyPage( static_cast<sal_uInt16>(nOldPos), static_cast<sal_uInt16>(nNewPos) ); + + if (pDPCollection) + pDPCollection->CopyToTab(nOldPos, nNewPos); + + maTabs[nNewPos]->SetPageStyle( maTabs[nOldPos]->GetPageStyle() ); + maTabs[nNewPos]->SetPendingRowHeights( maTabs[nOldPos]->IsPendingRowHeights() ); + + // Copy the custom print range if exists. + maTabs[nNewPos]->CopyPrintRange(*maTabs[nOldPos]); + + // Copy the RTL settings + maTabs[nNewPos]->SetLayoutRTL(maTabs[nOldPos]->IsLayoutRTL()); + maTabs[nNewPos]->SetLoadingRTL(maTabs[nOldPos]->IsLoadingRTL()); + + // Finally copy the note captions, which need + // 1. the updated source ScColumn::nTab members if nNewPos <= nOldPos + // 2. row heights and column widths of the destination + // 3. RTL settings of the destination + maTabs[nOldPos]->CopyCaptionsToTable( 0, 0, MaxCol(), MaxRow(), maTabs[nNewPos].get(), true /*bCloneCaption*/); + } + + return bValid; +} + +sal_uLong ScDocument::TransferTab( ScDocument& rSrcDoc, SCTAB nSrcPos, + SCTAB nDestPos, bool bInsertNew, + bool bResultsOnly ) +{ + sal_uLong nRetVal = 1; // 0 => error 1 = ok + // 3 => NameBox + // 4 => both + + if (rSrcDoc.mpShell->GetMedium()) + { + rSrcDoc.maFileURL = rSrcDoc.mpShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::ToIUri); + // for unsaved files use the title name and adjust during save of file + if (rSrcDoc.maFileURL.isEmpty()) + rSrcDoc.maFileURL = rSrcDoc.mpShell->GetName(); + } + else + { + rSrcDoc.maFileURL = rSrcDoc.mpShell->GetName(); + } + + bool bValid = true; + if (bInsertNew) // re-insert + { + OUString aName; + rSrcDoc.GetName(nSrcPos, aName); + CreateValidTabName(aName); + bValid = InsertTab(nDestPos, aName); + + // Copy the RTL settings + maTabs[nDestPos]->SetLayoutRTL(rSrcDoc.maTabs[nSrcPos]->IsLayoutRTL()); + maTabs[nDestPos]->SetLoadingRTL(rSrcDoc.maTabs[nSrcPos]->IsLoadingRTL()); + } + else // replace existing tables + { + if (ValidTab(nDestPos) && nDestPos < static_cast<SCTAB>(maTabs.size()) && maTabs[nDestPos]) + { + maTabs[nDestPos]->DeleteArea( 0,0, MaxCol(),MaxRow(), InsertDeleteFlags::ALL ); + } + else + bValid = false; + } + + if (bValid) + { + bool bOldAutoCalcSrc = false; + bool bOldAutoCalc = GetAutoCalc(); + SetAutoCalc( false ); // avoid repeated calculations + SetNoListening( true ); + if ( bResultsOnly ) + { + bOldAutoCalcSrc = rSrcDoc.GetAutoCalc(); + rSrcDoc.SetAutoCalc( true ); // in case something needs calculation + } + + { + NumFmtMergeHandler aNumFmtMergeHdl(*this, rSrcDoc); + + sc::CopyToDocContext aCxt(*this); + nDestPos = std::min(nDestPos, static_cast<SCTAB>(GetTableCount() - 1)); + { // scope for bulk broadcast + ScBulkBroadcast aBulkBroadcast( pBASM.get(), SfxHintId::ScDataChanged); + if (!bResultsOnly) + { + const bool bGlobalNamesToLocal = false; + const ScRangeName* pNames = rSrcDoc.GetRangeName( nSrcPos); + if (pNames) + pNames->CopyUsedNames( nSrcPos, nSrcPos, nDestPos, rSrcDoc, *this, bGlobalNamesToLocal); + rSrcDoc.GetRangeName()->CopyUsedNames( -1, nSrcPos, nDestPos, rSrcDoc, *this, bGlobalNamesToLocal); + } + rSrcDoc.maTabs[nSrcPos]->CopyToTable(aCxt, 0, 0, MaxCol(), MaxRow(), + ( bResultsOnly ? InsertDeleteFlags::ALL & ~InsertDeleteFlags::FORMULA : InsertDeleteFlags::ALL), + false, maTabs[nDestPos].get(), /*pMarkData*/nullptr, /*bAsLink*/false, /*bColRowFlags*/true, + /*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true ); + } + } + maTabs[nDestPos]->SetTabNo(nDestPos); + maTabs[nDestPos]->SetTabBgColor(rSrcDoc.maTabs[nSrcPos]->GetTabBgColor()); + + if ( !bResultsOnly ) + { + sc::RefUpdateContext aRefCxt(*this); + aRefCxt.meMode = URM_COPY; + aRefCxt.maRange = ScRange(0, 0, nDestPos, MaxCol(), MaxRow(), nDestPos); + aRefCxt.mnTabDelta = nDestPos - nSrcPos; + maTabs[nDestPos]->UpdateReference(aRefCxt); + + // Readjust self-contained absolute references to this sheet + maTabs[nDestPos]->TestTabRefAbs(nSrcPos); + sc::CompileFormulaContext aFormulaCxt(*this); + maTabs[nDestPos]->CompileAll(aFormulaCxt); + } + + SetNoListening( false ); + if ( !bResultsOnly ) + { + sc::StartListeningContext aSLCxt(*this); + maTabs[nDestPos]->StartListeners(aSLCxt, true); + } + SetDirty( ScRange( 0, 0, nDestPos, MaxCol(), MaxRow(), nDestPos), false); + + if ( bResultsOnly ) + rSrcDoc.SetAutoCalc( bOldAutoCalcSrc ); + SetAutoCalc( bOldAutoCalc ); + + // copy Drawing + + if (bInsertNew) + TransferDrawPage( rSrcDoc, nSrcPos, nDestPos ); + + maTabs[nDestPos]->SetPendingRowHeights( rSrcDoc.maTabs[nSrcPos]->IsPendingRowHeights() ); + } + if (!bValid) + nRetVal = 0; + bool bVbaEnabled = IsInVBAMode(); + + if ( bVbaEnabled ) + { + SfxObjectShell* pSrcShell = rSrcDoc.GetDocumentShell(); + if ( pSrcShell ) + { + OUString aLibName("Standard"); +#if HAVE_FEATURE_SCRIPTING + const BasicManager *pBasicManager = pSrcShell->GetBasicManager(); + if (pBasicManager && !pBasicManager->GetName().isEmpty()) + { + aLibName = pSrcShell->GetBasicManager()->GetName(); + } +#endif + OUString sSource; + uno::Reference< script::XLibraryContainer > xLibContainer = pSrcShell->GetBasicContainer(); + uno::Reference< container::XNameContainer > xLib; + if( xLibContainer.is() ) + { + uno::Any aLibAny = xLibContainer->getByName(aLibName); + aLibAny >>= xLib; + } + + if( xLib.is() ) + { + OUString sSrcCodeName; + rSrcDoc.GetCodeName( nSrcPos, sSrcCodeName ); + OUString sRTLSource; + xLib->getByName( sSrcCodeName ) >>= sRTLSource; + sSource = sRTLSource; + } + VBA_InsertModule( *this, nDestPos, sSource ); + } + } + + return nRetVal; +} + +void ScDocument::SetError( SCCOL nCol, SCROW nRow, SCTAB nTab, const FormulaError nError) +{ + if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size())) + if (maTabs[nTab]) + maTabs[nTab]->SetError( nCol, nRow, nError ); +} + +void ScDocument::SetFormula( + const ScAddress& rPos, const ScTokenArray& rArray ) +{ + if (!TableExists(rPos.Tab())) + return; + + maTabs[rPos.Tab()]->SetFormula(rPos.Col(), rPos.Row(), rArray, formula::FormulaGrammar::GRAM_DEFAULT); +} + +void ScDocument::SetFormula( + const ScAddress& rPos, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram ) +{ + if (!TableExists(rPos.Tab())) + return; + + maTabs[rPos.Tab()]->SetFormula(rPos.Col(), rPos.Row(), rFormula, eGram); +} + +ScFormulaCell* ScDocument::SetFormulaCell( const ScAddress& rPos, ScFormulaCell* pCell ) +{ + if (!TableExists(rPos.Tab())) + { + delete pCell; + return nullptr; + } + + return maTabs[rPos.Tab()]->SetFormulaCell(rPos.Col(), rPos.Row(), pCell); +} + +bool ScDocument::SetFormulaCells( const ScAddress& rPos, std::vector<ScFormulaCell*>& rCells ) +{ + if (rCells.empty()) + return false; + + ScTable* pTab = FetchTable(rPos.Tab()); + if (!pTab) + return false; + + return pTab->SetFormulaCells(rPos.Col(), rPos.Row(), rCells); +} + +void ScDocument::SetConsolidateDlgData( std::unique_ptr<ScConsolidateParam> pData ) +{ + pConsolidateDlgData = std::move(pData); +} + +void ScDocument::SetChangeViewSettings(const ScChangeViewSettings& rNew) +{ + if (pChangeViewSettings==nullptr) + pChangeViewSettings.reset( new ScChangeViewSettings ); + + *pChangeViewSettings=rNew; +} + +std::unique_ptr<ScFieldEditEngine> ScDocument::CreateFieldEditEngine() +{ + std::unique_ptr<ScFieldEditEngine> pNewEditEngine; + if (!pCacheFieldEditEngine) + { + pNewEditEngine.reset( new ScFieldEditEngine( + this, GetEnginePool(), GetEditPool(), false) ); + } + else + { + if ( !bImportingXML ) + { + // #i66209# previous use might not have restored update mode, + // ensure same state as for a new EditEngine (UpdateMode = true) + pCacheFieldEditEngine->SetUpdateLayout(true); + } + + pNewEditEngine = std::move(pCacheFieldEditEngine); + } + return pNewEditEngine; +} + +void ScDocument::DisposeFieldEditEngine(std::unique_ptr<ScFieldEditEngine>& rpEditEngine) +{ + if (!pCacheFieldEditEngine && rpEditEngine) + { + pCacheFieldEditEngine = std::move( rpEditEngine ); + pCacheFieldEditEngine->Clear(); + } + else + rpEditEngine.reset(); +} + +ScLookupCache & ScDocument::GetLookupCache( const ScRange & rRange, ScInterpreterContext* pContext ) +{ + ScLookupCache* pCache = nullptr; + if (!pContext->mxScLookupCache) + pContext->mxScLookupCache.reset(new ScLookupCacheMap); + ScLookupCacheMap* pCacheMap = pContext->mxScLookupCache.get(); + // insert with temporary value to avoid doing two lookups + auto [findIt, bInserted] = pCacheMap->aCacheMap.emplace(rRange, nullptr); + if (bInserted) + { + findIt->second = std::make_unique<ScLookupCache>(this, rRange, *pCacheMap); + pCache = findIt->second.get(); + // The StartListeningArea() call is not thread-safe, as all threads + // would access the same SvtBroadcaster. + std::unique_lock guard( mScLookupMutex ); + StartListeningArea(rRange, false, pCache); + } + else + pCache = (*findIt).second.get(); + + return *pCache; +} + +ScSortedRangeCache& ScDocument::GetSortedRangeCache( const ScRange & rRange, const ScQueryParam& param, + ScInterpreterContext* pContext ) +{ + assert(mxScSortedRangeCache); + ScSortedRangeCache::HashKey key = ScSortedRangeCache::makeHashKey(rRange, param); + // This should be created just once for one range, and repeated calls should reuse it, even + // between threads (it doesn't make sense to use ScInterpreterContext and have all threads + // build their own copy of the same data). So first try read-only access, which should + // in most cases be enough. + { + std::shared_lock guard(mScLookupMutex); + auto findIt = mxScSortedRangeCache->aCacheMap.find(key); + if( findIt != mxScSortedRangeCache->aCacheMap.end()) + return *findIt->second; + } + // Avoid recursive calls because of some cells in the range being dirty and triggering + // interpreting, which may call into this again. Threaded calculation makes sure + // no cells are dirty. If some cells in the range cannot be interpreted and remain + // dirty e.g. because of circular dependencies, create only an invalid empty cache to prevent + // a possible recursive deadlock. + bool invalid = false; + if(!IsThreadedGroupCalcInProgress()) + if(!InterpretCellsIfNeeded(rRange)) + invalid = true; + std::unique_lock guard(mScLookupMutex); + auto [findIt, bInserted] = mxScSortedRangeCache->aCacheMap.emplace(key, nullptr); + if (bInserted) + { + findIt->second = std::make_unique<ScSortedRangeCache>(this, rRange, param, pContext, invalid); + StartListeningArea(rRange, false, findIt->second.get()); + } + return *findIt->second; +} + +void ScDocument::RemoveLookupCache( ScLookupCache & rCache ) +{ + // Data changes leading to this should never happen during calculation (they are either + // a result of user input or recalc). If it turns out this can be the case, locking is needed + // here and also in ScLookupCache::Notify(). + assert(!IsThreadedGroupCalcInProgress()); + auto & cacheMap = rCache.getCacheMap(); + auto it(cacheMap.aCacheMap.find(rCache.getRange())); + if (it != cacheMap.aCacheMap.end()) + { + ScLookupCache* pCache = (*it).second.release(); + cacheMap.aCacheMap.erase(it); + assert(!IsThreadedGroupCalcInProgress()); // EndListeningArea() is not thread-safe + EndListeningArea(pCache->getRange(), false, &rCache); + return; + } + OSL_FAIL( "ScDocument::RemoveLookupCache: range not found in hash map"); +} + +void ScDocument::RemoveSortedRangeCache( ScSortedRangeCache & rCache ) +{ + // Data changes leading to this should never happen during calculation (they are either + // a result of user input or recalc). If it turns out this can be the case, locking is needed + // here and also in ScSortedRangeCache::Notify(). + assert(!IsThreadedGroupCalcInProgress()); + auto it(mxScSortedRangeCache->aCacheMap.find(rCache.getHashKey())); + if (it != mxScSortedRangeCache->aCacheMap.end()) + { + ScSortedRangeCache* pCache = (*it).second.release(); + mxScSortedRangeCache->aCacheMap.erase(it); + assert(!IsThreadedGroupCalcInProgress()); // EndListeningArea() is not thread-safe + EndListeningArea(pCache->getRange(), false, &rCache); + return; + } + OSL_FAIL( "ScDocument::RemoveSortedRangeCache: range not found in hash map"); +} + +void ScDocument::ClearLookupCaches() +{ + assert(!IsThreadedGroupCalcInProgress()); + GetNonThreadedContext().mxScLookupCache.reset(); + mxScSortedRangeCache->aCacheMap.clear(); + // Clear lookup cache in all interpreter-contexts in the (threaded/non-threaded) pools. + ScInterpreterContextPool::ClearLookupCaches(); +} + +bool ScDocument::IsCellInChangeTrack(const ScAddress &cell,Color *pColCellBorder) +{ + ScChangeTrack* pTrack = GetChangeTrack(); + ScChangeViewSettings* pSettings = GetChangeViewSettings(); + if ( !pTrack || !pTrack->GetFirst() || !pSettings || !pSettings->ShowChanges() ) + return false; // missing or turned-off + ScActionColorChanger aColorChanger(*pTrack); + // Clipping happens from outside + //! TODO: without Clipping; only paint affected cells ??!??!? + const ScChangeAction* pAction = pTrack->GetFirst(); + while (pAction) + { + if ( pAction->IsVisible() ) + { + ScChangeActionType eType = pAction->GetType(); + const ScBigRange& rBig = pAction->GetBigRange(); + if ( rBig.aStart.Tab() == cell.Tab()) + { + ScRange aRange = rBig.MakeRange( *this ); + if ( eType == SC_CAT_DELETE_ROWS ) + aRange.aEnd.SetRow( aRange.aStart.Row() ); + else if ( eType == SC_CAT_DELETE_COLS ) + aRange.aEnd.SetCol( aRange.aStart.Col() ); + if (ScViewUtil::IsActionShown( *pAction, *pSettings, *this ) ) + { + if (aRange.Contains(cell)) + { + if (pColCellBorder != nullptr) + { + aColorChanger.Update( *pAction ); + Color aColor( aColorChanger.GetColor() ); + *pColCellBorder = aColor; + } + return true; + } + } + } + if ( eType == SC_CAT_MOVE && + static_cast<const ScChangeActionMove*>(pAction)-> + GetFromRange().aStart.Tab() == cell.Col() ) + { + ScRange aRange = static_cast<const ScChangeActionMove*>(pAction)-> + GetFromRange().MakeRange( *this ); + if (ScViewUtil::IsActionShown( *pAction, *pSettings, *this ) ) + { + if (aRange.Contains(cell)) + { + if (pColCellBorder != nullptr) + { + aColorChanger.Update( *pAction ); + Color aColor( aColorChanger.GetColor() ); + *pColCellBorder = aColor; + } + return true; + } + } + } + } + pAction = pAction->GetNext(); + } + return false; +} + +void ScDocument::GetCellChangeTrackNote( const ScAddress &aCellPos, OUString &aTrackText,bool &bLeftEdge) +{ + aTrackText.clear(); + // Change-Tracking + ScChangeTrack* pTrack = GetChangeTrack(); + ScChangeViewSettings* pSettings = GetChangeViewSettings(); + if ( !(pTrack && pTrack->GetFirst() && pSettings && pSettings->ShowChanges())) + return; + + const ScChangeAction* pFound = nullptr; + const ScChangeAction* pFoundContent = nullptr; + const ScChangeAction* pFoundMove = nullptr; + const ScChangeAction* pAction = pTrack->GetFirst(); + while (pAction) + { + if ( pAction->IsVisible() && + ScViewUtil::IsActionShown( *pAction, *pSettings, *this ) ) + { + ScChangeActionType eType = pAction->GetType(); + const ScBigRange& rBig = pAction->GetBigRange(); + if ( rBig.aStart.Tab() == aCellPos.Tab()) + { + ScRange aRange = rBig.MakeRange( *this ); + if ( eType == SC_CAT_DELETE_ROWS ) + aRange.aEnd.SetRow( aRange.aStart.Row() ); + else if ( eType == SC_CAT_DELETE_COLS ) + aRange.aEnd.SetCol( aRange.aStart.Col() ); + if ( aRange.Contains( aCellPos ) ) + { + pFound = pAction; // the last wins + switch ( eType ) + { + case SC_CAT_CONTENT : + pFoundContent = pAction; + break; + case SC_CAT_MOVE : + pFoundMove = pAction; + break; + default: + break; + } + } + } + if ( eType == SC_CAT_MOVE ) + { + ScRange aRange = + static_cast<const ScChangeActionMove*>(pAction)-> + GetFromRange().MakeRange( *this ); + if ( aRange.Contains( aCellPos ) ) + { + pFound = pAction; + } + } + } + pAction = pAction->GetNext(); + } + if ( !pFound ) + return; + + if ( pFoundContent && pFound->GetType() != SC_CAT_CONTENT ) + pFound = pFoundContent; // Content wins + if ( pFoundMove && pFound->GetType() != SC_CAT_MOVE && + pFoundMove->GetActionNumber() > + pFound->GetActionNumber() ) + pFound = pFoundMove; // Move wins + // for deleted columns: arrow on left side of row + if ( pFound->GetType() == SC_CAT_DELETE_COLS ) + bLeftEdge = true; + DateTime aDT = pFound->GetDateTime(); + aTrackText = pFound->GetUser(); + aTrackText += ", "; + aTrackText += ScGlobal::getLocaleData().getDate(aDT); + aTrackText += " "; + aTrackText += ScGlobal::getLocaleData().getTime(aDT); + aTrackText += ":\n"; + OUString aComStr = pFound->GetComment(); + if(!aComStr.isEmpty()) + { + aTrackText += aComStr; + aTrackText += "\n( "; + } + aTrackText = pFound->GetDescription( *this ); + if (!aComStr.isEmpty()) + { + aTrackText += ")"; + } +} + +void ScDocument::SetPreviewFont( std::unique_ptr<SfxItemSet> pFont ) +{ + pPreviewFont = std::move(pFont); +} + +void ScDocument::SetPreviewSelection( const ScMarkData& rSel ) +{ + maPreviewSelection = rSel; +} + +SfxItemSet* ScDocument::GetPreviewFont( SCCOL nCol, SCROW nRow, SCTAB nTab ) +{ + SfxItemSet* pRet = nullptr; + if ( pPreviewFont ) + { + ScMarkData aSel = GetPreviewSelection(); + if ( aSel.IsCellMarked( nCol, nRow ) && aSel.GetFirstSelected() == nTab ) + pRet = pPreviewFont.get(); + } + return pRet; +} + +ScStyleSheet* ScDocument::GetPreviewCellStyle( SCCOL nCol, SCROW nRow, SCTAB nTab ) +{ + ScStyleSheet* pRet = nullptr; + ScMarkData aSel = GetPreviewSelection(); + if ( pPreviewCellStyle && aSel.IsCellMarked( nCol, nRow ) && aSel.GetFirstSelected() == nTab ) + pRet = pPreviewCellStyle; + return pRet; +} + +sc::IconSetBitmapMap& ScDocument::GetIconSetBitmapMap() +{ + if (!m_pIconSetBitmapMap) + { + m_pIconSetBitmapMap.reset(new sc::IconSetBitmapMap); + } + return *m_pIconSetBitmapMap; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |