/* -*- 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 .
*/
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));
}
/* 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 );
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();
}
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
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();
// 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() );
}
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");
}
}
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();
// check first if Prefix is valid; if not, then only avoid duplicates bool bPrefix = ValidTabName( aName );
OSL_ENSURE(bPrefix, "invalid table name");
SCTAB nDummy;
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
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);
// 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*/);
}
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();
}
// 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(); constauto 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);
}
}
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);
}
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);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.