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