1529 lines
53 KiB
C++
1529 lines
53 KiB
C++
/* -*- 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/test_info.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 <comphelper/configuration.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 <docpool.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 (ScModule* mod = ScModule::get())
|
|
jumboSheets = mod->GetDefaultsOptions().GetInitJumboSheets();
|
|
else
|
|
assert(o3tl::IsRunningUnitTest());
|
|
if (jumboSheets)
|
|
return ScSheetLimits(MAXCOL_JUMBO, MAXROW_JUMBO);
|
|
else
|
|
#endif
|
|
return ScSheetLimits(MAXCOL, MAXROW);
|
|
}
|
|
|
|
CellAttributeHelper& ScDocument::getCellAttributeHelper() const
|
|
{
|
|
if (!mpCellAttributeHelper)
|
|
{
|
|
assert(!IsClipOrUndo() && "CellAttributeHelper needs to be shared using SharePooledResources, not created (!)");
|
|
SfxItemPool* pPool(const_cast<ScDocument*>(this)->GetPool());
|
|
assert(nullptr != pPool && "No SfxItemPool for this ScDocument (!)");
|
|
mpCellAttributeHelper.reset(new CellAttributeHelper(*pPool));
|
|
}
|
|
|
|
return *mpCellAttributeHelper;
|
|
}
|
|
|
|
ScDocument::ScDocument( ScDocumentMode eMode, ScDocShell* pDocShell ) :
|
|
mpCellAttributeHelper(),
|
|
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 (!comphelper::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 ) );
|
|
if (mpShell)
|
|
mpShell->SetModified();
|
|
}
|
|
}
|
|
|
|
void ScDocument::EndChangeTracking()
|
|
{
|
|
if (pChangeTrack && mpShell)
|
|
mpShell->SetModified();
|
|
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();
|
|
mpDrawLayer.reset();
|
|
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(getCellAttributeHelper().getDefaultCellAttribute().GetItemSet());
|
|
auto pEEItemSet = std::make_unique<SfxItemSet>(mpNoteEngine->GetEmptyItemSet());
|
|
ScPatternAttr::FillToEditItemSet(*pEEItemSet, rItemSet);
|
|
mpNoteEngine->SetDefaults(std::move(pEEItemSet)); // edit engine takes ownership
|
|
}
|
|
return *mpNoteEngine;
|
|
}
|
|
|
|
std::unique_ptr<EditTextObject> ScDocument::CreateSharedStringTextObject( const svl::SharedString& rSS )
|
|
{
|
|
/* TODO: Add shared string support to the edit engine to make this process
|
|
* simpler. */
|
|
ScFieldEditEngine& rEngine = GetEditEngine();
|
|
rEngine.SetTextCurrentDefaults( rSS.getString());
|
|
std::unique_ptr<EditTextObject> pObj( rEngine.CreateTextObject());
|
|
pObj->NormalizeString( GetSharedStringPool());
|
|
return pObj;
|
|
}
|
|
|
|
void ScDocument::ResetClip( ScDocument* pSourceDoc, const ScMarkData* pMarks )
|
|
{
|
|
if (bIsClip)
|
|
{
|
|
InitClipPtrs(pSourceDoc);
|
|
|
|
for (SCTAB i = 0; i < pSourceDoc->GetTableCount(); i++)
|
|
if (pSourceDoc->maTabs[i])
|
|
if (!pMarks || pMarks->GetTableSelect(i))
|
|
{
|
|
OUString aString = pSourceDoc->maTabs[i]->GetName();
|
|
if (i < GetTableCount())
|
|
{
|
|
maTabs[i].reset( new ScTable(*this, i, aString) );
|
|
|
|
}
|
|
else
|
|
{
|
|
if (i > GetTableCount())
|
|
{
|
|
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 >= GetTableCount())
|
|
{
|
|
maTabs.resize(nTab+1);
|
|
}
|
|
maTabs[nTab].reset( new ScTable(*this, nTab, u"baeh"_ustr) );
|
|
if (nTab < pSourceDoc->GetTableCount() && 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 (nTab >= GetTableCount())
|
|
maTabs.resize(nTab+1);
|
|
|
|
if (!maTabs[nTab])
|
|
maTabs[nTab].reset( new ScTable(*this, nTab, u"temp"_ustr, bExtras, bExtras) );
|
|
}
|
|
|
|
ScRefCellValue ScDocument::GetRefCellValue( const ScAddress& rPos )
|
|
{
|
|
if (ScTable* pTable = FetchTable(rPos.Tab()))
|
|
return pTable->GetRefCellValue(rPos.Col(), rPos.Row());
|
|
return ScRefCellValue(); // empty
|
|
}
|
|
|
|
ScRefCellValue ScDocument::GetRefCellValue( const ScAddress& rPos, sc::ColumnBlockPosition& rBlockPos )
|
|
{
|
|
if (ScTable* pTable = FetchTable(rPos.Tab()))
|
|
return pTable->GetRefCellValue(rPos.Col(), rPos.Row(), rBlockPos);
|
|
return ScRefCellValue(); // empty
|
|
}
|
|
|
|
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 (const ScTable* pTable = FetchTable(nTab))
|
|
{
|
|
bool bAny = pTable->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 (const ScTable* pTable = FetchTable(nTab))
|
|
{
|
|
bool bAny = pTable->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 (const ScTable* pTable = FetchTable(nTab))
|
|
{
|
|
bool bAny = pTable->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 (const ScTable* pTable = FetchTable(nTab))
|
|
{
|
|
bool bAny = pTable->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 = GetCellArea(nTab, rEndCol, rEndRow);
|
|
|
|
// 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 = GetTableCount();
|
|
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 >= GetTableCount())
|
|
nNewPos = GetTableCount();
|
|
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 >= GetTableCount())
|
|
{
|
|
nNewPos = GetTableCount();
|
|
maTabs.emplace_back(new ScTable(*this, nNewPos, aName));
|
|
}
|
|
else
|
|
{
|
|
if (ValidTab(nNewPos) && nNewPos < GetTableCount())
|
|
{
|
|
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;
|
|
}
|
|
|
|
bool ScDocument::TransferTab( ScDocument& rSrcDoc, SCTAB nSrcPos,
|
|
SCTAB nDestPos, bool bInsertNew,
|
|
bool bResultsOnly )
|
|
{
|
|
bool bRetVal = true;
|
|
|
|
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 (ScTable* pTable = FetchTable(nDestPos))
|
|
{
|
|
pTable->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());
|
|
|
|
// tdf#66613 - copy existing print ranges and col/row repetitions
|
|
if (auto aRepeatColRange = rSrcDoc.maTabs[nSrcPos]->GetRepeatColRange())
|
|
{
|
|
aRepeatColRange->aStart.SetTab(nDestPos);
|
|
aRepeatColRange->aEnd.SetTab(nDestPos);
|
|
maTabs[nDestPos]->SetRepeatColRange(std::move(aRepeatColRange));
|
|
}
|
|
|
|
if (auto aRepeatRowRange = rSrcDoc.maTabs[nSrcPos]->GetRepeatRowRange())
|
|
{
|
|
aRepeatRowRange->aStart.SetTab(nDestPos);
|
|
aRepeatRowRange->aEnd.SetTab(nDestPos);
|
|
maTabs[nDestPos]->SetRepeatRowRange(std::move(aRepeatRowRange));
|
|
}
|
|
|
|
if (rSrcDoc.IsPrintEntireSheet(nSrcPos))
|
|
maTabs[nDestPos]->SetPrintEntireSheet();
|
|
else
|
|
{
|
|
// tdf#157897 - clear print ranges before adding additional ones
|
|
maTabs[nDestPos]->ClearPrintRanges();
|
|
const auto nPrintRangeCount = rSrcDoc.maTabs[nSrcPos]->GetPrintRangeCount();
|
|
for (auto nPos = 0; nPos < nPrintRangeCount; nPos++)
|
|
{
|
|
// Adjust the tab for the print range at the new position
|
|
ScRange aSrcPrintRange(*rSrcDoc.maTabs[nSrcPos]->GetPrintRange(nPos));
|
|
aSrcPrintRange.aStart.SetTab(nDestPos);
|
|
aSrcPrintRange.aEnd.SetTab(nDestPos);
|
|
maTabs[nDestPos]->AddPrintRange(aSrcPrintRange);
|
|
}
|
|
}
|
|
|
|
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)
|
|
bRetVal = false;
|
|
bool bVbaEnabled = IsInVBAMode();
|
|
|
|
if ( bVbaEnabled )
|
|
{
|
|
ScDocShell* pSrcShell = rSrcDoc.GetDocumentShell();
|
|
if ( pSrcShell )
|
|
{
|
|
OUString aLibName(u"Standard"_ustr);
|
|
#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;
|
|
if (xLib->hasByName( sSrcCodeName ))
|
|
xLib->getByName( sSrcCodeName ) >>= sRTLSource;
|
|
sSource = sRTLSource;
|
|
}
|
|
VBA_InsertModule( *this, nDestPos, sSource );
|
|
}
|
|
}
|
|
|
|
return bRetVal;
|
|
}
|
|
|
|
void ScDocument::SetError( SCCOL nCol, SCROW nRow, SCTAB nTab, const FormulaError nError)
|
|
{
|
|
if (ScTable* pTable = FetchTable(nTab))
|
|
pTable->SetError(nCol, nRow, nError);
|
|
}
|
|
|
|
void ScDocument::SetFormula(
|
|
const ScAddress& rPos, const ScTokenArray& rArray )
|
|
{
|
|
if (ScTable* pTable = FetchTable(rPos.Tab()))
|
|
pTable->SetFormula(rPos.Col(), rPos.Row(), rArray, formula::FormulaGrammar::GRAM_DEFAULT);
|
|
}
|
|
|
|
void ScDocument::SetFormula(
|
|
const ScAddress& rPos, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram )
|
|
{
|
|
if (ScTable* pTable = FetchTable(rPos.Tab()))
|
|
pTable->SetFormula(rPos.Col(), rPos.Row(), rFormula, eGram);
|
|
}
|
|
|
|
ScFormulaCell* ScDocument::SetFormulaCell( const ScAddress& rPos, ScFormulaCell* pCell )
|
|
{
|
|
if (ScTable* pTable = FetchTable(rPos.Tab()))
|
|
return pTable->SetFormulaCell(rPos.Col(), rPos.Row(), pCell);
|
|
|
|
delete pCell;
|
|
return nullptr;
|
|
}
|
|
|
|
bool ScDocument::SetFormulaCells( const ScAddress& rPos, std::vector<ScFormulaCell*>& rCells )
|
|
{
|
|
if (rCells.empty())
|
|
return false;
|
|
|
|
if (ScTable* pTable = FetchTable(rPos.Tab()))
|
|
return pTable->SetFormulaCells(rPos.Col(), rPos.Row(), rCells);
|
|
return false;
|
|
}
|
|
|
|
void ScDocument::SetConsolidateDlgData( std::unique_ptr<ScConsolidateParam> pData )
|
|
{
|
|
pConsolidateDlgData = std::move(pData);
|
|
}
|
|
|
|
void ScDocument::SetEasyConditionalFormatDialogData(std::unique_ptr<ScConditionMode> pMode)
|
|
{
|
|
pConditionalFormatDialogMode = std::move(pMode);
|
|
}
|
|
|
|
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, bool bNewSearchFunction,
|
|
sal_uInt8 nSortedBinarySearch )
|
|
{
|
|
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, bNewSearchFunction, nSortedBinarySearch);
|
|
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())
|
|
{
|
|
std::unique_ptr<ScLookupCache> xCache = std::move(it->second);
|
|
cacheMap.aCacheMap.erase(it);
|
|
assert(!IsThreadedGroupCalcInProgress()); // EndListeningArea() is not thread-safe
|
|
EndListeningArea(xCache->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())
|
|
{
|
|
std::unique_ptr<ScSortedRangeCache> xCache = std::move(it->second);
|
|
mxScSortedRangeCache->aCacheMap.erase(it);
|
|
assert(!IsThreadedGroupCalcInProgress()); // EndListeningArea() is not thread-safe
|
|
EndListeningArea(xCache->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(this);
|
|
}
|
|
|
|
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: */
|