tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / core / data / documen2.cxx
blob3890a5194e8531f5a7b2531b9ccfbf50a306bb74
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <scextopt.hxx>
21 #include <autonamecache.hxx>
23 #include <o3tl/test_info.hxx>
24 #include <osl/thread.h>
25 #include <svx/xtable.hxx>
26 #include <sfx2/bindings.hxx>
27 #include <sfx2/objsh.hxx>
28 #include <sfx2/docfile.hxx>
29 #include <sfx2/printer.hxx>
30 #include <svl/asiancfg.hxx>
31 #include <vcl/virdev.hxx>
32 #include <svl/sharedstringpool.hxx>
33 #include <tools/urlobj.hxx>
34 #include <rtl/crc.h>
35 #include <basic/basmgr.hxx>
36 #include <comphelper/threadpool.hxx>
37 #include <sal/log.hxx>
38 #include <osl/diagnose.h>
39 #include <comphelper/configuration.hxx>
41 #include <scmod.hxx>
42 #include <document.hxx>
43 #include <table.hxx>
44 #include <patattr.hxx>
45 #include <rangenam.hxx>
46 #include <dbdata.hxx>
47 #include <chartlock.hxx>
48 #include <rechead.hxx>
49 #include <global.hxx>
50 #include <bcaslot.hxx>
51 #include <adiasync.hxx>
52 #include <addinlis.hxx>
53 #include <chartlis.hxx>
54 #include <markdata.hxx>
55 #include <validat.hxx>
56 #include <detdata.hxx>
57 #include <defaultsoptions.hxx>
58 #include <ddelink.hxx>
59 #include <chgtrack.hxx>
60 #include <chgviset.hxx>
61 #include <editutil.hxx>
62 #include <hints.hxx>
63 #include <dpobject.hxx>
64 #include <scrdata.hxx>
65 #include <poolhelp.hxx>
66 #include <unoreflist.hxx>
67 #include <listenercalls.hxx>
68 #include <recursionhelper.hxx>
69 #include <lookupcache.hxx>
70 #include <rangecache.hxx>
71 #include <externalrefmgr.hxx>
72 #include <viewdata.hxx>
73 #include <viewutil.hxx>
74 #include <tabprotection.hxx>
75 #include <formulaparserpool.hxx>
76 #include <clipparam.hxx>
77 #include <macromgr.hxx>
78 #include <formulacell.hxx>
79 #include <clipcontext.hxx>
80 #include <refupdatecontext.hxx>
81 #include <refreshtimerprotector.hxx>
82 #include <scopetools.hxx>
83 #include <documentlinkmgr.hxx>
84 #include <interpre.hxx>
85 #include <tokenstringcontext.hxx>
86 #include <docsh.hxx>
87 #include <clipoptions.hxx>
88 #include <listenercontext.hxx>
89 #include <datamapper.hxx>
90 #include <drwlayer.hxx>
91 #include <sharedstringpoolpurge.hxx>
92 #include <docpool.hxx>
93 #include <config_features.h>
95 using namespace com::sun::star;
97 const sal_uInt16 ScDocument::nSrcVer = SC_CURRENT_VERSION;
99 ScSheetLimits ScSheetLimits::CreateDefault()
101 #if HAVE_FEATURE_JUMBO_SHEETS
102 bool jumboSheets = false;
103 if (ScModule* mod = ScModule::get())
104 jumboSheets = mod->GetDefaultsOptions().GetInitJumboSheets();
105 else
106 assert(o3tl::IsRunningUnitTest());
107 if (jumboSheets)
108 return ScSheetLimits(MAXCOL_JUMBO, MAXROW_JUMBO);
109 else
110 #endif
111 return ScSheetLimits(MAXCOL, MAXROW);
114 CellAttributeHelper& ScDocument::getCellAttributeHelper() const
116 if (!mpCellAttributeHelper)
118 assert(!IsClipOrUndo() && "CellAttributeHelper needs to be shared using SharePooledResources, not created (!)");
119 SfxItemPool* pPool(const_cast<ScDocument*>(this)->GetPool());
120 assert(nullptr != pPool && "No SfxItemPool for this ScDocument (!)");
121 mpCellAttributeHelper.reset(new CellAttributeHelper(*pPool));
124 return *mpCellAttributeHelper;
127 ScDocument::ScDocument( ScDocumentMode eMode, ScDocShell* pDocShell ) :
128 mpCellAttributeHelper(),
129 mpCellStringPool(std::make_shared<svl::SharedStringPool>(ScGlobal::getCharClass())),
130 mpDocLinkMgr(new sc::DocumentLinkManager(pDocShell)),
131 mbFormulaGroupCxtBlockDiscard(false),
132 maCalcConfig( ScInterpreter::GetGlobalConfig()),
133 mpUndoManager( nullptr ),
134 mpShell( pDocShell ),
135 mpPrinter( nullptr ),
136 mpVirtualDevice_100th_mm( nullptr ),
137 pFormatExchangeList( nullptr ),
138 mxSheetLimits(new ScSheetLimits(ScSheetLimits::CreateDefault())),
139 pFormulaTree( nullptr ),
140 pEOFormulaTree( nullptr ),
141 pFormulaTrack( nullptr ),
142 pEOFormulaTrack( nullptr ),
143 pPreviewCellStyle( nullptr ),
144 maPreviewSelection(*mxSheetLimits),
145 nUnoObjectId( 0 ),
146 nRangeOverflowType( 0 ),
147 aCurTextWidthCalcPos(MaxCol(),0,0),
148 aTrackIdle("sc ScDocument Track Idle"),
149 nFormulaCodeInTree(0),
150 nXMLImportedFormulaCount( 0 ),
151 nInterpretLevel(0),
152 nMacroInterpretLevel(0),
153 nInterpreterTableOpLevel(0),
154 maInterpreterContext( *this, nullptr ),
155 mxScSortedRangeCache(new ScSortedRangeCacheMap),
156 nFormulaTrackCount(0),
157 eHardRecalcState(HardRecalcState::OFF),
158 nVisibleTab( 0 ),
159 nPosLeft( 0 ),
160 nPosTop( 0 ),
161 eLinkMode(LM_UNKNOWN),
162 bAutoCalc( eMode == SCDOCMODE_DOCUMENT || eMode == SCDOCMODE_FUNCTIONACCESS ),
163 bAutoCalcShellDisabled( false ),
164 bForcedFormulaPending( false ),
165 bCalculatingFormulaTree( false ),
166 bIsClip( eMode == SCDOCMODE_CLIP ),
167 bIsUndo( eMode == SCDOCMODE_UNDO ),
168 bIsFunctionAccess( eMode == SCDOCMODE_FUNCTIONACCESS ),
169 bIsVisible( false ),
170 bIsEmbedded( false ),
171 bInsertingFromOtherDoc( false ),
172 bLoadingMedium( false ),
173 bImportingXML( false ),
174 bCalcingAfterLoad( false ),
175 bNoListening( false ),
176 mbIdleEnabled(true),
177 bInLinkUpdate( false ),
178 bChartListenerCollectionNeedsUpdate( false ),
179 bHasForcedFormulas( false ),
180 bInDtorClear( false ),
181 bExpandRefs( false ),
182 bDetectiveDirty( false ),
183 bDelayedDeletingBroadcasters( false ),
184 bLinkFormulaNeedingCheck( false ),
185 nAsianCompression(CharCompressType::Invalid),
186 nAsianKerning(SC_ASIANKERNING_INVALID),
187 bPastingDrawFromOtherDoc( false ),
188 nInDdeLinkUpdate( 0 ),
189 bInUnoBroadcast( false ),
190 bInUnoListenerCall( false ),
191 nAdjustHeightLock(0),
192 eGrammar( formula::FormulaGrammar::GRAM_NATIVE ),
193 bStyleSheetUsageInvalid( true ),
194 mbUndoEnabled( true ),
195 mbExecuteLinkEnabled( true ),
196 mbChangeReadOnlyEnabled( false ),
197 mbStreamValidLocked( false ),
198 mbUserInteractionEnabled(true),
199 mnNamedRangesLockCount(0),
200 mbEmbedFonts(false),
201 mbEmbedUsedFontsOnly(false),
202 mbEmbedFontScriptLatin(true),
203 mbEmbedFontScriptAsian(true),
204 mbEmbedFontScriptComplex(true),
205 mnImagePreferredDPI(0),
206 mbTrackFormulasPending(false),
207 mbFinalTrackFormulas(false),
208 mbDocShellRecalc(false),
209 mbLayoutStrings(false),
210 mnMutationGuardFlags(0)
212 maPreviewSelection = { *mxSheetLimits };
213 aCurTextWidthCalcPos = { MaxCol(), 0, 0 };
215 SetStorageGrammar( formula::FormulaGrammar::GRAM_STORAGE_DEFAULT);
217 eSrcSet = osl_getThreadTextEncoding();
219 /* TODO: for SCDOCMODE_FUNCTIONACCESS it might not even be necessary to
220 * have all of these available. */
221 if ( eMode == SCDOCMODE_DOCUMENT || eMode == SCDOCMODE_FUNCTIONACCESS )
223 mxPoolHelper = new ScPoolHelper( *this );
224 if (!comphelper::IsFuzzing()) //just too slow
225 pBASM.reset( new ScBroadcastAreaSlotMachine( this ) );
226 pChartListenerCollection.reset( new ScChartListenerCollection( *this ) );
227 pRefreshTimerControl.reset( new ScRefreshTimerControl );
229 else
231 pChartListenerCollection = nullptr;
234 pDBCollection.reset( new ScDBCollection(*this) );
235 pSelectionAttr = nullptr;
236 apTemporaryChartLock.reset( new ScTemporaryChartLock(this) );
237 xColNameRanges = new ScRangePairList;
238 xRowNameRanges = new ScRangePairList;
239 ImplCreateOptions();
240 // languages for a visible document are set by docshell later (from options)
241 SetLanguage( ScGlobal::eLnge, ScGlobal::eLnge, ScGlobal::eLnge );
243 aTrackIdle.SetInvokeHandler( LINK( this, ScDocument, TrackTimeHdl ) );
246 sfx2::LinkManager* ScDocument::GetLinkManager()
248 return GetDocLinkManager().getLinkManager();
251 const sfx2::LinkManager* ScDocument::GetLinkManager() const
253 return GetDocLinkManager().getExistingLinkManager();
256 sc::DocumentLinkManager& ScDocument::GetDocLinkManager()
258 return *mpDocLinkMgr;
261 const sc::DocumentLinkManager& ScDocument::GetDocLinkManager() const
263 return const_cast<ScDocument*>(this)->GetDocLinkManager();
266 void ScDocument::SetStorageGrammar( formula::FormulaGrammar::Grammar eGram )
268 OSL_PRECOND(
269 eGram == formula::FormulaGrammar::GRAM_ODFF ||
270 eGram == formula::FormulaGrammar::GRAM_PODF,
271 "ScDocument::SetStorageGrammar: wrong storage grammar");
273 eStorageGrammar = eGram;
276 void ScDocument::SetDocVisible( bool bSet )
278 // called from view ctor - only for a visible document,
279 // each new sheet's RTL flag is initialized from the locale
280 bIsVisible = bSet;
283 sal_uInt32 ScDocument::GetDocumentID() const
285 const ScDocument* pThis = this;
286 sal_uInt32 nCrc = rtl_crc32( 0, &pThis, sizeof(ScDocument*) );
287 // the this pointer only might not be sufficient
288 nCrc = rtl_crc32( nCrc, &mpShell, sizeof(SfxObjectShell*) );
289 return nCrc;
292 void ScDocument::StartChangeTracking()
294 if (!pChangeTrack)
296 pChangeTrack.reset( new ScChangeTrack( *this ) );
297 if (mpShell)
298 mpShell->SetModified();
302 void ScDocument::EndChangeTracking()
304 if (pChangeTrack && mpShell)
305 mpShell->SetModified();
306 pChangeTrack.reset();
309 void ScDocument::SetChangeTrack( std::unique_ptr<ScChangeTrack> pTrack )
311 OSL_ENSURE( &pTrack->GetDocument() == this, "SetChangeTrack: different documents" );
312 if ( !pTrack || pTrack == pChangeTrack || &pTrack->GetDocument() != this )
313 return ;
314 EndChangeTracking();
315 pChangeTrack = std::move(pTrack);
318 IMPL_LINK_NOARG(ScDocument, TrackTimeHdl, Timer *, void)
320 if ( ScDdeLink::IsInUpdate() ) // do not nest
322 aTrackIdle.Start(); // try again later
324 else if (mpShell) // execute
326 TrackFormulas();
327 mpShell->Broadcast( SfxHint( SfxHintId::ScDataChanged ) );
329 if (!mpShell->IsModified())
331 mpShell->SetModified();
332 SfxBindings* pBindings = GetViewBindings();
333 if (pBindings)
335 pBindings->Invalidate( SID_SAVEDOC );
336 pBindings->Invalidate( SID_DOC_MODIFIED );
342 void ScDocument::SetExpandRefs( bool bVal )
344 bExpandRefs = bVal;
347 void ScDocument::StartTrackTimer()
349 if (!aTrackIdle.IsActive()) // do not postpone for forever
350 aTrackIdle.Start();
353 void ScDocument::ClosingClipboardSource()
355 if (!bIsClip)
356 return;
358 ForgetNoteCaptions( ScRangeList( ScRange( 0,0,0, MaxCol(), MaxRow(), GetTableCount()-1)), true);
361 ScDocument::~ScDocument()
363 OSL_PRECOND( !bInLinkUpdate, "bInLinkUpdate in dtor" );
365 // Join any pending(recalc) threads in global threadpool
366 comphelper::ThreadPool::getSharedOptimalPool().joinThreadsIfIdle();
368 bInDtorClear = true;
370 // first of all disable all refresh timers by deleting the control
371 if ( pRefreshTimerControl )
372 { // To be sure there isn't anything running do it with a protector,
373 // this ensures also that nothing needs the control anymore.
374 ScRefreshTimerProtector aProt( GetRefreshTimerControlAddress() );
375 pRefreshTimerControl.reset();
378 mxFormulaParserPool.reset();
379 // Destroy the external ref mgr instance here because it has a timer
380 // which needs to be stopped before the app closes.
381 pExternalRefMgr.reset();
383 ScAddInAsync::RemoveDocument( this );
384 ScAddInListener::RemoveDocument( this );
385 pChartListenerCollection.reset(); // before pBASM because of potential Listener!
387 ClearLookupCaches(); // before pBASM because of listeners
389 // destroy BroadcastAreas first to avoid un-needed Single-EndListenings of Formula-Cells
390 pBASM.reset(); // BroadcastAreaSlotMachine
392 pUnoBroadcaster.reset(); // broadcasts SfxHintId::Dying again
394 pUnoRefUndoList.reset();
395 pUnoListenerCalls.reset();
397 Clear( true ); // true = from destructor (needed for SdrModel::ClearModel)
399 pValidationList.reset();
400 pRangeName.reset();
401 pDBCollection.reset();
402 pSelectionAttr.reset();
403 apTemporaryChartLock.reset();
404 mpDrawLayer.reset();
405 mpPrinter.disposeAndClear();
406 ImplDeleteOptions();
407 pConsolidateDlgData.reset();
408 pClipData.reset();
409 pDetOpList.reset(); // also deletes entries
410 pChangeTrack.reset();
411 mpEditEngine.reset();
412 mpNoteEngine.reset();
413 pChangeViewSettings.reset(); // and delete
414 mpVirtualDevice_100th_mm.disposeAndClear();
416 pDPCollection.reset();
417 mpAnonymousDBData.reset();
419 // delete the EditEngine before destroying the mxPoolHelper
420 pCacheFieldEditEngine.reset();
422 if ( mxPoolHelper.is() && !bIsClip && !bIsUndo)
423 mxPoolHelper->SourceDocumentGone();
424 mxPoolHelper.clear();
426 pScriptTypeData.reset();
427 maNonThreaded.xRecursionHelper.reset();
428 assert(!maThreadSpecific.xRecursionHelper);
430 pPreviewFont.reset();
431 SAL_WARN_IF( pAutoNameCache, "sc.core", "AutoNameCache still set in dtor" );
433 mpFormulaGroupCxt.reset();
434 // Purge unused items if the string pool will be still used (e.g. by undo history).
435 if(mpCellStringPool.use_count() > 1)
437 // Calling purge() may be somewhat expensive with large documents, so
438 // try to delay and compress it for temporary documents.
439 if(IsClipOrUndo())
440 ScGlobal::GetSharedStringPoolPurge().delayedPurge(mpCellStringPool);
441 else
442 mpCellStringPool->purge();
444 mpCellStringPool.reset();
446 assert( pDelayedFormulaGrouping == nullptr );
447 assert( pDelayedStartListeningFormulaCells.empty());
450 void ScDocument::InitClipPtrs( ScDocument* pSourceDoc )
452 OSL_ENSURE(bIsClip, "InitClipPtrs and not bIsClip");
454 ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
456 pValidationList.reset();
458 Clear();
460 SharePooledResources(pSourceDoc);
462 // conditional Formats / validations
463 // TODO: Copy Templates?
464 const ScValidationDataList* pSourceValid = pSourceDoc->pValidationList.get();
465 if ( pSourceValid )
466 pValidationList.reset(new ScValidationDataList(*this, *pSourceValid));
468 // store Links in Stream
469 pClipData.reset();
470 if (pSourceDoc->GetDocLinkManager().hasDdeLinks())
472 pClipData.reset( new SvMemoryStream );
473 pSourceDoc->SaveDdeLinks(*pClipData);
476 // Options pointers exist (ImplCreateOptions) for any document.
477 // Must be copied for correct results in OLE objects (#i42666#).
478 SetDocOptions( pSourceDoc->GetDocOptions() );
479 SetViewOptions( pSourceDoc->GetViewOptions() );
482 SvNumberFormatter* ScDocument::GetFormatTable() const
484 assert(!IsThreadedGroupCalcInProgress());
485 return mxPoolHelper->GetFormTable();
488 SfxItemPool* ScDocument::GetEditPool() const
490 return mxPoolHelper->GetEditPool();
493 SfxItemPool* ScDocument::GetEnginePool() const
495 return mxPoolHelper->GetEnginePool();
498 ScFieldEditEngine& ScDocument::GetEditEngine()
500 if ( !mpEditEngine )
502 mpEditEngine.reset( new ScFieldEditEngine(this, GetEnginePool(), GetEditPool()) );
503 mpEditEngine->SetUpdateLayout( false );
504 mpEditEngine->EnableUndo( false );
505 mpEditEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM));
506 ApplyAsianEditSettings( *mpEditEngine );
508 return *mpEditEngine;
511 ScNoteEditEngine& ScDocument::GetNoteEngine()
513 if ( !mpNoteEngine )
515 ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
516 mpNoteEngine.reset( new ScNoteEditEngine( GetEnginePool(), GetEditPool() ) );
517 mpNoteEngine->SetUpdateLayout( false );
518 mpNoteEngine->EnableUndo( false );
519 mpNoteEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM));
520 ApplyAsianEditSettings( *mpNoteEngine );
521 const SfxItemSet& rItemSet(getCellAttributeHelper().getDefaultCellAttribute().GetItemSet());
522 auto pEEItemSet = std::make_unique<SfxItemSet>(mpNoteEngine->GetEmptyItemSet());
523 ScPatternAttr::FillToEditItemSet(*pEEItemSet, rItemSet);
524 mpNoteEngine->SetDefaults(std::move(pEEItemSet)); // edit engine takes ownership
526 return *mpNoteEngine;
529 std::unique_ptr<EditTextObject> ScDocument::CreateSharedStringTextObject( const svl::SharedString& rSS )
531 /* TODO: Add shared string support to the edit engine to make this process
532 * simpler. */
533 ScFieldEditEngine& rEngine = GetEditEngine();
534 rEngine.SetTextCurrentDefaults( rSS.getString());
535 std::unique_ptr<EditTextObject> pObj( rEngine.CreateTextObject());
536 pObj->NormalizeString( GetSharedStringPool());
537 return pObj;
540 void ScDocument::ResetClip( ScDocument* pSourceDoc, const ScMarkData* pMarks )
542 if (bIsClip)
544 InitClipPtrs(pSourceDoc);
546 for (SCTAB i = 0; i < pSourceDoc->GetTableCount(); i++)
547 if (pSourceDoc->maTabs[i])
548 if (!pMarks || pMarks->GetTableSelect(i))
550 OUString aString = pSourceDoc->maTabs[i]->GetName();
551 if (i < GetTableCount())
553 maTabs[i].reset( new ScTable(*this, i, aString) );
556 else
558 if (i > GetTableCount())
560 maTabs.resize(i);
562 maTabs.emplace_back(new ScTable(*this, i, aString));
564 maTabs[i]->SetLayoutRTL( pSourceDoc->maTabs[i]->IsLayoutRTL() );
567 else
569 OSL_FAIL("ResetClip");
573 void ScDocument::ResetClip( ScDocument* pSourceDoc, SCTAB nTab )
575 if (bIsClip)
577 InitClipPtrs(pSourceDoc);
578 if (nTab >= GetTableCount())
580 maTabs.resize(nTab+1);
582 maTabs[nTab].reset( new ScTable(*this, nTab, u"baeh"_ustr) );
583 if (nTab < pSourceDoc->GetTableCount() && pSourceDoc->maTabs[nTab])
584 maTabs[nTab]->SetLayoutRTL( pSourceDoc->maTabs[nTab]->IsLayoutRTL() );
586 else
588 OSL_FAIL("ResetClip");
592 void ScDocument::EnsureTable( SCTAB nTab )
594 bool bExtras = !bIsUndo; // Column-Widths, Row-Heights, Flags
595 if (nTab >= GetTableCount())
596 maTabs.resize(nTab+1);
598 if (!maTabs[nTab])
599 maTabs[nTab].reset( new ScTable(*this, nTab, u"temp"_ustr, bExtras, bExtras) );
602 ScRefCellValue ScDocument::GetRefCellValue( const ScAddress& rPos )
604 if (ScTable* pTable = FetchTable(rPos.Tab()))
605 return pTable->GetRefCellValue(rPos.Col(), rPos.Row());
606 return ScRefCellValue(); // empty
609 ScRefCellValue ScDocument::GetRefCellValue( const ScAddress& rPos, sc::ColumnBlockPosition& rBlockPos )
611 if (ScTable* pTable = FetchTable(rPos.Tab()))
612 return pTable->GetRefCellValue(rPos.Col(), rPos.Row(), rBlockPos);
613 return ScRefCellValue(); // empty
616 svl::SharedStringPool& ScDocument::GetSharedStringPool()
618 return *mpCellStringPool;
621 const svl::SharedStringPool& ScDocument::GetSharedStringPool() const
623 return *mpCellStringPool;
626 bool ScDocument::GetPrintArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow,
627 bool bNotes) const
629 if (const ScTable* pTable = FetchTable(nTab))
631 bool bAny = pTable->GetPrintArea( rEndCol, rEndRow, bNotes, /*bCalcHiddens*/false);
632 if (mpDrawLayer)
634 ScRange aDrawRange(0,0,nTab, MaxCol(),MaxRow(),nTab);
635 if (DrawGetPrintArea( aDrawRange, true, true ))
637 if (aDrawRange.aEnd.Col()>rEndCol) rEndCol=aDrawRange.aEnd.Col();
638 if (aDrawRange.aEnd.Row()>rEndRow) rEndRow=aDrawRange.aEnd.Row();
639 bAny = true;
642 return bAny;
645 rEndCol = 0;
646 rEndRow = 0;
647 return false;
650 bool ScDocument::GetPrintAreaHor( SCTAB nTab, SCROW nStartRow, SCROW nEndRow,
651 SCCOL& rEndCol ) const
653 if (const ScTable* pTable = FetchTable(nTab))
655 bool bAny = pTable->GetPrintAreaHor( nStartRow, nEndRow, rEndCol );
656 if (mpDrawLayer)
658 ScRange aDrawRange(0,nStartRow,nTab, MaxCol(),nEndRow,nTab);
659 if (DrawGetPrintArea( aDrawRange, true, false ))
661 if (aDrawRange.aEnd.Col()>rEndCol) rEndCol=aDrawRange.aEnd.Col();
662 bAny = true;
665 return bAny;
668 rEndCol = 0;
669 return false;
672 bool ScDocument::GetPrintAreaVer( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol,
673 SCROW& rEndRow, bool bNotes ) const
675 if (const ScTable* pTable = FetchTable(nTab))
677 bool bAny = pTable->GetPrintAreaVer( nStartCol, nEndCol, rEndRow, bNotes );
678 if (mpDrawLayer)
680 ScRange aDrawRange(nStartCol,0,nTab, nEndCol,MaxRow(),nTab);
681 if (DrawGetPrintArea( aDrawRange, false, true ))
683 if (aDrawRange.aEnd.Row()>rEndRow) rEndRow=aDrawRange.aEnd.Row();
684 bAny = true;
687 return bAny;
690 rEndRow = 0;
691 return false;
694 bool ScDocument::GetDataStart( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow ) const
696 if (const ScTable* pTable = FetchTable(nTab))
698 bool bAny = pTable->GetDataStart( rStartCol, rStartRow );
699 if (mpDrawLayer)
701 ScRange aDrawRange(0,0,nTab, MaxCol(),MaxRow(),nTab);
702 if (DrawGetPrintArea( aDrawRange, true, true ))
704 if (aDrawRange.aStart.Col()<rStartCol) rStartCol=aDrawRange.aStart.Col();
705 if (aDrawRange.aStart.Row()<rStartRow) rStartRow=aDrawRange.aStart.Row();
706 bAny = true;
709 return bAny;
712 rStartCol = 0;
713 rStartRow = 0;
714 return false;
717 void ScDocument::GetTiledRenderingArea(SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow) const
719 bool bHasPrintArea = GetCellArea(nTab, rEndCol, rEndRow);
721 // we need some reasonable minimal document size
722 ScViewData* pViewData = ScDocShell::GetViewData();
723 if (!pViewData)
725 if (!bHasPrintArea)
727 rEndCol = 20;
728 rEndRow = 50;
730 else
732 rEndCol += 20;
733 rEndRow += 50;
736 else if (!bHasPrintArea)
738 rEndCol = pViewData->GetMaxTiledCol();
739 rEndRow = pViewData->GetMaxTiledRow();
741 else
743 rEndCol = std::max(rEndCol, pViewData->GetMaxTiledCol());
744 rEndRow = std::max(rEndRow, pViewData->GetMaxTiledRow());
748 bool ScDocument::MoveTab( SCTAB nOldPos, SCTAB nNewPos, ScProgress* pProgress )
750 if (nOldPos == nNewPos)
751 return false;
753 SCTAB nTabCount = GetTableCount();
754 if(nTabCount < 2)
755 return false;
757 bool bValid = false;
758 if (ValidTab(nOldPos) && nOldPos < nTabCount )
760 if (maTabs[nOldPos])
762 sc::AutoCalcSwitch aACSwitch(*this, false);
763 sc::DelayDeletingBroadcasters delayDeletingBroadcasters(*this);
765 SetNoListening( true );
766 if (nNewPos == SC_TAB_APPEND || nNewPos >= nTabCount)
767 nNewPos = nTabCount-1;
769 // Update Reference
770 // TODO: combine with UpdateReference!
772 sc::RefUpdateMoveTabContext aCxt( *this, nOldPos, nNewPos);
774 SCTAB nDz = nNewPos - nOldPos;
775 ScRange aSourceRange( 0,0,nOldPos, MaxCol(),MaxRow(),nOldPos );
776 if (pRangeName)
777 pRangeName->UpdateMoveTab(aCxt);
779 pDBCollection->UpdateMoveTab( nOldPos, nNewPos );
780 xColNameRanges->UpdateReference( URM_REORDER, this, aSourceRange, 0,0,nDz );
781 xRowNameRanges->UpdateReference( URM_REORDER, this, aSourceRange, 0,0,nDz );
782 if (pDPCollection)
783 pDPCollection->UpdateReference( URM_REORDER, aSourceRange, 0,0,nDz );
784 if (pDetOpList)
785 pDetOpList->UpdateReference( this, URM_REORDER, aSourceRange, 0,0,nDz );
786 UpdateChartRef( URM_REORDER,
787 0,0,nOldPos, MaxCol(),MaxRow(),nOldPos, 0,0,nDz );
788 UpdateRefAreaLinks( URM_REORDER, aSourceRange, 0,0,nDz );
789 if ( pValidationList )
790 pValidationList->UpdateMoveTab(aCxt);
791 if ( pUnoBroadcaster )
792 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_REORDER,
793 aSourceRange, 0,0,nDz ) );
795 ScTableUniquePtr pSaveTab = std::move(maTabs[nOldPos]);
796 maTabs.erase(maTabs.begin()+nOldPos);
797 maTabs.insert(maTabs.begin()+nNewPos, std::move(pSaveTab));
798 for (SCTAB i = 0; i < nTabCount; i++)
799 if (maTabs[i])
800 maTabs[i]->UpdateMoveTab(aCxt, i, pProgress);
801 for (auto& rxTab : maTabs)
802 if (rxTab)
803 rxTab->UpdateCompile();
804 SetNoListening( false );
805 StartAllListeners();
807 sc::SetFormulaDirtyContext aFormulaDirtyCxt;
808 SetAllFormulasDirty(aFormulaDirtyCxt);
810 if (mpDrawLayer)
811 mpDrawLayer->ScMovePage( static_cast<sal_uInt16>(nOldPos), static_cast<sal_uInt16>(nNewPos) );
813 bValid = true;
816 return bValid;
819 bool ScDocument::CopyTab( SCTAB nOldPos, SCTAB nNewPos, const ScMarkData* pOnlyMarked )
821 if (SC_TAB_APPEND == nNewPos || nNewPos >= GetTableCount())
822 nNewPos = GetTableCount();
823 OUString aName;
824 GetName(nOldPos, aName);
826 // check first if Prefix is valid; if not, then only avoid duplicates
827 bool bPrefix = ValidTabName( aName );
828 OSL_ENSURE(bPrefix, "invalid table name");
829 SCTAB nDummy;
831 CreateValidTabName(aName);
833 bool bValid;
834 if (bPrefix)
835 bValid = ValidNewTabName(aName);
836 else
837 bValid = !GetTable( aName, nDummy );
839 sc::AutoCalcSwitch aACSwitch(*this, false);
840 sc::RefUpdateInsertTabContext aCxt( *this, nNewPos, 1);
842 if (bValid)
844 if (nNewPos >= GetTableCount())
846 nNewPos = GetTableCount();
847 maTabs.emplace_back(new ScTable(*this, nNewPos, aName));
849 else
851 if (ValidTab(nNewPos) && nNewPos < GetTableCount())
853 SetNoListening( true );
855 ScRange aRange( 0,0,nNewPos, MaxCol(),MaxRow(),MAXTAB );
856 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
857 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
858 if (pRangeName)
859 pRangeName->UpdateInsertTab(aCxt);
861 pDBCollection->UpdateReference(
862 URM_INSDEL, 0,0,nNewPos, MaxCol(),MaxRow(),MAXTAB, 0,0,1 );
863 if (pDPCollection)
864 pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
865 if (pDetOpList)
866 pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,1 );
867 UpdateChartRef( URM_INSDEL, 0,0,nNewPos, MaxCol(),MaxRow(),MAXTAB, 0,0,1 );
868 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,1 );
869 if ( pUnoBroadcaster )
870 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,1 ) );
872 for (TableContainer::iterator it = maTabs.begin(); it != maTabs.end(); ++it)
873 if (*it && it != (maTabs.begin() + nOldPos))
874 (*it)->UpdateInsertTab(aCxt);
875 if (nNewPos <= nOldPos)
876 nOldPos++;
877 maTabs.emplace(maTabs.begin() + nNewPos, new ScTable(*this, nNewPos, aName));
878 bValid = true;
879 for (TableContainer::iterator it = maTabs.begin(); it != maTabs.end(); ++it)
880 if (*it && it != maTabs.begin()+nOldPos && it != maTabs.begin() + nNewPos)
881 (*it)->UpdateCompile();
882 SetNoListening( false );
883 sc::StartListeningContext aSLCxt(*this);
884 for (TableContainer::iterator it = maTabs.begin(); it != maTabs.end(); ++it)
885 if (*it && it != maTabs.begin()+nOldPos && it != maTabs.begin()+nNewPos)
886 (*it)->StartListeners(aSLCxt, true);
888 if (pValidationList)
889 pValidationList->UpdateInsertTab(aCxt);
891 else
892 bValid = false;
896 if (bValid)
898 SetNoListening( true ); // not yet at CopyToTable/Insert
900 const bool bGlobalNamesToLocal = true;
901 const SCTAB nRealOldPos = (nNewPos < nOldPos) ? nOldPos - 1 : nOldPos;
902 const ScRangeName* pNames = GetRangeName( nOldPos);
903 if (pNames)
904 pNames->CopyUsedNames( nOldPos, nRealOldPos, nNewPos, *this, *this, bGlobalNamesToLocal);
905 GetRangeName()->CopyUsedNames( -1, nRealOldPos, nNewPos, *this, *this, bGlobalNamesToLocal);
907 sc::CopyToDocContext aCopyDocCxt(*this);
908 pDBCollection->CopyToTable(nOldPos, nNewPos);
909 maTabs[nOldPos]->CopyToTable(aCopyDocCxt, 0, 0, MaxCol(), MaxRow(), InsertDeleteFlags::ALL,
910 (pOnlyMarked != nullptr), maTabs[nNewPos].get(), pOnlyMarked,
911 false /*bAsLink*/, true /*bColRowFlags*/, bGlobalNamesToLocal, false /*bCopyCaptions*/ );
912 maTabs[nNewPos]->SetTabBgColor(maTabs[nOldPos]->GetTabBgColor());
914 SCTAB nDz = nNewPos - nOldPos;
915 sc::RefUpdateContext aRefCxt(*this);
916 aRefCxt.meMode = URM_COPY;
917 aRefCxt.maRange = ScRange(0, 0, nNewPos, MaxCol(), MaxRow(), nNewPos);
918 aRefCxt.mnTabDelta = nDz;
919 maTabs[nNewPos]->UpdateReference(aRefCxt);
921 maTabs[nNewPos]->UpdateInsertTabAbs(nNewPos); // move all paragraphs up by one!!
922 maTabs[nOldPos]->UpdateInsertTab(aCxt);
924 maTabs[nOldPos]->UpdateCompile();
925 maTabs[nNewPos]->UpdateCompile( true ); // maybe already compiled in Clone, but used names need recompilation
926 SetNoListening( false );
927 sc::StartListeningContext aSLCxt(*this);
928 maTabs[nOldPos]->StartListeners(aSLCxt, true);
929 maTabs[nNewPos]->StartListeners(aSLCxt, true);
931 sc::SetFormulaDirtyContext aFormulaDirtyCxt;
932 SetAllFormulasDirty(aFormulaDirtyCxt);
934 if (mpDrawLayer) // Skip cloning Note caption object
935 // page is already created in ScTable ctor
936 mpDrawLayer->ScCopyPage( static_cast<sal_uInt16>(nOldPos), static_cast<sal_uInt16>(nNewPos) );
938 if (pDPCollection)
939 pDPCollection->CopyToTab(nOldPos, nNewPos);
941 maTabs[nNewPos]->SetPageStyle( maTabs[nOldPos]->GetPageStyle() );
942 maTabs[nNewPos]->SetPendingRowHeights( maTabs[nOldPos]->IsPendingRowHeights() );
944 // Copy the custom print range if exists.
945 maTabs[nNewPos]->CopyPrintRange(*maTabs[nOldPos]);
947 // Copy the RTL settings
948 maTabs[nNewPos]->SetLayoutRTL(maTabs[nOldPos]->IsLayoutRTL());
949 maTabs[nNewPos]->SetLoadingRTL(maTabs[nOldPos]->IsLoadingRTL());
951 // Finally copy the note captions, which need
952 // 1. the updated source ScColumn::nTab members if nNewPos <= nOldPos
953 // 2. row heights and column widths of the destination
954 // 3. RTL settings of the destination
955 maTabs[nOldPos]->CopyCaptionsToTable( 0, 0, MaxCol(), MaxRow(), maTabs[nNewPos].get(), true /*bCloneCaption*/);
958 return bValid;
961 bool ScDocument::TransferTab( ScDocument& rSrcDoc, SCTAB nSrcPos,
962 SCTAB nDestPos, bool bInsertNew,
963 bool bResultsOnly )
965 bool bRetVal = true;
967 if (rSrcDoc.mpShell->GetMedium())
969 rSrcDoc.maFileURL = rSrcDoc.mpShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
970 // for unsaved files use the title name and adjust during save of file
971 if (rSrcDoc.maFileURL.isEmpty())
972 rSrcDoc.maFileURL = rSrcDoc.mpShell->GetName();
974 else
976 rSrcDoc.maFileURL = rSrcDoc.mpShell->GetName();
979 bool bValid = true;
980 if (bInsertNew) // re-insert
982 OUString aName;
983 rSrcDoc.GetName(nSrcPos, aName);
984 CreateValidTabName(aName);
985 bValid = InsertTab(nDestPos, aName);
987 // Copy the RTL settings
988 maTabs[nDestPos]->SetLayoutRTL(rSrcDoc.maTabs[nSrcPos]->IsLayoutRTL());
989 maTabs[nDestPos]->SetLoadingRTL(rSrcDoc.maTabs[nSrcPos]->IsLoadingRTL());
991 else // replace existing tables
993 if (ScTable* pTable = FetchTable(nDestPos))
995 pTable->DeleteArea(0, 0, MaxCol(), MaxRow(), InsertDeleteFlags::ALL);
997 else
998 bValid = false;
1001 if (bValid)
1003 bool bOldAutoCalcSrc = false;
1004 bool bOldAutoCalc = GetAutoCalc();
1005 SetAutoCalc( false ); // avoid repeated calculations
1006 SetNoListening( true );
1007 if ( bResultsOnly )
1009 bOldAutoCalcSrc = rSrcDoc.GetAutoCalc();
1010 rSrcDoc.SetAutoCalc( true ); // in case something needs calculation
1014 NumFmtMergeHandler aNumFmtMergeHdl(*this, rSrcDoc);
1016 sc::CopyToDocContext aCxt(*this);
1017 nDestPos = std::min(nDestPos, static_cast<SCTAB>(GetTableCount() - 1));
1018 { // scope for bulk broadcast
1019 ScBulkBroadcast aBulkBroadcast( pBASM.get(), SfxHintId::ScDataChanged);
1020 if (!bResultsOnly)
1022 const bool bGlobalNamesToLocal = false;
1023 const ScRangeName* pNames = rSrcDoc.GetRangeName( nSrcPos);
1024 if (pNames)
1025 pNames->CopyUsedNames( nSrcPos, nSrcPos, nDestPos, rSrcDoc, *this, bGlobalNamesToLocal);
1026 rSrcDoc.GetRangeName()->CopyUsedNames( -1, nSrcPos, nDestPos, rSrcDoc, *this, bGlobalNamesToLocal);
1028 rSrcDoc.maTabs[nSrcPos]->CopyToTable(aCxt, 0, 0, MaxCol(), MaxRow(),
1029 ( bResultsOnly ? InsertDeleteFlags::ALL & ~InsertDeleteFlags::FORMULA : InsertDeleteFlags::ALL),
1030 false, maTabs[nDestPos].get(), /*pMarkData*/nullptr, /*bAsLink*/false, /*bColRowFlags*/true,
1031 /*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true );
1034 maTabs[nDestPos]->SetTabNo(nDestPos);
1035 maTabs[nDestPos]->SetTabBgColor(rSrcDoc.maTabs[nSrcPos]->GetTabBgColor());
1037 // tdf#66613 - copy existing print ranges and col/row repetitions
1038 if (auto aRepeatColRange = rSrcDoc.maTabs[nSrcPos]->GetRepeatColRange())
1040 aRepeatColRange->aStart.SetTab(nDestPos);
1041 aRepeatColRange->aEnd.SetTab(nDestPos);
1042 maTabs[nDestPos]->SetRepeatColRange(std::move(aRepeatColRange));
1045 if (auto aRepeatRowRange = rSrcDoc.maTabs[nSrcPos]->GetRepeatRowRange())
1047 aRepeatRowRange->aStart.SetTab(nDestPos);
1048 aRepeatRowRange->aEnd.SetTab(nDestPos);
1049 maTabs[nDestPos]->SetRepeatRowRange(std::move(aRepeatRowRange));
1052 if (rSrcDoc.IsPrintEntireSheet(nSrcPos))
1053 maTabs[nDestPos]->SetPrintEntireSheet();
1054 else
1056 // tdf#157897 - clear print ranges before adding additional ones
1057 maTabs[nDestPos]->ClearPrintRanges();
1058 const auto nPrintRangeCount = rSrcDoc.maTabs[nSrcPos]->GetPrintRangeCount();
1059 for (auto nPos = 0; nPos < nPrintRangeCount; nPos++)
1061 // Adjust the tab for the print range at the new position
1062 ScRange aSrcPrintRange(*rSrcDoc.maTabs[nSrcPos]->GetPrintRange(nPos));
1063 aSrcPrintRange.aStart.SetTab(nDestPos);
1064 aSrcPrintRange.aEnd.SetTab(nDestPos);
1065 maTabs[nDestPos]->AddPrintRange(aSrcPrintRange);
1069 if ( !bResultsOnly )
1071 sc::RefUpdateContext aRefCxt(*this);
1072 aRefCxt.meMode = URM_COPY;
1073 aRefCxt.maRange = ScRange(0, 0, nDestPos, MaxCol(), MaxRow(), nDestPos);
1074 aRefCxt.mnTabDelta = nDestPos - nSrcPos;
1075 maTabs[nDestPos]->UpdateReference(aRefCxt);
1077 // Readjust self-contained absolute references to this sheet
1078 maTabs[nDestPos]->TestTabRefAbs(nSrcPos);
1079 sc::CompileFormulaContext aFormulaCxt(*this);
1080 maTabs[nDestPos]->CompileAll(aFormulaCxt);
1083 SetNoListening( false );
1084 if ( !bResultsOnly )
1086 sc::StartListeningContext aSLCxt(*this);
1087 maTabs[nDestPos]->StartListeners(aSLCxt, true);
1089 SetDirty( ScRange( 0, 0, nDestPos, MaxCol(), MaxRow(), nDestPos), false);
1091 if ( bResultsOnly )
1092 rSrcDoc.SetAutoCalc( bOldAutoCalcSrc );
1093 SetAutoCalc( bOldAutoCalc );
1095 // copy Drawing
1097 if (bInsertNew)
1098 TransferDrawPage( rSrcDoc, nSrcPos, nDestPos );
1100 maTabs[nDestPos]->SetPendingRowHeights( rSrcDoc.maTabs[nSrcPos]->IsPendingRowHeights() );
1102 if (!bValid)
1103 bRetVal = false;
1104 bool bVbaEnabled = IsInVBAMode();
1106 if ( bVbaEnabled )
1108 ScDocShell* pSrcShell = rSrcDoc.GetDocumentShell();
1109 if ( pSrcShell )
1111 OUString aLibName(u"Standard"_ustr);
1112 #if HAVE_FEATURE_SCRIPTING
1113 const BasicManager *pBasicManager = pSrcShell->GetBasicManager();
1114 if (pBasicManager && !pBasicManager->GetName().isEmpty())
1116 aLibName = pSrcShell->GetBasicManager()->GetName();
1118 #endif
1119 OUString sSource;
1120 uno::Reference< script::XLibraryContainer > xLibContainer = pSrcShell->GetBasicContainer();
1121 uno::Reference< container::XNameContainer > xLib;
1122 if( xLibContainer.is() )
1124 uno::Any aLibAny = xLibContainer->getByName(aLibName);
1125 aLibAny >>= xLib;
1128 if( xLib.is() )
1130 OUString sSrcCodeName;
1131 rSrcDoc.GetCodeName( nSrcPos, sSrcCodeName );
1132 OUString sRTLSource;
1133 if (xLib->hasByName( sSrcCodeName ))
1134 xLib->getByName( sSrcCodeName ) >>= sRTLSource;
1135 sSource = sRTLSource;
1137 VBA_InsertModule( *this, nDestPos, sSource );
1141 return bRetVal;
1144 void ScDocument::SetError( SCCOL nCol, SCROW nRow, SCTAB nTab, const FormulaError nError)
1146 if (ScTable* pTable = FetchTable(nTab))
1147 pTable->SetError(nCol, nRow, nError);
1150 void ScDocument::SetFormula(
1151 const ScAddress& rPos, const ScTokenArray& rArray )
1153 if (ScTable* pTable = FetchTable(rPos.Tab()))
1154 pTable->SetFormula(rPos.Col(), rPos.Row(), rArray, formula::FormulaGrammar::GRAM_DEFAULT);
1157 void ScDocument::SetFormula(
1158 const ScAddress& rPos, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram )
1160 if (ScTable* pTable = FetchTable(rPos.Tab()))
1161 pTable->SetFormula(rPos.Col(), rPos.Row(), rFormula, eGram);
1164 ScFormulaCell* ScDocument::SetFormulaCell( const ScAddress& rPos, ScFormulaCell* pCell )
1166 if (ScTable* pTable = FetchTable(rPos.Tab()))
1167 return pTable->SetFormulaCell(rPos.Col(), rPos.Row(), pCell);
1169 delete pCell;
1170 return nullptr;
1173 bool ScDocument::SetFormulaCells( const ScAddress& rPos, std::vector<ScFormulaCell*>& rCells )
1175 if (rCells.empty())
1176 return false;
1178 if (ScTable* pTable = FetchTable(rPos.Tab()))
1179 return pTable->SetFormulaCells(rPos.Col(), rPos.Row(), rCells);
1180 return false;
1183 void ScDocument::SetConsolidateDlgData( std::unique_ptr<ScConsolidateParam> pData )
1185 pConsolidateDlgData = std::move(pData);
1188 void ScDocument::SetEasyConditionalFormatDialogData(std::unique_ptr<ScConditionMode> pMode)
1190 pConditionalFormatDialogMode = std::move(pMode);
1193 void ScDocument::SetChangeViewSettings(const ScChangeViewSettings& rNew)
1195 if (pChangeViewSettings==nullptr)
1196 pChangeViewSettings.reset( new ScChangeViewSettings );
1198 *pChangeViewSettings=rNew;
1201 std::unique_ptr<ScFieldEditEngine> ScDocument::CreateFieldEditEngine()
1203 std::unique_ptr<ScFieldEditEngine> pNewEditEngine;
1204 if (!pCacheFieldEditEngine)
1206 pNewEditEngine.reset( new ScFieldEditEngine(
1207 this, GetEnginePool(), GetEditPool(), false) );
1209 else
1211 if ( !bImportingXML )
1213 // #i66209# previous use might not have restored update mode,
1214 // ensure same state as for a new EditEngine (UpdateMode = true)
1215 pCacheFieldEditEngine->SetUpdateLayout(true);
1218 pNewEditEngine = std::move(pCacheFieldEditEngine);
1220 return pNewEditEngine;
1223 void ScDocument::DisposeFieldEditEngine(std::unique_ptr<ScFieldEditEngine>& rpEditEngine)
1225 if (!pCacheFieldEditEngine && rpEditEngine)
1227 pCacheFieldEditEngine = std::move( rpEditEngine );
1228 pCacheFieldEditEngine->Clear();
1230 else
1231 rpEditEngine.reset();
1234 ScLookupCache & ScDocument::GetLookupCache( const ScRange & rRange, ScInterpreterContext* pContext )
1236 ScLookupCache* pCache = nullptr;
1237 if (!pContext->mxScLookupCache)
1238 pContext->mxScLookupCache.reset(new ScLookupCacheMap);
1239 ScLookupCacheMap* pCacheMap = pContext->mxScLookupCache.get();
1240 // insert with temporary value to avoid doing two lookups
1241 auto [findIt, bInserted] = pCacheMap->aCacheMap.emplace(rRange, nullptr);
1242 if (bInserted)
1244 findIt->second = std::make_unique<ScLookupCache>(this, rRange, *pCacheMap);
1245 pCache = findIt->second.get();
1246 // The StartListeningArea() call is not thread-safe, as all threads
1247 // would access the same SvtBroadcaster.
1248 std::unique_lock guard( mScLookupMutex );
1249 StartListeningArea(rRange, false, pCache);
1251 else
1252 pCache = (*findIt).second.get();
1254 return *pCache;
1257 ScSortedRangeCache& ScDocument::GetSortedRangeCache( const ScRange & rRange, const ScQueryParam& param,
1258 ScInterpreterContext* pContext, bool bNewSearchFunction,
1259 sal_uInt8 nSortedBinarySearch )
1261 assert(mxScSortedRangeCache);
1262 ScSortedRangeCache::HashKey key = ScSortedRangeCache::makeHashKey(rRange, param);
1263 // This should be created just once for one range, and repeated calls should reuse it, even
1264 // between threads (it doesn't make sense to use ScInterpreterContext and have all threads
1265 // build their own copy of the same data). So first try read-only access, which should
1266 // in most cases be enough.
1268 std::shared_lock guard(mScLookupMutex);
1269 auto findIt = mxScSortedRangeCache->aCacheMap.find(key);
1270 if( findIt != mxScSortedRangeCache->aCacheMap.end())
1271 return *findIt->second;
1273 // Avoid recursive calls because of some cells in the range being dirty and triggering
1274 // interpreting, which may call into this again. Threaded calculation makes sure
1275 // no cells are dirty. If some cells in the range cannot be interpreted and remain
1276 // dirty e.g. because of circular dependencies, create only an invalid empty cache to prevent
1277 // a possible recursive deadlock.
1278 bool invalid = false;
1279 if(!IsThreadedGroupCalcInProgress())
1280 if(!InterpretCellsIfNeeded(rRange))
1281 invalid = true;
1282 std::unique_lock guard(mScLookupMutex);
1283 auto [findIt, bInserted] = mxScSortedRangeCache->aCacheMap.emplace(key, nullptr);
1284 if (bInserted)
1286 findIt->second = std::make_unique<ScSortedRangeCache>(this, rRange, param, pContext, invalid, bNewSearchFunction, nSortedBinarySearch);
1287 StartListeningArea(rRange, false, findIt->second.get());
1289 return *findIt->second;
1292 void ScDocument::RemoveLookupCache( ScLookupCache & rCache )
1294 // Data changes leading to this should never happen during calculation (they are either
1295 // a result of user input or recalc). If it turns out this can be the case, locking is needed
1296 // here and also in ScLookupCache::Notify().
1297 assert(!IsThreadedGroupCalcInProgress());
1298 auto & cacheMap = rCache.getCacheMap();
1299 auto it(cacheMap.aCacheMap.find(rCache.getRange()));
1300 if (it != cacheMap.aCacheMap.end())
1302 std::unique_ptr<ScLookupCache> xCache = std::move(it->second);
1303 cacheMap.aCacheMap.erase(it);
1304 assert(!IsThreadedGroupCalcInProgress()); // EndListeningArea() is not thread-safe
1305 EndListeningArea(xCache->getRange(), false, &rCache);
1306 return;
1308 OSL_FAIL( "ScDocument::RemoveLookupCache: range not found in hash map");
1311 void ScDocument::RemoveSortedRangeCache( ScSortedRangeCache & rCache )
1313 // Data changes leading to this should never happen during calculation (they are either
1314 // a result of user input or recalc). If it turns out this can be the case, locking is needed
1315 // here and also in ScSortedRangeCache::Notify().
1316 assert(!IsThreadedGroupCalcInProgress());
1317 auto it(mxScSortedRangeCache->aCacheMap.find(rCache.getHashKey()));
1318 if (it != mxScSortedRangeCache->aCacheMap.end())
1320 std::unique_ptr<ScSortedRangeCache> xCache = std::move(it->second);
1321 mxScSortedRangeCache->aCacheMap.erase(it);
1322 assert(!IsThreadedGroupCalcInProgress()); // EndListeningArea() is not thread-safe
1323 EndListeningArea(xCache->getRange(), false, &rCache);
1324 return;
1326 OSL_FAIL( "ScDocument::RemoveSortedRangeCache: range not found in hash map");
1329 void ScDocument::ClearLookupCaches()
1331 assert(!IsThreadedGroupCalcInProgress());
1332 GetNonThreadedContext().mxScLookupCache.reset();
1333 mxScSortedRangeCache->aCacheMap.clear();
1334 // Clear lookup cache in all interpreter-contexts in the (threaded/non-threaded) pools.
1335 ScInterpreterContextPool::ClearLookupCaches(this);
1338 bool ScDocument::IsCellInChangeTrack(const ScAddress &cell,Color *pColCellBorder)
1340 ScChangeTrack* pTrack = GetChangeTrack();
1341 ScChangeViewSettings* pSettings = GetChangeViewSettings();
1342 if ( !pTrack || !pTrack->GetFirst() || !pSettings || !pSettings->ShowChanges() )
1343 return false; // missing or turned-off
1344 ScActionColorChanger aColorChanger(*pTrack);
1345 // Clipping happens from outside
1346 //! TODO: without Clipping; only paint affected cells ??!??!?
1347 const ScChangeAction* pAction = pTrack->GetFirst();
1348 while (pAction)
1350 if ( pAction->IsVisible() )
1352 ScChangeActionType eType = pAction->GetType();
1353 const ScBigRange& rBig = pAction->GetBigRange();
1354 if ( rBig.aStart.Tab() == cell.Tab())
1356 ScRange aRange = rBig.MakeRange( *this );
1357 if ( eType == SC_CAT_DELETE_ROWS )
1358 aRange.aEnd.SetRow( aRange.aStart.Row() );
1359 else if ( eType == SC_CAT_DELETE_COLS )
1360 aRange.aEnd.SetCol( aRange.aStart.Col() );
1361 if (ScViewUtil::IsActionShown( *pAction, *pSettings, *this ) )
1363 if (aRange.Contains(cell))
1365 if (pColCellBorder != nullptr)
1367 aColorChanger.Update( *pAction );
1368 Color aColor( aColorChanger.GetColor() );
1369 *pColCellBorder = aColor;
1371 return true;
1375 if ( eType == SC_CAT_MOVE &&
1376 static_cast<const ScChangeActionMove*>(pAction)->
1377 GetFromRange().aStart.Tab() == cell.Col() )
1379 ScRange aRange = static_cast<const ScChangeActionMove*>(pAction)->
1380 GetFromRange().MakeRange( *this );
1381 if (ScViewUtil::IsActionShown( *pAction, *pSettings, *this ) )
1383 if (aRange.Contains(cell))
1385 if (pColCellBorder != nullptr)
1387 aColorChanger.Update( *pAction );
1388 Color aColor( aColorChanger.GetColor() );
1389 *pColCellBorder = aColor;
1391 return true;
1396 pAction = pAction->GetNext();
1398 return false;
1401 void ScDocument::GetCellChangeTrackNote( const ScAddress &aCellPos, OUString &aTrackText,bool &bLeftEdge)
1403 aTrackText.clear();
1404 // Change-Tracking
1405 ScChangeTrack* pTrack = GetChangeTrack();
1406 ScChangeViewSettings* pSettings = GetChangeViewSettings();
1407 if ( !(pTrack && pTrack->GetFirst() && pSettings && pSettings->ShowChanges()))
1408 return;
1410 const ScChangeAction* pFound = nullptr;
1411 const ScChangeAction* pFoundContent = nullptr;
1412 const ScChangeAction* pFoundMove = nullptr;
1413 const ScChangeAction* pAction = pTrack->GetFirst();
1414 while (pAction)
1416 if ( pAction->IsVisible() &&
1417 ScViewUtil::IsActionShown( *pAction, *pSettings, *this ) )
1419 ScChangeActionType eType = pAction->GetType();
1420 const ScBigRange& rBig = pAction->GetBigRange();
1421 if ( rBig.aStart.Tab() == aCellPos.Tab())
1423 ScRange aRange = rBig.MakeRange( *this );
1424 if ( eType == SC_CAT_DELETE_ROWS )
1425 aRange.aEnd.SetRow( aRange.aStart.Row() );
1426 else if ( eType == SC_CAT_DELETE_COLS )
1427 aRange.aEnd.SetCol( aRange.aStart.Col() );
1428 if ( aRange.Contains( aCellPos ) )
1430 pFound = pAction; // the last wins
1431 switch ( eType )
1433 case SC_CAT_CONTENT :
1434 pFoundContent = pAction;
1435 break;
1436 case SC_CAT_MOVE :
1437 pFoundMove = pAction;
1438 break;
1439 default:
1440 break;
1444 if ( eType == SC_CAT_MOVE )
1446 ScRange aRange =
1447 static_cast<const ScChangeActionMove*>(pAction)->
1448 GetFromRange().MakeRange( *this );
1449 if ( aRange.Contains( aCellPos ) )
1451 pFound = pAction;
1455 pAction = pAction->GetNext();
1457 if ( !pFound )
1458 return;
1460 if ( pFoundContent && pFound->GetType() != SC_CAT_CONTENT )
1461 pFound = pFoundContent; // Content wins
1462 if ( pFoundMove && pFound->GetType() != SC_CAT_MOVE &&
1463 pFoundMove->GetActionNumber() >
1464 pFound->GetActionNumber() )
1465 pFound = pFoundMove; // Move wins
1466 // for deleted columns: arrow on left side of row
1467 if ( pFound->GetType() == SC_CAT_DELETE_COLS )
1468 bLeftEdge = true;
1469 DateTime aDT = pFound->GetDateTime();
1470 aTrackText = pFound->GetUser();
1471 aTrackText += ", ";
1472 aTrackText += ScGlobal::getLocaleData().getDate(aDT);
1473 aTrackText += " ";
1474 aTrackText += ScGlobal::getLocaleData().getTime(aDT);
1475 aTrackText += ":\n";
1476 OUString aComStr = pFound->GetComment();
1477 if(!aComStr.isEmpty())
1479 aTrackText += aComStr;
1480 aTrackText += "\n( ";
1482 aTrackText = pFound->GetDescription( *this );
1483 if (!aComStr.isEmpty())
1485 aTrackText += ")";
1489 void ScDocument::SetPreviewFont( std::unique_ptr<SfxItemSet> pFont )
1491 pPreviewFont = std::move(pFont);
1494 void ScDocument::SetPreviewSelection( const ScMarkData& rSel )
1496 maPreviewSelection = rSel;
1499 SfxItemSet* ScDocument::GetPreviewFont( SCCOL nCol, SCROW nRow, SCTAB nTab )
1501 SfxItemSet* pRet = nullptr;
1502 if ( pPreviewFont )
1504 ScMarkData aSel = GetPreviewSelection();
1505 if ( aSel.IsCellMarked( nCol, nRow ) && aSel.GetFirstSelected() == nTab )
1506 pRet = pPreviewFont.get();
1508 return pRet;
1511 ScStyleSheet* ScDocument::GetPreviewCellStyle( SCCOL nCol, SCROW nRow, SCTAB nTab )
1513 ScStyleSheet* pRet = nullptr;
1514 ScMarkData aSel = GetPreviewSelection();
1515 if ( pPreviewCellStyle && aSel.IsCellMarked( nCol, nRow ) && aSel.GetFirstSelected() == nTab )
1516 pRet = pPreviewCellStyle;
1517 return pRet;
1520 sc::IconSetBitmapMap& ScDocument::GetIconSetBitmapMap()
1522 if (!m_pIconSetBitmapMap)
1524 m_pIconSetBitmapMap.reset(new sc::IconSetBitmapMap);
1526 return *m_pIconSetBitmapMap;
1529 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */