xref: /core/sc/source/core/data/documen2.cxx (revision 4f8b32e92c0e85430c49e00ce0b32dff55a20efd)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <scextopt.hxx>
21 #include <autonamecache.hxx>
22 
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>
40 
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>
94 
95 using namespace com::sun::star;
96 
97 const sal_uInt16 ScDocument::nSrcVer = SC_CURRENT_VERSION;
98 
CreateDefault()99 ScSheetLimits ScSheetLimits::CreateDefault()
100 {
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);
112 }
113 
getCellAttributeHelper() const114 CellAttributeHelper& ScDocument::getCellAttributeHelper() const
115 {
116     if (!mpCellAttributeHelper)
117     {
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));
122     }
123 
124     return *mpCellAttributeHelper;
125 }
126 
ScDocument(ScDocumentMode eMode,ScDocShell * pDocShell)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         mbImportingXLSX( false ),
175         bCalcingAfterLoad( false ),
176         bNoListening( false ),
177         mbIdleEnabled(true),
178         bInLinkUpdate( false ),
179         bChartListenerCollectionNeedsUpdate( false ),
180         bHasForcedFormulas( false ),
181         bInDtorClear( false ),
182         bExpandRefs( false ),
183         bDetectiveDirty( false ),
184         bDelayedDeletingBroadcasters( false ),
185         bLinkFormulaNeedingCheck( false ),
186         nAsianCompression(CharCompressType::Invalid),
187         nAsianKerning(SC_ASIANKERNING_INVALID),
188         bPastingDrawFromOtherDoc( false ),
189         nInDdeLinkUpdate( 0 ),
190         bInUnoBroadcast( false ),
191         bInUnoListenerCall( false ),
192         nAdjustHeightLock(0),
193         eGrammar( formula::FormulaGrammar::GRAM_NATIVE ),
194         bStyleSheetUsageInvalid( true ),
195         mbUndoEnabled( true ),
196         mbExecuteLinkEnabled( true ),
197         mbChangeReadOnlyEnabled( false ),
198         mbStreamValidLocked( false ),
199         mbUserInteractionEnabled(true),
200         mnNamedRangesLockCount(0),
201         mbEmbedFonts(false),
202         mbEmbedUsedFontsOnly(false),
203         mbEmbedFontScriptLatin(true),
204         mbEmbedFontScriptAsian(true),
205         mbEmbedFontScriptComplex(true),
206         mnImagePreferredDPI(0),
207         mbTrackFormulasPending(false),
208         mbFinalTrackFormulas(false),
209         mbDocShellRecalc(false),
210         mbLayoutStrings(false),
211         mnMutationGuardFlags(0)
212 {
213     maPreviewSelection = { *mxSheetLimits };
214     aCurTextWidthCalcPos = { MaxCol(), 0, 0 };
215 
216     SetStorageGrammar( formula::FormulaGrammar::GRAM_STORAGE_DEFAULT);
217 
218     eSrcSet = osl_getThreadTextEncoding();
219 
220     /* TODO: for SCDOCMODE_FUNCTIONACCESS it might not even be necessary to
221      * have all of these available. */
222     if ( eMode == SCDOCMODE_DOCUMENT || eMode == SCDOCMODE_FUNCTIONACCESS )
223     {
224         mxPoolHelper = new ScPoolHelper( *this );
225         if (!comphelper::IsFuzzing()) //just too slow
226             pBASM.reset( new ScBroadcastAreaSlotMachine( *this ) );
227         pChartListenerCollection.reset( new ScChartListenerCollection( *this ) );
228         pRefreshTimerControl.reset( new ScRefreshTimerControl );
229     }
230     else
231     {
232         pChartListenerCollection = nullptr;
233     }
234 
235     pDBCollection.reset( new ScDBCollection(*this) );
236     pSelectionAttr = nullptr;
237     apTemporaryChartLock.reset( new ScTemporaryChartLock(this) );
238     xColNameRanges = new ScRangePairList;
239     xRowNameRanges = new ScRangePairList;
240     ImplCreateOptions();
241     // languages for a visible document are set by docshell later (from options)
242     SetLanguage( ScGlobal::eLnge, ScGlobal::eLnge, ScGlobal::eLnge );
243 
244     aTrackIdle.SetInvokeHandler( LINK( this, ScDocument, TrackTimeHdl ) );
245 }
246 
GetLinkManager()247 sfx2::LinkManager* ScDocument::GetLinkManager()
248 {
249     return GetDocLinkManager().getLinkManager();
250 }
251 
GetLinkManager() const252 const sfx2::LinkManager* ScDocument::GetLinkManager() const
253 {
254     return GetDocLinkManager().getExistingLinkManager();
255 }
256 
GetDocLinkManager()257 sc::DocumentLinkManager& ScDocument::GetDocLinkManager()
258 {
259     return *mpDocLinkMgr;
260 }
261 
GetDocLinkManager() const262 const sc::DocumentLinkManager& ScDocument::GetDocLinkManager() const
263 {
264     return const_cast<ScDocument*>(this)->GetDocLinkManager();
265 }
266 
SetStorageGrammar(formula::FormulaGrammar::Grammar eGram)267 void ScDocument::SetStorageGrammar( formula::FormulaGrammar::Grammar eGram )
268 {
269     OSL_PRECOND(
270         eGram == formula::FormulaGrammar::GRAM_ODFF ||
271             eGram == formula::FormulaGrammar::GRAM_PODF,
272             "ScDocument::SetStorageGrammar: wrong storage grammar");
273 
274     eStorageGrammar = eGram;
275 }
276 
SetDocVisible(bool bSet)277 void ScDocument::SetDocVisible( bool bSet )
278 {
279     //  called from view ctor - only for a visible document,
280     //  each new sheet's RTL flag is initialized from the locale
281     bIsVisible = bSet;
282 }
283 
GetDocumentID() const284 sal_uInt32 ScDocument::GetDocumentID() const
285 {
286     const ScDocument* pThis = this;
287     sal_uInt32 nCrc = rtl_crc32( 0, &pThis, sizeof(ScDocument*) );
288     // the this pointer only might not be sufficient
289     nCrc = rtl_crc32( nCrc, &mpShell, sizeof(SfxObjectShell*) );
290     return nCrc;
291 }
292 
StartChangeTracking()293 void ScDocument::StartChangeTracking()
294 {
295     if (!pChangeTrack)
296     {
297         pChangeTrack.reset( new ScChangeTrack( *this ) );
298         if (mpShell)
299             mpShell->SetModified();
300     }
301 }
302 
EndChangeTracking()303 void ScDocument::EndChangeTracking()
304 {
305     if (pChangeTrack && mpShell)
306         mpShell->SetModified();
307     pChangeTrack.reset();
308 }
309 
SetChangeTrack(std::unique_ptr<ScChangeTrack> pTrack)310 void ScDocument::SetChangeTrack( std::unique_ptr<ScChangeTrack> pTrack )
311 {
312     OSL_ENSURE( &pTrack->GetDocument() == this, "SetChangeTrack: different documents" );
313     if ( !pTrack || pTrack == pChangeTrack || &pTrack->GetDocument() != this )
314         return ;
315     EndChangeTracking();
316     pChangeTrack = std::move(pTrack);
317 }
318 
IMPL_LINK_NOARG(ScDocument,TrackTimeHdl,Timer *,void)319 IMPL_LINK_NOARG(ScDocument, TrackTimeHdl, Timer *, void)
320 {
321     if ( ScDdeLink::IsInUpdate() )      // do not nest
322     {
323         aTrackIdle.Start();            // try again later
324     }
325     else if (mpShell)                    // execute
326     {
327         TrackFormulas();
328         mpShell->Broadcast( SfxHint( SfxHintId::ScDataChanged ) );
329 
330         if (!mpShell->IsModified())
331         {
332             mpShell->SetModified();
333             SfxBindings* pBindings = GetViewBindings();
334             if (pBindings)
335             {
336                 pBindings->Invalidate( SID_SAVEDOC );
337                 pBindings->Invalidate( SID_DOC_MODIFIED );
338             }
339         }
340     }
341 }
342 
SetExpandRefs(bool bVal)343 void ScDocument::SetExpandRefs( bool bVal )
344 {
345     bExpandRefs = bVal;
346 }
347 
StartTrackTimer()348 void ScDocument::StartTrackTimer()
349 {
350     if (!aTrackIdle.IsActive())        // do not postpone for forever
351         aTrackIdle.Start();
352 }
353 
ClosingClipboardSource()354 void ScDocument::ClosingClipboardSource()
355 {
356     if (!bIsClip)
357         return;
358 
359     ForgetNoteCaptions( ScRangeList( ScRange( 0,0,0, MaxCol(), MaxRow(), GetTableCount()-1)), true);
360 }
361 
~ScDocument()362 ScDocument::~ScDocument()
363 {
364     OSL_PRECOND( !bInLinkUpdate, "bInLinkUpdate in dtor" );
365 
366     // Join any pending(recalc) threads in global threadpool
367     comphelper::ThreadPool::getSharedOptimalPool().joinThreadsIfIdle();
368 
369     bInDtorClear = true;
370 
371     // first of all disable all refresh timers by deleting the control
372     if ( pRefreshTimerControl )
373     {   // To be sure there isn't anything running do it with a protector,
374         // this ensures also that nothing needs the control anymore.
375         ScRefreshTimerProtector aProt( GetRefreshTimerControlAddress() );
376         pRefreshTimerControl.reset();
377     }
378 
379     mxFormulaParserPool.reset();
380     // Destroy the external ref mgr instance here because it has a timer
381     // which needs to be stopped before the app closes.
382     pExternalRefMgr.reset();
383 
384     ScAddInAsync::RemoveDocument( this );
385     ScAddInListener::RemoveDocument( this );
386     pChartListenerCollection.reset();   // before pBASM because of potential Listener!
387 
388     ClearLookupCaches(); // before pBASM because of listeners
389 
390     // destroy BroadcastAreas first to avoid un-needed Single-EndListenings of Formula-Cells
391     pBASM.reset();       // BroadcastAreaSlotMachine
392 
393     pUnoBroadcaster.reset();     // broadcasts SfxHintId::Dying again
394 
395     pUnoRefUndoList.reset();
396     pUnoListenerCalls.reset();
397 
398     Clear( true );              // true = from destructor (needed for SdrModel::ClearModel)
399 
400     pValidationList.reset();
401     pRangeName.reset();
402     pDBCollection.reset();
403     pSelectionAttr.reset();
404     apTemporaryChartLock.reset();
405     mpDrawLayer.reset();
406     mpPrinter.disposeAndClear();
407     ImplDeleteOptions();
408     pConsolidateDlgData.reset();
409     pClipData.reset();
410     pDetOpList.reset();                  // also deletes entries
411     pChangeTrack.reset();
412     mpEditEngine.reset();
413     mpNoteEngine.reset();
414     pChangeViewSettings.reset();         // and delete
415     mpVirtualDevice_100th_mm.disposeAndClear();
416 
417     pDPCollection.reset();
418     mpAnonymousDBData.reset();
419 
420     // delete the EditEngine before destroying the mxPoolHelper
421     pCacheFieldEditEngine.reset();
422 
423     if ( mxPoolHelper.is() && !bIsClip && !bIsUndo)
424         mxPoolHelper->SourceDocumentGone();
425     mxPoolHelper.clear();
426 
427     pScriptTypeData.reset();
428     maNonThreaded.xRecursionHelper.reset();
429     assert(!maThreadSpecific.xRecursionHelper);
430 
431     pPreviewFont.reset();
432     SAL_WARN_IF( pAutoNameCache, "sc.core", "AutoNameCache still set in dtor" );
433 
434     mpFormulaGroupCxt.reset();
435     // Purge unused items if the string pool will be still used (e.g. by undo history).
436     if(mpCellStringPool.use_count() > 1)
437     {
438         // Calling purge() may be somewhat expensive with large documents, so
439         // try to delay and compress it for temporary documents.
440         if(IsClipOrUndo())
441             ScGlobal::GetSharedStringPoolPurge().delayedPurge(mpCellStringPool);
442         else
443             mpCellStringPool->purge();
444     }
445     mpCellStringPool.reset();
446 
447     assert( pDelayedFormulaGrouping == nullptr );
448     assert( pDelayedStartListeningFormulaCells.empty());
449 }
450 
InitClipPtrs(ScDocument * pSourceDoc)451 void ScDocument::InitClipPtrs( ScDocument* pSourceDoc )
452 {
453     OSL_ENSURE(bIsClip, "InitClipPtrs and not bIsClip");
454 
455     ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
456 
457     pValidationList.reset();
458 
459     Clear();
460 
461     SharePooledResources(pSourceDoc);
462 
463     //  conditional Formats / validations
464     // TODO: Copy Templates?
465     const ScValidationDataList* pSourceValid = pSourceDoc->pValidationList.get();
466     if ( pSourceValid )
467         pValidationList.reset(new ScValidationDataList(*this, *pSourceValid));
468 
469     // store Links in Stream
470     pClipData.reset();
471     if (pSourceDoc->GetDocLinkManager().hasDdeLinks())
472     {
473         pClipData.reset( new SvMemoryStream );
474         pSourceDoc->SaveDdeLinks(*pClipData);
475     }
476 
477     // Options pointers exist (ImplCreateOptions) for any document.
478     // Must be copied for correct results in OLE objects (#i42666#).
479     SetDocOptions( pSourceDoc->GetDocOptions() );
480     SetViewOptions( pSourceDoc->GetViewOptions() );
481 }
482 
GetFormatTable() const483 SvNumberFormatter* ScDocument::GetFormatTable() const
484 {
485     assert(!IsThreadedGroupCalcInProgress());
486     return mxPoolHelper->GetFormTable();
487 }
488 
GetEditEnginePool() const489 SfxItemPool* ScDocument::GetEditEnginePool() const
490 {
491     return mxPoolHelper->GetEditEnginePool();
492 }
493 
GetEditEngine()494 ScFieldEditEngine& ScDocument::GetEditEngine()
495 {
496     if ( !mpEditEngine )
497     {
498         mpEditEngine.reset( new ScFieldEditEngine(this, GetEditEnginePool()) );
499         mpEditEngine->SetUpdateLayout( false );
500         mpEditEngine->EnableUndo( false );
501         mpEditEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM));
502         ApplyAsianEditSettings( *mpEditEngine );
503     }
504     return *mpEditEngine;
505 }
506 
GetNoteEngine()507 ScNoteEditEngine& ScDocument::GetNoteEngine()
508 {
509     if ( !mpNoteEngine )
510     {
511         ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
512         mpNoteEngine.reset( new ScNoteEditEngine( GetEditEnginePool() ) );
513         mpNoteEngine->SetUpdateLayout( false );
514         mpNoteEngine->EnableUndo( false );
515         mpNoteEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM));
516         ApplyAsianEditSettings( *mpNoteEngine );
517         const SfxItemSet& rItemSet(getCellAttributeHelper().getDefaultCellAttribute().GetItemSet());
518         SfxItemSet aEEItemSet(mpNoteEngine->GetEmptyItemSet());
519         ScPatternAttr::FillToEditItemSet(aEEItemSet, rItemSet);
520         mpNoteEngine->SetDefaults(std::move(aEEItemSet)); // edit engine takes ownership
521     }
522     return *mpNoteEngine;
523 }
524 
CreateSharedStringTextObject(const svl::SharedString & rSS)525 std::unique_ptr<EditTextObject> ScDocument::CreateSharedStringTextObject( const svl::SharedString& rSS )
526 {
527     /* TODO: Add shared string support to the edit engine to make this process
528      * simpler. */
529     ScFieldEditEngine& rEngine = GetEditEngine();
530     rEngine.SetTextCurrentDefaults( rSS.getString());
531     std::unique_ptr<EditTextObject> pObj( rEngine.CreateTextObject());
532     pObj->NormalizeString( GetSharedStringPool());
533     return pObj;
534 }
535 
ResetClip(ScDocument * pSourceDoc,const ScMarkData * pMarks)536 void ScDocument::ResetClip( ScDocument* pSourceDoc, const ScMarkData* pMarks )
537 {
538     if (bIsClip)
539     {
540         InitClipPtrs(pSourceDoc);
541 
542         for (SCTAB i = 0; i < pSourceDoc->GetTableCount(); i++)
543             if (pSourceDoc->maTabs[i])
544                 if (!pMarks || pMarks->GetTableSelect(i))
545                 {
546                     OUString aString = pSourceDoc->maTabs[i]->GetName();
547                     if (i < GetTableCount())
548                     {
549                         maTabs[i].reset( new ScTable(*this, i, aString) );
550 
551                     }
552                     else
553                     {
554                         if (i > GetTableCount())
555                         {
556                             maTabs.resize(i);
557                         }
558                         maTabs.emplace_back(new ScTable(*this, i, aString));
559                     }
560                     maTabs[i]->SetLayoutRTL( pSourceDoc->maTabs[i]->IsLayoutRTL() );
561                 }
562     }
563     else
564     {
565         OSL_FAIL("ResetClip");
566     }
567 }
568 
ResetClip(ScDocument * pSourceDoc,SCTAB nTab)569 void ScDocument::ResetClip( ScDocument* pSourceDoc, SCTAB nTab )
570 {
571     if (bIsClip)
572     {
573         InitClipPtrs(pSourceDoc);
574         if (nTab >= GetTableCount())
575         {
576             maTabs.resize(nTab+1);
577         }
578         maTabs[nTab].reset( new ScTable(*this, nTab, u"baeh"_ustr) );
579         if (nTab < pSourceDoc->GetTableCount() && pSourceDoc->maTabs[nTab])
580             maTabs[nTab]->SetLayoutRTL( pSourceDoc->maTabs[nTab]->IsLayoutRTL() );
581     }
582     else
583     {
584         OSL_FAIL("ResetClip");
585     }
586 }
587 
EnsureTable(SCTAB nTab)588 void ScDocument::EnsureTable( SCTAB nTab )
589 {
590     bool bExtras = !bIsUndo;        // Column-Widths, Row-Heights, Flags
591     if (nTab >= GetTableCount())
592         maTabs.resize(nTab+1);
593 
594     if (!maTabs[nTab])
595         maTabs[nTab].reset( new ScTable(*this, nTab, u"temp"_ustr, bExtras, bExtras) );
596 }
597 
GetRefCellValue(const ScAddress & rPos)598 ScRefCellValue ScDocument::GetRefCellValue( const ScAddress& rPos )
599 {
600     if (ScTable* pTable = FetchTable(rPos.Tab()))
601         return pTable->GetRefCellValue(rPos.Col(), rPos.Row());
602     return ScRefCellValue(); // empty
603 }
604 
GetRefCellValue(const ScAddress & rPos,sc::ColumnBlockPosition & rBlockPos)605 ScRefCellValue ScDocument::GetRefCellValue( const ScAddress& rPos, sc::ColumnBlockPosition& rBlockPos )
606 {
607     if (ScTable* pTable = FetchTable(rPos.Tab()))
608         return pTable->GetRefCellValue(rPos.Col(), rPos.Row(), rBlockPos);
609     return ScRefCellValue(); // empty
610 }
611 
GetSharedStringPool()612 svl::SharedStringPool& ScDocument::GetSharedStringPool()
613 {
614     return *mpCellStringPool;
615 }
616 
GetSharedStringPool() const617 const svl::SharedStringPool& ScDocument::GetSharedStringPool() const
618 {
619     return *mpCellStringPool;
620 }
621 
GetPrintArea(SCTAB nTab,SCCOL & rEndCol,SCROW & rEndRow,bool bNotes) const622 bool ScDocument::GetPrintArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow,
623                                 bool bNotes) const
624 {
625     if (const ScTable* pTable = FetchTable(nTab))
626     {
627         bool bAny = pTable->GetPrintArea( rEndCol, rEndRow, bNotes, /*bCalcHiddens*/false);
628         if (mpDrawLayer)
629         {
630             ScRange aDrawRange(0,0,nTab, MaxCol(),MaxRow(),nTab);
631             if (DrawGetPrintArea( aDrawRange, true, true ))
632             {
633                 if (aDrawRange.aEnd.Col()>rEndCol) rEndCol=aDrawRange.aEnd.Col();
634                 if (aDrawRange.aEnd.Row()>rEndRow) rEndRow=aDrawRange.aEnd.Row();
635                 bAny = true;
636             }
637         }
638         return bAny;
639     }
640 
641     rEndCol = 0;
642     rEndRow = 0;
643     return false;
644 }
645 
GetPrintAreaHor(SCTAB nTab,SCROW nStartRow,SCROW nEndRow,SCCOL & rEndCol) const646 bool ScDocument::GetPrintAreaHor( SCTAB nTab, SCROW nStartRow, SCROW nEndRow,
647                                         SCCOL& rEndCol ) const
648 {
649     if (const ScTable* pTable = FetchTable(nTab))
650     {
651         bool bAny = pTable->GetPrintAreaHor( nStartRow, nEndRow, rEndCol );
652         if (mpDrawLayer)
653         {
654             ScRange aDrawRange(0,nStartRow,nTab, MaxCol(),nEndRow,nTab);
655             if (DrawGetPrintArea( aDrawRange, true, false ))
656             {
657                 if (aDrawRange.aEnd.Col()>rEndCol) rEndCol=aDrawRange.aEnd.Col();
658                 bAny = true;
659             }
660         }
661         return bAny;
662     }
663 
664     rEndCol = 0;
665     return false;
666 }
667 
GetPrintAreaVer(SCTAB nTab,SCCOL nStartCol,SCCOL nEndCol,SCROW & rEndRow,bool bNotes) const668 bool ScDocument::GetPrintAreaVer( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol,
669                                         SCROW& rEndRow, bool bNotes ) const
670 {
671     if (const ScTable* pTable = FetchTable(nTab))
672     {
673         bool bAny = pTable->GetPrintAreaVer( nStartCol, nEndCol, rEndRow, bNotes );
674         if (mpDrawLayer)
675         {
676             ScRange aDrawRange(nStartCol,0,nTab, nEndCol,MaxRow(),nTab);
677             if (DrawGetPrintArea( aDrawRange, false, true ))
678             {
679                 if (aDrawRange.aEnd.Row()>rEndRow) rEndRow=aDrawRange.aEnd.Row();
680                 bAny = true;
681             }
682         }
683         return bAny;
684     }
685 
686     rEndRow = 0;
687     return false;
688 }
689 
GetDataStart(SCTAB nTab,SCCOL & rStartCol,SCROW & rStartRow) const690 bool ScDocument::GetDataStart( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow ) const
691 {
692     if (const ScTable* pTable = FetchTable(nTab))
693     {
694         bool bAny = pTable->GetDataStart( rStartCol, rStartRow );
695         if (mpDrawLayer)
696         {
697             ScRange aDrawRange(0,0,nTab, MaxCol(),MaxRow(),nTab);
698             if (DrawGetPrintArea( aDrawRange, true, true ))
699             {
700                 if (aDrawRange.aStart.Col()<rStartCol) rStartCol=aDrawRange.aStart.Col();
701                 if (aDrawRange.aStart.Row()<rStartRow) rStartRow=aDrawRange.aStart.Row();
702                 bAny = true;
703             }
704         }
705         return bAny;
706     }
707 
708     rStartCol = 0;
709     rStartRow = 0;
710     return false;
711 }
712 
GetTiledRenderingArea(SCTAB nTab,SCCOL & rEndCol,SCROW & rEndRow) const713 void ScDocument::GetTiledRenderingArea(SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow) const
714 {
715     bool bHasPrintArea = GetCellArea(nTab, rEndCol, rEndRow);
716 
717     // we need some reasonable minimal document size
718     ScViewData* pViewData = ScDocShell::GetViewData();
719     if (!pViewData)
720     {
721         if (!bHasPrintArea)
722         {
723             rEndCol = 20;
724             rEndRow = 50;
725         }
726         else
727         {
728             rEndCol += 20;
729             rEndRow += 50;
730         }
731     }
732     else if (!bHasPrintArea)
733     {
734         rEndCol = pViewData->GetMaxTiledCol();
735         rEndRow = pViewData->GetMaxTiledRow();
736     }
737     else
738     {
739         rEndCol = std::max(rEndCol, pViewData->GetMaxTiledCol());
740         rEndRow = std::max(rEndRow, pViewData->GetMaxTiledRow());
741     }
742 }
743 
MoveTab(SCTAB nOldPos,SCTAB nNewPos,ScProgress * pProgress)744 bool ScDocument::MoveTab( SCTAB nOldPos, SCTAB nNewPos, ScProgress* pProgress )
745 {
746     if (nOldPos == nNewPos)
747         return false;
748 
749     SCTAB nTabCount = GetTableCount();
750     if(nTabCount < 2)
751         return false;
752 
753     bool bValid = false;
754     if (ValidTab(nOldPos) && nOldPos < nTabCount )
755     {
756         if (maTabs[nOldPos])
757         {
758             sc::AutoCalcSwitch aACSwitch(*this, false);
759             sc::DelayDeletingBroadcasters delayDeletingBroadcasters(*this);
760 
761             SetNoListening( true );
762             if (nNewPos == SC_TAB_APPEND || nNewPos >= nTabCount)
763                 nNewPos = nTabCount-1;
764 
765             // Update Reference
766             // TODO: combine with UpdateReference!
767 
768             sc::RefUpdateMoveTabContext aCxt( *this, nOldPos, nNewPos);
769 
770             SCTAB nDz = nNewPos - nOldPos;
771             ScRange aSourceRange( 0,0,nOldPos, MaxCol(),MaxRow(),nOldPos );
772             if (pRangeName)
773                 pRangeName->UpdateMoveTab(aCxt);
774 
775             pDBCollection->UpdateMoveTab( nOldPos, nNewPos );
776             xColNameRanges->UpdateReference( URM_REORDER, *this, aSourceRange, 0,0,nDz );
777             xRowNameRanges->UpdateReference( URM_REORDER, *this, aSourceRange, 0,0,nDz );
778             if (pDPCollection)
779                 pDPCollection->UpdateReference( URM_REORDER, aSourceRange, 0,0,nDz );
780             if (pDetOpList)
781                 pDetOpList->UpdateReference( *this, URM_REORDER, aSourceRange, 0,0,nDz );
782             UpdateChartRef( URM_REORDER,
783                     0,0,nOldPos, MaxCol(),MaxRow(),nOldPos, 0,0,nDz );
784             UpdateRefAreaLinks( URM_REORDER, aSourceRange, 0,0,nDz );
785             if ( pValidationList )
786                 pValidationList->UpdateMoveTab(aCxt);
787             if ( pUnoBroadcaster )
788                 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_REORDER,
789                             aSourceRange, 0,0,nDz ) );
790 
791             ScTableUniquePtr pSaveTab = std::move(maTabs[nOldPos]);
792             maTabs.erase(maTabs.begin()+nOldPos);
793             maTabs.insert(maTabs.begin()+nNewPos, std::move(pSaveTab));
794             for (SCTAB i = 0; i < nTabCount; i++)
795                 if (maTabs[i])
796                     maTabs[i]->UpdateMoveTab(aCxt, i, pProgress);
797             for (auto& rxTab : maTabs)
798                 if (rxTab)
799                     rxTab->UpdateCompile();
800             SetNoListening( false );
801             StartAllListeners();
802 
803             sc::SetFormulaDirtyContext aFormulaDirtyCxt;
804             SetAllFormulasDirty(aFormulaDirtyCxt);
805 
806             if (mpDrawLayer)
807                 mpDrawLayer->ScMovePage( static_cast<sal_uInt16>(nOldPos), static_cast<sal_uInt16>(nNewPos) );
808 
809             bValid = true;
810         }
811     }
812     return bValid;
813 }
814 
CopyTab(SCTAB nOldPos,SCTAB nNewPos,const ScMarkData * pOnlyMarked)815 bool ScDocument::CopyTab( SCTAB nOldPos, SCTAB nNewPos, const ScMarkData* pOnlyMarked )
816 {
817     if (SC_TAB_APPEND == nNewPos  || nNewPos >= GetTableCount())
818         nNewPos = GetTableCount();
819     OUString aName;
820     GetName(nOldPos, aName);
821 
822     //  check first if Prefix is valid; if not, then only avoid duplicates
823     bool bPrefix = ValidTabName( aName );
824     OSL_ENSURE(bPrefix, "invalid table name");
825     SCTAB nDummy;
826 
827     CreateValidTabName(aName);
828 
829     bool bValid;
830     if (bPrefix)
831         bValid = ValidNewTabName(aName);
832     else
833         bValid = !GetTable( aName, nDummy );
834 
835     sc::AutoCalcSwitch aACSwitch(*this, false);
836     sc::RefUpdateInsertTabContext aCxt( *this, nNewPos, 1);
837 
838     if (bValid)
839     {
840         if (nNewPos >= GetTableCount())
841         {
842             nNewPos = GetTableCount();
843             maTabs.emplace_back(new ScTable(*this, nNewPos, aName));
844         }
845         else
846         {
847             if (ValidTab(nNewPos) && nNewPos < GetTableCount())
848             {
849                 SetNoListening( true );
850 
851                 ScRange aRange( 0,0,nNewPos, MaxCol(),MaxRow(),MAXTAB );
852                 xColNameRanges->UpdateReference( URM_INSDEL, *this, aRange, 0,0,1 );
853                 xRowNameRanges->UpdateReference( URM_INSDEL, *this, aRange, 0,0,1 );
854                 if (pRangeName)
855                     pRangeName->UpdateInsertTab(aCxt);
856 
857                 pDBCollection->UpdateReference(
858                                     URM_INSDEL, 0,0,nNewPos, MaxCol(),MaxRow(),MAXTAB, 0,0,1 );
859                 if (pDPCollection)
860                     pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
861                 if (pDetOpList)
862                     pDetOpList->UpdateReference( *this, URM_INSDEL, aRange, 0,0,1 );
863                 UpdateChartRef( URM_INSDEL, 0,0,nNewPos, MaxCol(),MaxRow(),MAXTAB, 0,0,1 );
864                 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,1 );
865                 if ( pUnoBroadcaster )
866                     pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,1 ) );
867 
868                 for (auto it = maTabs.begin(); it != maTabs.end(); ++it)
869                 {
870                     if (*it && it != (maTabs.begin() + nOldPos))
871                         (*it)->UpdateInsertTab(aCxt);
872                 }
873                 if (nNewPos <= nOldPos)
874                     nOldPos++;
875                 maTabs.emplace(maTabs.begin() + nNewPos, new ScTable(*this, nNewPos, aName));
876                 bValid = true;
877                 for (auto it = maTabs.begin(); it != maTabs.end(); ++it)
878                 {
879                     if (*it && it != maTabs.begin()+nOldPos && it != maTabs.begin() + nNewPos)
880                         (*it)->UpdateCompile();
881                 }
882                 SetNoListening( false );
883                 sc::StartListeningContext aSLCxt(*this);
884                 for (auto it = maTabs.begin(); it != maTabs.end(); ++it)
885                 {
886                     if (*it && it != maTabs.begin()+nOldPos && it != maTabs.begin()+nNewPos)
887                         (*it)->StartListeners(aSLCxt, true);
888                 }
889 
890                 if (pValidationList)
891                     pValidationList->UpdateInsertTab(aCxt);
892             }
893             else
894                 bValid = false;
895         }
896     }
897 
898     if (bValid)
899     {
900         SetNoListening( true );     // not yet at CopyToTable/Insert
901 
902         const bool bGlobalNamesToLocal = true;
903         const SCTAB nRealOldPos = (nNewPos < nOldPos) ? nOldPos - 1 : nOldPos;
904         const ScRangeName* pNames = GetRangeName( nOldPos);
905         if (pNames)
906             pNames->CopyUsedNames( nOldPos, nRealOldPos, nNewPos, *this, *this, bGlobalNamesToLocal);
907         GetRangeName()->CopyUsedNames( -1, nRealOldPos, nNewPos, *this, *this, bGlobalNamesToLocal);
908 
909         sc::CopyToDocContext aCopyDocCxt(*this);
910         pDBCollection->CopyToTable(nOldPos, nNewPos);
911         maTabs[nOldPos]->CopyToTable(aCopyDocCxt, 0, 0, MaxCol(), MaxRow(), InsertDeleteFlags::ALL,
912                 (pOnlyMarked != nullptr), maTabs[nNewPos].get(), pOnlyMarked,
913                 false /*bAsLink*/, true /*bColRowFlags*/, bGlobalNamesToLocal, false /*bCopyCaptions*/ );
914         maTabs[nNewPos]->SetTabBgColor(maTabs[nOldPos]->GetTabBgColor());
915 
916         SCTAB nDz = nNewPos - nOldPos;
917         sc::RefUpdateContext aRefCxt(*this);
918         aRefCxt.meMode = URM_COPY;
919         aRefCxt.maRange = ScRange(0, 0, nNewPos, MaxCol(), MaxRow(), nNewPos);
920         aRefCxt.mnTabDelta = nDz;
921         maTabs[nNewPos]->UpdateReference(aRefCxt);
922 
923         maTabs[nNewPos]->UpdateInsertTabAbs(nNewPos); // move all paragraphs up by one!!
924         maTabs[nOldPos]->UpdateInsertTab(aCxt);
925 
926         maTabs[nOldPos]->UpdateCompile();
927         maTabs[nNewPos]->UpdateCompile( true ); //  maybe already compiled in Clone, but used names need recompilation
928         SetNoListening( false );
929         sc::StartListeningContext aSLCxt(*this);
930         maTabs[nOldPos]->StartListeners(aSLCxt, true);
931         maTabs[nNewPos]->StartListeners(aSLCxt, true);
932 
933         sc::SetFormulaDirtyContext aFormulaDirtyCxt;
934         SetAllFormulasDirty(aFormulaDirtyCxt);
935 
936         if (mpDrawLayer) //  Skip cloning Note caption object
937             // page is already created in ScTable ctor
938             mpDrawLayer->ScCopyPage( static_cast<sal_uInt16>(nOldPos), static_cast<sal_uInt16>(nNewPos) );
939 
940         if (pDPCollection)
941             pDPCollection->CopyToTab(nOldPos, nNewPos);
942 
943         maTabs[nNewPos]->SetPageStyle( maTabs[nOldPos]->GetPageStyle() );
944         maTabs[nNewPos]->SetPendingRowHeights( maTabs[nOldPos]->IsPendingRowHeights() );
945 
946         // Copy the custom print range if exists.
947         maTabs[nNewPos]->CopyPrintRange(*maTabs[nOldPos]);
948 
949         // Copy the RTL settings
950         maTabs[nNewPos]->SetLayoutRTL(maTabs[nOldPos]->IsLayoutRTL());
951         maTabs[nNewPos]->SetLoadingRTL(maTabs[nOldPos]->IsLoadingRTL());
952 
953         // Finally copy the note captions, which need
954         // 1. the updated source ScColumn::nTab members if nNewPos <= nOldPos
955         // 2. row heights and column widths of the destination
956         // 3. RTL settings of the destination
957         maTabs[nOldPos]->CopyCaptionsToTable( 0, 0, MaxCol(), MaxRow(), maTabs[nNewPos].get(), true /*bCloneCaption*/);
958     }
959 
960     return bValid;
961 }
962 
TransferTab(ScDocument & rSrcDoc,SCTAB nSrcPos,SCTAB nDestPos,bool bInsertNew,bool bResultsOnly)963 bool ScDocument::TransferTab( ScDocument& rSrcDoc, SCTAB nSrcPos,
964                                 SCTAB nDestPos, bool bInsertNew,
965                                 bool bResultsOnly )
966 {
967     bool bRetVal = true;
968 
969     if (rSrcDoc.mpShell->GetMedium())
970     {
971         rSrcDoc.maFileURL = rSrcDoc.mpShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
972         // for unsaved files use the title name and adjust during save of file
973         if (rSrcDoc.maFileURL.isEmpty())
974             rSrcDoc.maFileURL = rSrcDoc.mpShell->GetName();
975     }
976     else
977     {
978         rSrcDoc.maFileURL = rSrcDoc.mpShell->GetName();
979     }
980 
981     bool bValid = true;
982     if (bInsertNew)             // re-insert
983     {
984         OUString aName;
985         rSrcDoc.GetName(nSrcPos, aName);
986         CreateValidTabName(aName);
987         bValid = InsertTab(nDestPos, aName);
988 
989         // Copy the RTL settings
990         maTabs[nDestPos]->SetLayoutRTL(rSrcDoc.maTabs[nSrcPos]->IsLayoutRTL());
991         maTabs[nDestPos]->SetLoadingRTL(rSrcDoc.maTabs[nSrcPos]->IsLoadingRTL());
992     }
993     else                        // replace existing tables
994     {
995         if (ScTable* pTable = FetchTable(nDestPos))
996         {
997             pTable->DeleteArea(0, 0, MaxCol(), MaxRow(), InsertDeleteFlags::ALL);
998         }
999         else
1000             bValid = false;
1001     }
1002 
1003     if (bValid)
1004     {
1005         bool bOldAutoCalcSrc = false;
1006         bool bOldAutoCalc = GetAutoCalc();
1007         SetAutoCalc( false );   // avoid repeated calculations
1008         SetNoListening( true );
1009         if ( bResultsOnly )
1010         {
1011             bOldAutoCalcSrc = rSrcDoc.GetAutoCalc();
1012             rSrcDoc.SetAutoCalc( true );   // in case something needs calculation
1013         }
1014 
1015         {
1016             NumFmtMergeHandler aNumFmtMergeHdl(*this, rSrcDoc);
1017 
1018             sc::CopyToDocContext aCxt(*this);
1019             nDestPos = std::min(nDestPos, static_cast<SCTAB>(GetTableCount() - 1));
1020             {   // scope for bulk broadcast
1021                 ScBulkBroadcast aBulkBroadcast( pBASM.get(), SfxHintId::ScDataChanged);
1022                 if (!bResultsOnly)
1023                 {
1024                     const bool bGlobalNamesToLocal = false;
1025                     const ScRangeName* pNames = rSrcDoc.GetRangeName( nSrcPos);
1026                     if (pNames)
1027                         pNames->CopyUsedNames( nSrcPos, nSrcPos, nDestPos, rSrcDoc, *this, bGlobalNamesToLocal);
1028                     rSrcDoc.GetRangeName()->CopyUsedNames( -1, nSrcPos, nDestPos, rSrcDoc, *this, bGlobalNamesToLocal);
1029                 }
1030                 rSrcDoc.maTabs[nSrcPos]->CopyToTable(aCxt, 0, 0, MaxCol(), MaxRow(),
1031                         ( bResultsOnly ? InsertDeleteFlags::ALL & ~InsertDeleteFlags::FORMULA : InsertDeleteFlags::ALL),
1032                         false, maTabs[nDestPos].get(), /*pMarkData*/nullptr, /*bAsLink*/false, /*bColRowFlags*/true,
1033                         /*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true );
1034             }
1035         }
1036         maTabs[nDestPos]->SetTabNo(nDestPos);
1037         maTabs[nDestPos]->SetTabBgColor(rSrcDoc.maTabs[nSrcPos]->GetTabBgColor());
1038 
1039         // tdf#66613 - copy existing print ranges and col/row repetitions
1040         if (auto aRepeatColRange = rSrcDoc.maTabs[nSrcPos]->GetRepeatColRange())
1041         {
1042             aRepeatColRange->aStart.SetTab(nDestPos);
1043             aRepeatColRange->aEnd.SetTab(nDestPos);
1044             maTabs[nDestPos]->SetRepeatColRange(std::move(aRepeatColRange));
1045         }
1046 
1047         if (auto aRepeatRowRange = rSrcDoc.maTabs[nSrcPos]->GetRepeatRowRange())
1048         {
1049             aRepeatRowRange->aStart.SetTab(nDestPos);
1050             aRepeatRowRange->aEnd.SetTab(nDestPos);
1051             maTabs[nDestPos]->SetRepeatRowRange(std::move(aRepeatRowRange));
1052         }
1053 
1054         if (rSrcDoc.IsPrintEntireSheet(nSrcPos))
1055             maTabs[nDestPos]->SetPrintEntireSheet();
1056         else
1057         {
1058             // tdf#157897 - clear print ranges before adding additional ones
1059             maTabs[nDestPos]->ClearPrintRanges();
1060             const auto nPrintRangeCount = rSrcDoc.maTabs[nSrcPos]->GetPrintRangeCount();
1061             for (auto nPos = 0; nPos < nPrintRangeCount; nPos++)
1062             {
1063                 // Adjust the tab for the print range at the new position
1064                 ScRange aSrcPrintRange(*rSrcDoc.maTabs[nSrcPos]->GetPrintRange(nPos));
1065                 aSrcPrintRange.aStart.SetTab(nDestPos);
1066                 aSrcPrintRange.aEnd.SetTab(nDestPos);
1067                 maTabs[nDestPos]->AddPrintRange(aSrcPrintRange);
1068             }
1069         }
1070 
1071         if ( !bResultsOnly )
1072         {
1073             sc::RefUpdateContext aRefCxt(*this);
1074             aRefCxt.meMode = URM_COPY;
1075             aRefCxt.maRange = ScRange(0, 0, nDestPos, MaxCol(), MaxRow(), nDestPos);
1076             aRefCxt.mnTabDelta = nDestPos - nSrcPos;
1077             maTabs[nDestPos]->UpdateReference(aRefCxt);
1078 
1079             // Readjust self-contained absolute references to this sheet
1080             maTabs[nDestPos]->TestTabRefAbs(nSrcPos);
1081             sc::CompileFormulaContext aFormulaCxt(*this);
1082             maTabs[nDestPos]->CompileAll(aFormulaCxt);
1083         }
1084 
1085         SetNoListening( false );
1086         if ( !bResultsOnly )
1087         {
1088             sc::StartListeningContext aSLCxt(*this);
1089             maTabs[nDestPos]->StartListeners(aSLCxt, true);
1090         }
1091         SetDirty( ScRange( 0, 0, nDestPos, MaxCol(), MaxRow(), nDestPos), false);
1092 
1093         if ( bResultsOnly )
1094             rSrcDoc.SetAutoCalc( bOldAutoCalcSrc );
1095         SetAutoCalc( bOldAutoCalc );
1096 
1097         //  copy Drawing
1098 
1099         if (bInsertNew)
1100             TransferDrawPage( rSrcDoc, nSrcPos, nDestPos );
1101 
1102         maTabs[nDestPos]->SetPendingRowHeights( rSrcDoc.maTabs[nSrcPos]->IsPendingRowHeights() );
1103     }
1104     if (!bValid)
1105         bRetVal = false;
1106     bool bVbaEnabled = IsInVBAMode();
1107 
1108     if ( bVbaEnabled  )
1109     {
1110         ScDocShell* pSrcShell = rSrcDoc.GetDocumentShell();
1111         if ( pSrcShell )
1112         {
1113             OUString aLibName(u"Standard"_ustr);
1114 #if HAVE_FEATURE_SCRIPTING
1115             const BasicManager *pBasicManager = pSrcShell->GetBasicManager();
1116             if (pBasicManager && !pBasicManager->GetName().isEmpty())
1117             {
1118                 aLibName = pSrcShell->GetBasicManager()->GetName();
1119             }
1120 #endif
1121             OUString sSource;
1122             uno::Reference< script::XLibraryContainer > xLibContainer = pSrcShell->GetBasicContainer();
1123             uno::Reference< container::XNameContainer > xLib;
1124             if( xLibContainer.is() )
1125             {
1126                 uno::Any aLibAny = xLibContainer->getByName(aLibName);
1127                 aLibAny >>= xLib;
1128             }
1129 
1130             if( xLib.is() )
1131             {
1132                 OUString sSrcCodeName;
1133                 rSrcDoc.GetCodeName( nSrcPos, sSrcCodeName );
1134                 OUString sRTLSource;
1135                 if (xLib->hasByName( sSrcCodeName ))
1136                     xLib->getByName( sSrcCodeName ) >>= sRTLSource;
1137                 sSource = sRTLSource;
1138             }
1139             VBA_InsertModule( *this, nDestPos, sSource );
1140         }
1141     }
1142 
1143     return bRetVal;
1144 }
1145 
SetError(SCCOL nCol,SCROW nRow,SCTAB nTab,const FormulaError nError)1146 void ScDocument::SetError( SCCOL nCol, SCROW nRow, SCTAB nTab, const FormulaError nError)
1147 {
1148     if (ScTable* pTable = FetchTable(nTab))
1149         pTable->SetError(nCol, nRow, nError);
1150 }
1151 
SetFormula(const ScAddress & rPos,const ScTokenArray & rArray)1152 void ScDocument::SetFormula(
1153     const ScAddress& rPos, const ScTokenArray& rArray )
1154 {
1155     if (ScTable* pTable = FetchTable(rPos.Tab()))
1156         pTable->SetFormula(rPos.Col(), rPos.Row(), rArray, formula::FormulaGrammar::GRAM_DEFAULT);
1157 }
1158 
SetFormula(const ScAddress & rPos,const OUString & rFormula,formula::FormulaGrammar::Grammar eGram)1159 void ScDocument::SetFormula(
1160     const ScAddress& rPos, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram )
1161 {
1162     if (ScTable* pTable = FetchTable(rPos.Tab()))
1163         pTable->SetFormula(rPos.Col(), rPos.Row(), rFormula, eGram);
1164 }
1165 
SetFormulaCell(const ScAddress & rPos,ScFormulaCell * pCell)1166 ScFormulaCell* ScDocument::SetFormulaCell( const ScAddress& rPos, ScFormulaCell* pCell )
1167 {
1168     if (ScTable* pTable = FetchTable(rPos.Tab()))
1169         return pTable->SetFormulaCell(rPos.Col(), rPos.Row(), pCell);
1170 
1171     delete pCell;
1172     return nullptr;
1173 }
1174 
SetFormulaCells(const ScAddress & rPos,std::vector<ScFormulaCell * > & rCells)1175 bool ScDocument::SetFormulaCells( const ScAddress& rPos, std::vector<ScFormulaCell*>& rCells )
1176 {
1177     if (rCells.empty())
1178         return false;
1179 
1180     if (ScTable* pTable = FetchTable(rPos.Tab()))
1181         return pTable->SetFormulaCells(rPos.Col(), rPos.Row(), rCells);
1182     return false;
1183 }
1184 
SetConsolidateDlgData(std::unique_ptr<ScConsolidateParam> pData)1185 void ScDocument::SetConsolidateDlgData( std::unique_ptr<ScConsolidateParam> pData )
1186 {
1187     pConsolidateDlgData = std::move(pData);
1188 }
1189 
SetEasyConditionalFormatDialogData(std::unique_ptr<ScConditionMode> pMode)1190 void ScDocument::SetEasyConditionalFormatDialogData(std::unique_ptr<ScConditionMode> pMode)
1191 {
1192     pConditionalFormatDialogMode = std::move(pMode);
1193 }
1194 
SetChangeViewSettings(const ScChangeViewSettings & rNew)1195 void ScDocument::SetChangeViewSettings(const ScChangeViewSettings& rNew)
1196 {
1197     if (pChangeViewSettings==nullptr)
1198         pChangeViewSettings.reset( new ScChangeViewSettings );
1199 
1200     *pChangeViewSettings=rNew;
1201 }
1202 
CreateFieldEditEngine()1203 std::unique_ptr<ScFieldEditEngine> ScDocument::CreateFieldEditEngine()
1204 {
1205     std::unique_ptr<ScFieldEditEngine> pNewEditEngine;
1206     if (!pCacheFieldEditEngine)
1207     {
1208         pNewEditEngine.reset( new ScFieldEditEngine(
1209             this, GetEditEnginePool(), false) );
1210     }
1211     else
1212     {
1213         if ( !bImportingXML )
1214         {
1215             // #i66209# previous use might not have restored update mode,
1216             // ensure same state as for a new EditEngine (UpdateMode = true)
1217             pCacheFieldEditEngine->SetUpdateLayout(true);
1218         }
1219 
1220         pNewEditEngine = std::move(pCacheFieldEditEngine);
1221     }
1222     return pNewEditEngine;
1223 }
1224 
DisposeFieldEditEngine(std::unique_ptr<ScFieldEditEngine> & rpEditEngine)1225 void ScDocument::DisposeFieldEditEngine(std::unique_ptr<ScFieldEditEngine>& rpEditEngine)
1226 {
1227     if (!pCacheFieldEditEngine && rpEditEngine)
1228     {
1229         pCacheFieldEditEngine = std::move( rpEditEngine );
1230         pCacheFieldEditEngine->Clear();
1231     }
1232     else
1233         rpEditEngine.reset();
1234 }
1235 
GetLookupCache(const ScRange & rRange,ScInterpreterContext * pContext)1236 ScLookupCache & ScDocument::GetLookupCache( const ScRange & rRange, ScInterpreterContext* pContext )
1237 {
1238     ScLookupCache* pCache = nullptr;
1239     if (!pContext->mxScLookupCache)
1240         pContext->mxScLookupCache.reset(new ScLookupCacheMap);
1241     ScLookupCacheMap* pCacheMap = pContext->mxScLookupCache.get();
1242     // insert with temporary value to avoid doing two lookups
1243     auto [findIt, bInserted] = pCacheMap->aCacheMap.emplace(rRange, nullptr);
1244     if (bInserted)
1245     {
1246         findIt->second = std::make_unique<ScLookupCache>(this, rRange, *pCacheMap);
1247         pCache = findIt->second.get();
1248         // The StartListeningArea() call is not thread-safe, as all threads
1249         // would access the same SvtBroadcaster.
1250         std::unique_lock guard( mScLookupMutex );
1251         StartListeningArea(rRange, false, pCache);
1252     }
1253     else
1254         pCache = (*findIt).second.get();
1255 
1256     return *pCache;
1257 }
1258 
GetSortedRangeCache(const ScRange & rRange,const ScQueryParam & param,ScInterpreterContext * pContext,bool bNewSearchFunction,sal_uInt8 nSortedBinarySearch)1259 ScSortedRangeCache& ScDocument::GetSortedRangeCache( const ScRange & rRange, const ScQueryParam& param,
1260                                                      ScInterpreterContext* pContext, bool bNewSearchFunction,
1261                                                      sal_uInt8 nSortedBinarySearch )
1262 {
1263     assert(mxScSortedRangeCache);
1264     ScSortedRangeCache::HashKey key = ScSortedRangeCache::makeHashKey(rRange, param);
1265     // This should be created just once for one range, and repeated calls should reuse it, even
1266     // between threads (it doesn't make sense to use ScInterpreterContext and have all threads
1267     // build their own copy of the same data). So first try read-only access, which should
1268     // in most cases be enough.
1269     {
1270       std::shared_lock guard(mScLookupMutex);
1271       auto findIt = mxScSortedRangeCache->aCacheMap.find(key);
1272       if( findIt != mxScSortedRangeCache->aCacheMap.end())
1273         return *findIt->second;
1274     }
1275     // Avoid recursive calls because of some cells in the range being dirty and triggering
1276     // interpreting, which may call into this again. Threaded calculation makes sure
1277     // no cells are dirty. If some cells in the range cannot be interpreted and remain
1278     // dirty e.g. because of circular dependencies, create only an invalid empty cache to prevent
1279     // a possible recursive deadlock.
1280     bool invalid = false;
1281     if(!IsThreadedGroupCalcInProgress())
1282         if(!InterpretCellsIfNeeded(rRange))
1283             invalid = true;
1284     std::unique_lock guard(mScLookupMutex);
1285     auto [findIt, bInserted] = mxScSortedRangeCache->aCacheMap.emplace(key, nullptr);
1286     if (bInserted)
1287     {
1288         findIt->second = std::make_unique<ScSortedRangeCache>(*this, rRange, param, pContext, invalid, bNewSearchFunction, nSortedBinarySearch);
1289         StartListeningArea(rRange, false, findIt->second.get());
1290     }
1291     return *findIt->second;
1292 }
1293 
RemoveLookupCache(ScLookupCache & rCache)1294 void ScDocument::RemoveLookupCache( ScLookupCache & rCache )
1295 {
1296     // Data changes leading to this should never happen during calculation (they are either
1297     // a result of user input or recalc). If it turns out this can be the case, locking is needed
1298     // here and also in ScLookupCache::Notify().
1299     assert(!IsThreadedGroupCalcInProgress());
1300     auto & cacheMap = rCache.getCacheMap();
1301     auto it(cacheMap.aCacheMap.find(rCache.getRange()));
1302     if (it != cacheMap.aCacheMap.end())
1303     {
1304         std::unique_ptr<ScLookupCache> xCache = std::move(it->second);
1305         cacheMap.aCacheMap.erase(it);
1306         assert(!IsThreadedGroupCalcInProgress()); // EndListeningArea() is not thread-safe
1307         EndListeningArea(xCache->getRange(), false, &rCache);
1308         return;
1309     }
1310     OSL_FAIL( "ScDocument::RemoveLookupCache: range not found in hash map");
1311 }
1312 
RemoveSortedRangeCache(ScSortedRangeCache & rCache)1313 void ScDocument::RemoveSortedRangeCache( ScSortedRangeCache & rCache )
1314 {
1315     // Data changes leading to this should never happen during calculation (they are either
1316     // a result of user input or recalc). If it turns out this can be the case, locking is needed
1317     // here and also in ScSortedRangeCache::Notify().
1318     assert(!IsThreadedGroupCalcInProgress());
1319     auto it(mxScSortedRangeCache->aCacheMap.find(rCache.getHashKey()));
1320     if (it != mxScSortedRangeCache->aCacheMap.end())
1321     {
1322         std::unique_ptr<ScSortedRangeCache> xCache = std::move(it->second);
1323         mxScSortedRangeCache->aCacheMap.erase(it);
1324         assert(!IsThreadedGroupCalcInProgress()); // EndListeningArea() is not thread-safe
1325         EndListeningArea(xCache->getRange(), false, &rCache);
1326         return;
1327     }
1328     OSL_FAIL( "ScDocument::RemoveSortedRangeCache: range not found in hash map");
1329 }
1330 
ClearLookupCaches()1331 void ScDocument::ClearLookupCaches()
1332 {
1333     assert(!IsThreadedGroupCalcInProgress());
1334     GetNonThreadedContext().mxScLookupCache.reset();
1335     mxScSortedRangeCache->aCacheMap.clear();
1336     // Clear lookup cache in all interpreter-contexts in the (threaded/non-threaded) pools.
1337     ScInterpreterContextPool::ClearLookupCaches(this);
1338 }
1339 
IsCellInChangeTrack(const ScAddress & cell,Color * pColCellBorder)1340 bool ScDocument::IsCellInChangeTrack(const ScAddress &cell,Color *pColCellBorder)
1341 {
1342     ScChangeTrack* pTrack = GetChangeTrack();
1343     ScChangeViewSettings* pSettings = GetChangeViewSettings();
1344     if ( !pTrack || !pTrack->GetFirst() || !pSettings || !pSettings->ShowChanges() )
1345         return false;           // missing or turned-off
1346     ScActionColorChanger aColorChanger(*pTrack);
1347     //  Clipping happens from outside
1348     //! TODO: without Clipping; only paint affected cells ??!??!?
1349     const ScChangeAction* pAction = pTrack->GetFirst();
1350     while (pAction)
1351     {
1352         if ( pAction->IsVisible() )
1353         {
1354             ScChangeActionType eType = pAction->GetType();
1355             const ScBigRange& rBig = pAction->GetBigRange();
1356             if ( rBig.aStart.Tab() == cell.Tab())
1357             {
1358                 ScRange aRange = rBig.MakeRange( *this );
1359                 if ( eType == SC_CAT_DELETE_ROWS )
1360                     aRange.aEnd.SetRow( aRange.aStart.Row() );
1361                 else if ( eType == SC_CAT_DELETE_COLS )
1362                     aRange.aEnd.SetCol( aRange.aStart.Col() );
1363                 if (ScViewUtil::IsActionShown( *pAction, *pSettings, *this ) )
1364                 {
1365                     if (aRange.Contains(cell))
1366                     {
1367                         if (pColCellBorder != nullptr)
1368                         {
1369                             aColorChanger.Update( *pAction );
1370                             Color aColor( aColorChanger.GetColor() );
1371                             *pColCellBorder = aColor;
1372                         }
1373                         return true;
1374                     }
1375                 }
1376             }
1377             if ( eType == SC_CAT_MOVE &&
1378                 static_cast<const ScChangeActionMove*>(pAction)->
1379                 GetFromRange().aStart.Tab() == cell.Col() )
1380             {
1381                 ScRange aRange = static_cast<const ScChangeActionMove*>(pAction)->
1382                     GetFromRange().MakeRange( *this );
1383                 if (ScViewUtil::IsActionShown( *pAction, *pSettings, *this ) )
1384                 {
1385                     if (aRange.Contains(cell))
1386                     {
1387                         if (pColCellBorder != nullptr)
1388                         {
1389                             aColorChanger.Update( *pAction );
1390                             Color aColor( aColorChanger.GetColor() );
1391                             *pColCellBorder = aColor;
1392                         }
1393                         return true;
1394                     }
1395                 }
1396             }
1397         }
1398         pAction = pAction->GetNext();
1399     }
1400     return false;
1401 }
1402 
GetCellChangeTrackNote(const ScAddress & aCellPos,OUString & aTrackText,bool & bLeftEdge)1403 void ScDocument::GetCellChangeTrackNote( const ScAddress &aCellPos, OUString &aTrackText,bool &bLeftEdge)
1404 {
1405     aTrackText.clear();
1406     //  Change-Tracking
1407     ScChangeTrack* pTrack = GetChangeTrack();
1408     ScChangeViewSettings* pSettings = GetChangeViewSettings();
1409     if ( !(pTrack && pTrack->GetFirst() && pSettings && pSettings->ShowChanges()))
1410         return;
1411 
1412     const ScChangeAction* pFound = nullptr;
1413     const ScChangeAction* pFoundContent = nullptr;
1414     const ScChangeAction* pFoundMove = nullptr;
1415     const ScChangeAction* pAction = pTrack->GetFirst();
1416     while (pAction)
1417     {
1418         if ( pAction->IsVisible() &&
1419              ScViewUtil::IsActionShown( *pAction, *pSettings, *this ) )
1420         {
1421             ScChangeActionType eType = pAction->GetType();
1422             const ScBigRange& rBig = pAction->GetBigRange();
1423             if ( rBig.aStart.Tab() == aCellPos.Tab())
1424             {
1425                 ScRange aRange = rBig.MakeRange( *this );
1426                 if ( eType == SC_CAT_DELETE_ROWS )
1427                     aRange.aEnd.SetRow( aRange.aStart.Row() );
1428                 else if ( eType == SC_CAT_DELETE_COLS )
1429                     aRange.aEnd.SetCol( aRange.aStart.Col() );
1430                 if ( aRange.Contains( aCellPos ) )
1431                 {
1432                     pFound = pAction;       // the last wins
1433                     switch ( eType )
1434                     {
1435                         case SC_CAT_CONTENT :
1436                             pFoundContent = pAction;
1437                         break;
1438                         case SC_CAT_MOVE :
1439                             pFoundMove = pAction;
1440                         break;
1441                         default:
1442                             break;
1443                     }
1444                 }
1445             }
1446             if ( eType == SC_CAT_MOVE )
1447             {
1448                 ScRange aRange =
1449                     static_cast<const ScChangeActionMove*>(pAction)->
1450                     GetFromRange().MakeRange( *this );
1451                 if ( aRange.Contains( aCellPos ) )
1452                 {
1453                     pFound = pAction;
1454                 }
1455             }
1456         }
1457         pAction = pAction->GetNext();
1458     }
1459     if ( !pFound )
1460         return;
1461 
1462     if ( pFoundContent && pFound->GetType() != SC_CAT_CONTENT )
1463         pFound = pFoundContent;     // Content wins
1464     if ( pFoundMove && pFound->GetType() != SC_CAT_MOVE &&
1465             pFoundMove->GetActionNumber() >
1466             pFound->GetActionNumber() )
1467         pFound = pFoundMove;        // Move wins
1468     //  for deleted columns: arrow on left side of row
1469     if ( pFound->GetType() == SC_CAT_DELETE_COLS )
1470         bLeftEdge = true;
1471     DateTime aDT = pFound->GetDateTime();
1472     aTrackText  = pFound->GetUser();
1473     aTrackText += ", ";
1474     aTrackText += ScGlobal::getLocaleData().getDate(aDT);
1475     aTrackText += " ";
1476     aTrackText += ScGlobal::getLocaleData().getTime(aDT);
1477     aTrackText += ":\n";
1478     OUString aComStr = pFound->GetComment();
1479     if(!aComStr.isEmpty())
1480     {
1481         aTrackText += aComStr;
1482         aTrackText += "\n( ";
1483     }
1484     aTrackText = pFound->GetDescription( *this );
1485     if (!aComStr.isEmpty())
1486     {
1487         aTrackText += ")";
1488     }
1489 }
1490 
SetPreviewFont(std::unique_ptr<SfxItemSet> pFont)1491 void ScDocument::SetPreviewFont( std::unique_ptr<SfxItemSet> pFont )
1492 {
1493     pPreviewFont = std::move(pFont);
1494 }
1495 
SetPreviewSelection(const ScMarkData & rSel)1496 void  ScDocument::SetPreviewSelection( const ScMarkData& rSel )
1497 {
1498     maPreviewSelection = rSel;
1499 }
1500 
GetPreviewFont(SCCOL nCol,SCROW nRow,SCTAB nTab)1501 SfxItemSet* ScDocument::GetPreviewFont( SCCOL nCol, SCROW nRow, SCTAB nTab )
1502 {
1503     SfxItemSet* pRet = nullptr;
1504     if ( pPreviewFont )
1505     {
1506         ScMarkData aSel = GetPreviewSelection();
1507         if ( aSel.IsCellMarked( nCol, nRow ) && aSel.GetFirstSelected() == nTab )
1508             pRet = pPreviewFont.get();
1509     }
1510     return pRet;
1511 }
1512 
GetPreviewCellStyle(SCCOL nCol,SCROW nRow,SCTAB nTab)1513 ScStyleSheet* ScDocument::GetPreviewCellStyle( SCCOL nCol, SCROW nRow, SCTAB nTab )
1514 {
1515     ScStyleSheet* pRet = nullptr;
1516     ScMarkData aSel = GetPreviewSelection();
1517     if ( pPreviewCellStyle && aSel.IsCellMarked( nCol, nRow ) && aSel.GetFirstSelected() == nTab  )
1518         pRet = pPreviewCellStyle;
1519     return pRet;
1520 }
1521 
GetIconSetBitmapMap()1522 sc::IconSetBitmapMap& ScDocument::GetIconSetBitmapMap()
1523 {
1524     if (!m_pIconSetBitmapMap)
1525     {
1526         m_pIconSetBitmapMap.reset(new sc::IconSetBitmapMap);
1527     }
1528     return *m_pIconSetBitmapMap;
1529 }
1530 
1531 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1532