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 <scitems.hxx>
21 #include <comphelper/fileformat.h>
22 #include <comphelper/processfactory.hxx>
23 #include <comphelper/servicehelper.hxx>
24 #include <tools/urlobj.hxx>
25 #include <editeng/editobj.hxx>
26 #include <editeng/frmdiritem.hxx>
27 #include <editeng/langitem.hxx>
28 #include <sfx2/linkmgr.hxx>
29 #include <sfx2/bindings.hxx>
30 #include <sfx2/objsh.hxx>
31 #include <sfx2/printer.hxx>
32 #include <sfx2/viewfrm.hxx>
33 #include <sfx2/viewsh.hxx>
34 #include <svl/flagitem.hxx>
35 #include <svl/intitem.hxx>
36 #include <svl/zforlist.hxx>
37 #include <svl/zformat.hxx>
38 #include <unotools/misccfg.hxx>
39 #include <unotools/transliterationwrapper.hxx>
40 #include <sal/log.hxx>
41 
42 #include <vcl/svapp.hxx>
43 #include <vcl/virdev.hxx>
44 #include <vcl/weld.hxx>
45 #include <vcl/TaskStopwatch.hxx>
46 
47 #include <inputopt.hxx>
48 #include <global.hxx>
49 #include <table.hxx>
50 #include <column.hxx>
51 #include <poolhelp.hxx>
52 #include <docpool.hxx>
53 #include <stlpool.hxx>
54 #include <stlsheet.hxx>
55 #include <docoptio.hxx>
56 #include <viewopti.hxx>
57 #include <scextopt.hxx>
58 #include <rechead.hxx>
59 #include <ddelink.hxx>
60 #include <scmatrix.hxx>
61 #include <arealink.hxx>
62 #include <patattr.hxx>
63 #include <editutil.hxx>
64 #include <progress.hxx>
65 #include <document.hxx>
66 #include <chartlis.hxx>
67 #include <chartlock.hxx>
68 #include <refupdat.hxx>
69 #include <markdata.hxx>
70 #include <scmod.hxx>
71 #include <externalrefmgr.hxx>
72 #include <globstr.hrc>
73 #include <strings.hrc>
74 #include <sc.hrc>
75 #include <charthelper.hxx>
76 #include <macromgr.hxx>
77 #include <docuno.hxx>
78 #include <scresid.hxx>
79 #include <columniterator.hxx>
80 #include <globalnames.hxx>
81 #include <stringutil.hxx>
82 #include <documentlinkmgr.hxx>
83 #include <scopetools.hxx>
84 #include <tokenarray.hxx>
85 
86 #include <memory>
87 #include <utility>
88 
89 using namespace com::sun::star;
90 
91 namespace {
92 
getScaleValue(SfxStyleSheetBase & rStyle,sal_uInt16 nWhich)93 sal_uInt16 getScaleValue(SfxStyleSheetBase& rStyle, sal_uInt16 nWhich)
94 {
95     return static_cast<const SfxUInt16Item&>(rStyle.GetItemSet().Get(nWhich)).GetValue();
96 }
97 
98 }
99 
ImplCreateOptions()100 void ScDocument::ImplCreateOptions()
101 {
102     pDocOptions.reset( new ScDocOptions() );
103     pViewOptions.reset( new ScViewOptions() );
104 }
105 
ImplDeleteOptions()106 void ScDocument::ImplDeleteOptions()
107 {
108     pDocOptions.reset();
109     pViewOptions.reset();
110     pExtDocOptions.reset();
111 }
112 
GetPrinter(bool bCreateIfNotExist)113 SfxPrinter* ScDocument::GetPrinter(bool bCreateIfNotExist)
114 {
115     if ( !mpPrinter && bCreateIfNotExist )
116     {
117         auto pSet =
118             std::make_unique<SfxItemSet>( *mxPoolHelper->GetDocPool(),
119                             svl::Items<SID_PRINTER_NOTFOUND_WARN,  SID_PRINTER_NOTFOUND_WARN,
120                             SID_PRINTER_CHANGESTODOC,   SID_PRINTER_CHANGESTODOC,
121                             SID_PRINT_SELECTEDSHEET,    SID_PRINT_SELECTEDSHEET,
122                             SID_SCPRINTOPTIONS,         SID_SCPRINTOPTIONS>{} );
123 
124         ::utl::MiscCfg aMisc;
125         SfxPrinterChangeFlags nFlags = SfxPrinterChangeFlags::NONE;
126         if ( aMisc.IsPaperOrientationWarning() )
127             nFlags |= SfxPrinterChangeFlags::CHG_ORIENTATION;
128         if ( aMisc.IsPaperSizeWarning() )
129             nFlags |= SfxPrinterChangeFlags::CHG_SIZE;
130         pSet->Put( SfxFlagItem( SID_PRINTER_CHANGESTODOC, static_cast<int>(nFlags) ) );
131         pSet->Put( SfxBoolItem( SID_PRINTER_NOTFOUND_WARN, aMisc.IsNotFoundWarning() ) );
132 
133         mpPrinter = VclPtr<SfxPrinter>::Create( std::move(pSet) );
134         mpPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
135         UpdateDrawPrinter();
136         mpPrinter->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
137     }
138 
139     return mpPrinter;
140 }
141 
SetPrinter(VclPtr<SfxPrinter> const & pNewPrinter)142 void ScDocument::SetPrinter( VclPtr<SfxPrinter> const & pNewPrinter )
143 {
144     if ( pNewPrinter == mpPrinter.get() )
145     {
146         //  #i6706# SetPrinter is called with the same printer again if
147         //  the JobSetup has changed. In that case just call UpdateDrawPrinter
148         //  (SetRefDevice for drawing layer) because of changed text sizes.
149         UpdateDrawPrinter();
150     }
151     else
152     {
153         ScopedVclPtr<SfxPrinter> pOld( mpPrinter );
154         mpPrinter = pNewPrinter;
155         UpdateDrawPrinter();
156         mpPrinter->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
157     }
158     InvalidateTextWidth(nullptr, nullptr, false);     // in both cases
159 }
160 
SetPrintOptions()161 void ScDocument::SetPrintOptions()
162 {
163     if ( !mpPrinter ) GetPrinter(); // this sets mpPrinter
164     OSL_ENSURE( mpPrinter, "Error in printer creation :-/" );
165 
166     if ( mpPrinter )
167     {
168         ::utl::MiscCfg aMisc;
169         SfxItemSet aOptSet( mpPrinter->GetOptions() );
170 
171         SfxPrinterChangeFlags nFlags = SfxPrinterChangeFlags::NONE;
172         if ( aMisc.IsPaperOrientationWarning() )
173             nFlags |= SfxPrinterChangeFlags::CHG_ORIENTATION;
174         if ( aMisc.IsPaperSizeWarning() )
175             nFlags |= SfxPrinterChangeFlags::CHG_SIZE;
176         aOptSet.Put( SfxFlagItem( SID_PRINTER_CHANGESTODOC, static_cast<int>(nFlags) ) );
177         aOptSet.Put( SfxBoolItem( SID_PRINTER_NOTFOUND_WARN, aMisc.IsNotFoundWarning() ) );
178 
179         mpPrinter->SetOptions( aOptSet );
180     }
181 }
182 
GetVirtualDevice_100th_mm()183 VirtualDevice* ScDocument::GetVirtualDevice_100th_mm()
184 {
185     if (!mpVirtualDevice_100th_mm)
186     {
187 #ifdef IOS
188         mpVirtualDevice_100th_mm = VclPtr<VirtualDevice>::Create(DeviceFormat::GRAYSCALE);
189 #else
190         mpVirtualDevice_100th_mm = VclPtr<VirtualDevice>::Create(DeviceFormat::BITMASK);
191 #endif
192         mpVirtualDevice_100th_mm->SetReferenceDevice(VirtualDevice::RefDevMode::MSO1);
193         MapMode aMapMode( mpVirtualDevice_100th_mm->GetMapMode() );
194         aMapMode.SetMapUnit( MapUnit::Map100thMM );
195         mpVirtualDevice_100th_mm->SetMapMode( aMapMode );
196     }
197     return mpVirtualDevice_100th_mm;
198 }
199 
GetRefDevice()200 OutputDevice* ScDocument::GetRefDevice()
201 {
202     // Create printer like ref device, see Writer...
203     OutputDevice* pRefDevice = nullptr;
204     if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() )
205         pRefDevice = GetPrinter();
206     else
207         pRefDevice = GetVirtualDevice_100th_mm();
208     return pRefDevice;
209 }
210 
ModifyStyleSheet(SfxStyleSheetBase & rStyleSheet,const SfxItemSet & rChanges)211 void ScDocument::ModifyStyleSheet( SfxStyleSheetBase& rStyleSheet,
212                                    const SfxItemSet&  rChanges )
213 {
214     SfxItemSet& rSet = rStyleSheet.GetItemSet();
215 
216     switch ( rStyleSheet.GetFamily() )
217     {
218         case SfxStyleFamily::Page:
219             {
220                 const sal_uInt16 nOldScale = getScaleValue(rStyleSheet, ATTR_PAGE_SCALE);
221                 const sal_uInt16 nOldScaleToPages = getScaleValue(rStyleSheet, ATTR_PAGE_SCALETOPAGES);
222                 rSet.Put( rChanges );
223                 const sal_uInt16 nNewScale        = getScaleValue(rStyleSheet, ATTR_PAGE_SCALE);
224                 const sal_uInt16 nNewScaleToPages = getScaleValue(rStyleSheet, ATTR_PAGE_SCALETOPAGES);
225 
226                 if ( (nOldScale != nNewScale) || (nOldScaleToPages != nNewScaleToPages) )
227                     InvalidateTextWidth( rStyleSheet.GetName() );
228 
229                 if( SvtLanguageOptions().IsCTLFontEnabled() )
230                 {
231                     const SfxPoolItem *pItem = nullptr;
232                     if( rChanges.GetItemState(ATTR_WRITINGDIR, true, &pItem ) == SfxItemState::SET )
233                         ScChartHelper::DoUpdateAllCharts( this );
234                 }
235             }
236             break;
237 
238         case SfxStyleFamily::Para:
239             {
240                 bool bNumFormatChanged;
241                 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
242                         rSet, rChanges ) )
243                     InvalidateTextWidth( nullptr, nullptr, bNumFormatChanged );
244 
245                 for (SCTAB nTab=0; nTab<=MAXTAB; ++nTab)
246                     if (maTabs[nTab])
247                         maTabs[nTab]->SetStreamValid( false );
248 
249                 sal_uLong nOldFormat =
250                     rSet.Get( ATTR_VALUE_FORMAT ).GetValue();
251                 sal_uLong nNewFormat =
252                     rChanges.Get( ATTR_VALUE_FORMAT ).GetValue();
253                 LanguageType eNewLang, eOldLang;
254                 eNewLang = eOldLang = LANGUAGE_DONTKNOW;
255                 if ( nNewFormat != nOldFormat )
256                 {
257                     SvNumberFormatter* pFormatter = GetFormatTable();
258                     eOldLang = pFormatter->GetEntry( nOldFormat )->GetLanguage();
259                     eNewLang = pFormatter->GetEntry( nNewFormat )->GetLanguage();
260                 }
261 
262                 // Explanation to Items in rChanges:
263                 //  Set Item        - take over change
264                 //  Dontcare        - Set Default
265                 //  Default         - No change
266                 // ("no change" is not possible with PutExtended, thus the loop)
267                 for (sal_uInt16 nWhich = ATTR_PATTERN_START; nWhich <= ATTR_PATTERN_END; nWhich++)
268                 {
269                     const SfxPoolItem* pItem;
270                     SfxItemState eState = rChanges.GetItemState( nWhich, false, &pItem );
271                     if ( eState == SfxItemState::SET )
272                         rSet.Put( *pItem );
273                     else if ( eState == SfxItemState::DONTCARE )
274                         rSet.ClearItem( nWhich );
275                     // when Default nothing
276                 }
277 
278                 if ( eNewLang != eOldLang )
279                     rSet.Put(
280                         SvxLanguageItem( eNewLang, ATTR_LANGUAGE_FORMAT ) );
281             }
282             break;
283         default:
284         {
285             // added to avoid warnings
286         }
287     }
288 }
289 
CopyStdStylesFrom(const ScDocument * pSrcDoc)290 void ScDocument::CopyStdStylesFrom( const ScDocument* pSrcDoc )
291 {
292     // number format exchange list has to be handled here, too
293     NumFmtMergeHandler aNumFmtMergeHdl(this, pSrcDoc);
294     mxPoolHelper->GetStylePool()->CopyStdStylesFrom( pSrcDoc->mxPoolHelper->GetStylePool() );
295 }
296 
InvalidateTextWidth(const OUString & rStyleName)297 void ScDocument::InvalidateTextWidth( const OUString& rStyleName )
298 {
299     const SCTAB nCount = GetTableCount();
300     for ( SCTAB i=0; i<nCount && maTabs[i]; i++ )
301         if ( maTabs[i]->GetPageStyle() == rStyleName )
302             InvalidateTextWidth( i );
303 }
304 
InvalidateTextWidth(SCTAB nTab)305 void ScDocument::InvalidateTextWidth( SCTAB nTab )
306 {
307     ScAddress aAdrFrom( 0,    0,        nTab );
308     ScAddress aAdrTo  ( MaxCol(), MaxRow(), nTab );
309     InvalidateTextWidth( &aAdrFrom, &aAdrTo, false );
310 }
311 
IsPageStyleInUse(const OUString & rStrPageStyle,SCTAB * pInTab)312 bool ScDocument::IsPageStyleInUse( const OUString& rStrPageStyle, SCTAB* pInTab )
313 {
314     bool         bInUse = false;
315     const SCTAB nCount = GetTableCount();
316     SCTAB i;
317 
318     for ( i = 0; !bInUse && i < nCount && maTabs[i]; i++ )
319         bInUse = ( maTabs[i]->GetPageStyle() == rStrPageStyle );
320 
321     if ( pInTab )
322         *pInTab = i-1;
323 
324     return bInUse;
325 }
326 
RemovePageStyleInUse(const OUString & rStyle)327 bool ScDocument::RemovePageStyleInUse( const OUString& rStyle )
328 {
329     bool bWasInUse = false;
330     const SCTAB nCount = GetTableCount();
331 
332     for ( SCTAB i=0; i<nCount && maTabs[i]; i++ )
333         if ( maTabs[i]->GetPageStyle() == rStyle )
334         {
335             bWasInUse = true;
336             maTabs[i]->SetPageStyle( ScResId(STR_STYLENAME_STANDARD) );
337         }
338 
339     return bWasInUse;
340 }
341 
RenamePageStyleInUse(const OUString & rOld,const OUString & rNew)342 bool ScDocument::RenamePageStyleInUse( const OUString& rOld, const OUString& rNew )
343 {
344     bool bWasInUse = false;
345     const SCTAB nCount = GetTableCount();
346 
347     for ( SCTAB i=0; i<nCount && maTabs[i]; i++ )
348         if ( maTabs[i]->GetPageStyle() == rOld )
349         {
350             bWasInUse = true;
351             maTabs[i]->SetPageStyle( rNew );
352         }
353 
354     return bWasInUse;
355 }
356 
GetEditTextDirection(SCTAB nTab) const357 EEHorizontalTextDirection ScDocument::GetEditTextDirection(SCTAB nTab) const
358 {
359     EEHorizontalTextDirection eRet = EEHorizontalTextDirection::Default;
360 
361     OUString aStyleName = GetPageStyle( nTab );
362     SfxStyleSheetBase* pStyle = mxPoolHelper->GetStylePool()->Find( aStyleName, SfxStyleFamily::Page );
363     if ( pStyle )
364     {
365         SfxItemSet& rStyleSet = pStyle->GetItemSet();
366         SvxFrameDirection eDirection =
367             rStyleSet.Get( ATTR_WRITINGDIR ).GetValue();
368 
369         if ( eDirection == SvxFrameDirection::Horizontal_LR_TB )
370             eRet = EEHorizontalTextDirection::L2R;
371         else if ( eDirection == SvxFrameDirection::Horizontal_RL_TB )
372             eRet = EEHorizontalTextDirection::R2L;
373         // else (invalid for EditEngine): keep "default"
374     }
375 
376     return eRet;
377 }
378 
GetMacroManager()379 ScMacroManager* ScDocument::GetMacroManager()
380 {
381     if (!mpMacroMgr)
382         mpMacroMgr.reset(new ScMacroManager(this));
383     return mpMacroMgr.get();
384 }
385 
FillMatrix(ScMatrix & rMat,SCTAB nTab,SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2,svl::SharedStringPool * pPool) const386 void ScDocument::FillMatrix(
387     ScMatrix& rMat, SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, svl::SharedStringPool* pPool ) const
388 {
389     const ScTable* pTab = FetchTable(nTab);
390     if (!pTab)
391         return;
392 
393     if (nCol1 > nCol2 || nRow1 > nRow2)
394         return;
395 
396     SCSIZE nC, nR;
397     rMat.GetDimensions(nC, nR);
398     if (static_cast<SCROW>(nR) != nRow2 - nRow1 + 1 || static_cast<SCCOL>(nC) != nCol2 - nCol1 + 1)
399         return;
400 
401     pTab->FillMatrix(rMat, nCol1, nRow1, nCol2, nRow2, pPool);
402 }
403 
SetFormulaResults(const ScAddress & rTopPos,const double * pResults,size_t nLen)404 void ScDocument::SetFormulaResults( const ScAddress& rTopPos, const double* pResults, size_t nLen )
405 {
406     ScTable* pTab = FetchTable(rTopPos.Tab());
407     if (!pTab)
408         return;
409 
410     pTab->SetFormulaResults(rTopPos.Col(), rTopPos.Row(), pResults, nLen);
411 }
412 
CalculateInColumnInThread(ScInterpreterContext & rContext,const ScRange & rCalcRange,unsigned nThisThread,unsigned nThreadsTotal)413 const ScDocumentThreadSpecific& ScDocument::CalculateInColumnInThread( ScInterpreterContext& rContext, const ScRange& rCalcRange, unsigned nThisThread, unsigned nThreadsTotal)
414 {
415     ScTable* pTab = FetchTable(rCalcRange.aStart.Tab());
416     if (!pTab)
417         return maNonThreaded;
418 
419     assert(IsThreadedGroupCalcInProgress());
420 
421     maThreadSpecific.pContext = &rContext;
422     ScDocumentThreadSpecific::SetupFromNonThreadedData(maNonThreaded);
423     pTab->CalculateInColumnInThread(rContext, rCalcRange.aStart.Col(), rCalcRange.aEnd.Col(), rCalcRange.aStart.Row(), rCalcRange.aEnd.Row(), nThisThread, nThreadsTotal);
424 
425     assert(IsThreadedGroupCalcInProgress());
426     maThreadSpecific.pContext = nullptr;
427 
428     return maThreadSpecific;
429 }
430 
HandleStuffAfterParallelCalculation(SCCOL nColStart,SCCOL nColEnd,SCROW nRow,size_t nLen,SCTAB nTab,ScInterpreter * pInterpreter)431 void ScDocument::HandleStuffAfterParallelCalculation( SCCOL nColStart, SCCOL nColEnd, SCROW nRow, size_t nLen, SCTAB nTab, ScInterpreter* pInterpreter )
432 {
433     assert(!IsThreadedGroupCalcInProgress());
434     for( const DelayedSetNumberFormat& data : GetNonThreadedContext().maDelayedSetNumberFormat)
435         SetNumberFormat( ScAddress( data.mCol, data.mRow, nTab ), data.mnNumberFormat );
436     GetNonThreadedContext().maDelayedSetNumberFormat.clear();
437 
438     ScTable* pTab = FetchTable(nTab);
439     if (!pTab)
440         return;
441 
442     pTab->HandleStuffAfterParallelCalculation(nColStart, nColEnd, nRow, nLen, pInterpreter);
443 }
444 
InvalidateTextWidth(const ScAddress * pAdrFrom,const ScAddress * pAdrTo,bool bNumFormatChanged)445 void ScDocument::InvalidateTextWidth( const ScAddress* pAdrFrom, const ScAddress* pAdrTo,
446                                       bool bNumFormatChanged )
447 {
448     bool bBroadcast = (bNumFormatChanged && GetDocOptions().IsCalcAsShown() && !IsImportingXML() && !IsClipboard());
449     if ( pAdrFrom && !pAdrTo )
450     {
451         const SCTAB nTab = pAdrFrom->Tab();
452 
453         if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
454             maTabs[nTab]->InvalidateTextWidth( pAdrFrom, nullptr, bNumFormatChanged, bBroadcast );
455     }
456     else
457     {
458         const SCTAB nTabStart = pAdrFrom ? pAdrFrom->Tab() : 0;
459         const SCTAB nTabEnd   = pAdrTo   ? pAdrTo->Tab()   : MAXTAB;
460 
461         for ( SCTAB nTab=nTabStart; nTab<=nTabEnd && nTab < static_cast<SCTAB>(maTabs.size()); nTab++ )
462             if ( maTabs[nTab] )
463                 maTabs[nTab]->InvalidateTextWidth( pAdrFrom, pAdrTo, bNumFormatChanged, bBroadcast );
464     }
465 }
466 
467 #define CALCMAX                 1000    // Calculations
468 
469 namespace {
470 
471 class IdleCalcTextWidthScope : public TaskStopwatch
472 {
473     ScDocument& mrDoc;
474     ScAddress& mrCalcPos;
475     MapMode maOldMapMode;
476     ScStyleSheetPool* mpStylePool;
477     SfxStyleSearchBits const mnOldSearchMask;
478     SfxStyleFamily const meOldFamily;
479     bool mbNeedMore;
480     bool mbProgress;
481 
482 public:
IdleCalcTextWidthScope(ScDocument & rDoc,ScAddress & rCalcPos)483     IdleCalcTextWidthScope(ScDocument& rDoc, ScAddress& rCalcPos) :
484         mrDoc(rDoc),
485         mrCalcPos(rCalcPos),
486         mpStylePool(rDoc.GetStyleSheetPool()),
487         mnOldSearchMask(mpStylePool->GetSearchMask()),
488         meOldFamily(mpStylePool->GetSearchFamily()),
489         mbNeedMore(false),
490         mbProgress(false)
491     {
492         // The old search mask / family flags must be restored so that e.g.
493         // the styles dialog shows correct listing when it's opened in-between
494         // the calls.
495 
496         mrDoc.EnableIdle(false);
497         mpStylePool->SetSearchMask(SfxStyleFamily::Page);
498     }
499 
~IdleCalcTextWidthScope()500     ~IdleCalcTextWidthScope() COVERITY_NOEXCEPT_FALSE
501     {
502         SfxPrinter* pDev = mrDoc.GetPrinter();
503         if (pDev)
504             pDev->SetMapMode(maOldMapMode);
505 
506         if (mbProgress)
507             ScProgress::DeleteInterpretProgress();
508 
509         mpStylePool->SetSearchMask(meOldFamily, mnOldSearchMask);
510         mrDoc.EnableIdle(true);
511     }
512 
Tab() const513     SCTAB Tab() const { return mrCalcPos.Tab(); }
Col() const514     SCCOL Col() const { return mrCalcPos.Col(); }
Row() const515     SCROW Row() const { return mrCalcPos.Row(); }
516 
setTab(SCTAB nTab)517     void setTab(SCTAB nTab) { mrCalcPos.SetTab(nTab); }
setCol(SCCOL nCol)518     void setCol(SCCOL nCol) { mrCalcPos.SetCol(nCol); }
setRow(SCROW nRow)519     void setRow(SCROW nRow) { mrCalcPos.SetRow(nRow); }
520 
incTab()521     void incTab() { mrCalcPos.IncTab(); }
incCol(SCCOL nInc)522     void incCol(SCCOL nInc) { mrCalcPos.IncCol(nInc); }
523 
setOldMapMode(const MapMode & rOldMapMode)524     void setOldMapMode(const MapMode& rOldMapMode) { maOldMapMode = rOldMapMode; }
525 
setNeedMore(bool b)526     void setNeedMore(bool b) { mbNeedMore = b; }
getNeedMore() const527     bool getNeedMore() const { return mbNeedMore; }
528 
createProgressBar()529     void createProgressBar()
530     {
531         ScProgress::CreateInterpretProgress(&mrDoc, false);
532         mbProgress = true;
533     }
534 
hasProgressBar() const535     bool hasProgressBar() const { return mbProgress; }
536 
getStylePool()537     ScStyleSheetPool* getStylePool() { return mpStylePool; }
538 };
539 
540 }
541 
IdleCalcTextWidth()542 bool ScDocument::IdleCalcTextWidth()            // true = try next again
543 {
544     // #i75610# if a printer hasn't been set or created yet, don't create one for this
545     if (!mbIdleEnabled || IsInLinkUpdate() || GetPrinter(false) == nullptr)
546         return false;
547 
548     IdleCalcTextWidthScope aScope(*this, aCurTextWidthCalcPos);
549 
550     if (!ValidRow(aScope.Row()))
551     {
552         aScope.setRow(0);
553         aScope.incCol(-1);
554     }
555 
556     if (aScope.Col() < 0)
557     {
558         aScope.setCol(MaxCol());
559         aScope.incTab();
560     }
561 
562     if (!ValidTab(aScope.Tab()) || aScope.Tab() >= static_cast<SCTAB>(maTabs.size()) || !maTabs[aScope.Tab()])
563         aScope.setTab(0);
564 
565     ScTable* pTab = maTabs[aScope.Tab()].get();
566     ScStyleSheet* pStyle = static_cast<ScStyleSheet*>(aScope.getStylePool()->Find(pTab->aPageStyle, SfxStyleFamily::Page));
567     OSL_ENSURE( pStyle, "Missing StyleSheet :-/" );
568 
569     if (!pStyle || getScaleValue(*pStyle, ATTR_PAGE_SCALETOPAGES) == 0)
570     {
571         // Move to the next sheet as the current one has scale-to-pages set,
572         // and bail out.
573         aScope.incTab();
574         return false;
575     }
576 
577     sal_uInt16 nZoom = getScaleValue(*pStyle, ATTR_PAGE_SCALE);
578     Fraction aZoomFract(nZoom, 100);
579 
580     aScope.setCol(pTab->ClampToAllocatedColumns(aScope.Col()));
581     // Start at specified cell position (nCol, nRow, nTab).
582     ScColumn* pCol  = &pTab->aCol[aScope.Col()];
583     std::unique_ptr<ScColumnTextWidthIterator> pColIter(new ScColumnTextWidthIterator(*pCol, aScope.Row(), MaxRow()));
584 
585     OutputDevice* pDev = nullptr;
586     sal_uInt16 nRestart = 0;
587     sal_uInt16 nCount = 0;
588     while ( (nZoom > 0) && (nCount < CALCMAX) && (nRestart < 2) )
589     {
590         if (pColIter->hasCell())
591         {
592             // More cell in this column.
593             SCROW nRow = pColIter->getPos();
594             aScope.setRow(nRow);
595 
596             if (pColIter->getValue() == TEXTWIDTH_DIRTY)
597             {
598                 // Calculate text width for this cell.
599                 double nPPTX = 0.0;
600                 double nPPTY = 0.0;
601                 if (!pDev)
602                 {
603                     pDev = GetPrinter();
604                     aScope.setOldMapMode(pDev->GetMapMode());
605                     pDev->SetMapMode(MapMode(MapUnit::MapPixel)); // Important for GetNeededSize
606 
607                     Point aPix1000 = pDev->LogicToPixel(Point(1000,1000), MapMode(MapUnit::MapTwip));
608                     nPPTX = aPix1000.X() / 1000.0;
609                     nPPTY = aPix1000.Y() / 1000.0;
610                 }
611 
612                 if (!aScope.hasProgressBar() && pCol->IsFormulaDirty(nRow))
613                     aScope.createProgressBar();
614 
615                 sal_uInt16 nNewWidth = static_cast<sal_uInt16>(GetNeededSize(
616                     aScope.Col(), aScope.Row(), aScope.Tab(),
617                     pDev, nPPTX, nPPTY, aZoomFract,aZoomFract, true, true));   // bTotalSize
618 
619                 pColIter->setValue(nNewWidth);
620                 aScope.setNeedMore(true);
621             }
622             pColIter->next();
623         }
624         else
625         {
626             // No more cell in this column.  Move to the left column and start at row 0.
627 
628             bool bNewTab = false;
629 
630             aScope.setRow(0);
631             aScope.incCol(-1);
632 
633             if (aScope.Col() < 0)
634             {
635                 // No more column to the left.  Move to the right-most column of the next sheet.
636                 aScope.setCol(MaxCol());
637                 aScope.incTab();
638                 bNewTab = true;
639             }
640 
641             if (!ValidTab(aScope.Tab()) || aScope.Tab() >= static_cast<SCTAB>(maTabs.size()) || !maTabs[aScope.Tab()] )
642             {
643                 // Sheet doesn't exist at specified sheet position.  Restart at sheet 0.
644                 aScope.setTab(0);
645                 nRestart++;
646                 bNewTab = true;
647             }
648 
649             if ( nRestart < 2 )
650             {
651                 if ( bNewTab )
652                 {
653                     pTab = maTabs[aScope.Tab()].get();
654                     aScope.setCol(pTab->ClampToAllocatedColumns(aScope.Col()));
655                     pStyle = static_cast<ScStyleSheet*>(aScope.getStylePool()->Find(
656                         pTab->aPageStyle, SfxStyleFamily::Page));
657 
658                     if ( pStyle )
659                     {
660                         // Check if the scale-to-pages setting is set. If
661                         // set, we exit the loop.  If not, get the page
662                         // scale factor of the new sheet.
663                         if (getScaleValue(*pStyle, ATTR_PAGE_SCALETOPAGES) == 0)
664                         {
665                             nZoom = getScaleValue(*pStyle, ATTR_PAGE_SCALE);
666                             aZoomFract = Fraction(nZoom, 100);
667                         }
668                         else
669                             nZoom = 0;
670                     }
671                     else
672                     {
673                         OSL_FAIL( "Missing StyleSheet :-/" );
674                     }
675                 }
676 
677                 if ( nZoom > 0 )
678                 {
679                     pCol  = &pTab->aCol[aScope.Col()];
680                     pColIter.reset(new ScColumnTextWidthIterator(*pCol, aScope.Row(), MaxRow()));
681                 }
682                 else
683                 {
684                     aScope.incTab(); // Move to the next sheet as the current one has scale-to-pages set.
685                     return false;
686                 }
687             }
688         }
689 
690         ++nCount;
691 
692         if (!aScope.continueIter())
693             break;
694     }
695 
696     return aScope.getNeedMore();
697 }
698 
RepaintRange(const ScRange & rRange)699 void ScDocument::RepaintRange( const ScRange& rRange )
700 {
701     if ( bIsVisible && mpShell )
702     {
703         ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>( mpShell->GetModel() );
704         if ( pModel )
705             pModel->RepaintRange( rRange );     // locked repaints are checked there
706     }
707 }
708 
RepaintRange(const ScRangeList & rRange)709 void ScDocument::RepaintRange( const ScRangeList& rRange )
710 {
711     if ( bIsVisible && mpShell )
712     {
713         ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>( mpShell->GetModel() );
714         if ( pModel )
715             pModel->RepaintRange( rRange );     // locked repaints are checked there
716     }
717 }
718 
SaveDdeLinks(SvStream & rStream) const719 void ScDocument::SaveDdeLinks(SvStream& rStream) const
720 {
721     //  when 4.0-Export, remove all with mode != DEFAULT
722     bool bExport40 = ( rStream.GetVersion() <= SOFFICE_FILEFORMAT_40 );
723 
724     const ::sfx2::SvBaseLinks& rLinks = GetLinkManager()->GetLinks();
725     sal_uInt16 nCount = rLinks.size();
726 
727     // Count them first
728 
729     sal_uInt16 nDdeCount = 0;
730     sal_uInt16 i;
731     for (i=0; i<nCount; i++)
732     {
733         ::sfx2::SvBaseLink* pBase = rLinks[i].get();
734         if (ScDdeLink* pLink = dynamic_cast<ScDdeLink*>(pBase))
735             if ( !bExport40 || pLink->GetMode() == SC_DDE_DEFAULT )
736                 ++nDdeCount;
737     }
738 
739     //  Header
740 
741     ScMultipleWriteHeader aHdr( rStream );
742     rStream.WriteUInt16( nDdeCount );
743 
744     // Save links
745 
746     for (i=0; i<nCount; i++)
747     {
748         ::sfx2::SvBaseLink* pBase = rLinks[i].get();
749         if (ScDdeLink* pLink = dynamic_cast<ScDdeLink*>(pBase))
750         {
751             if ( !bExport40 || pLink->GetMode() == SC_DDE_DEFAULT )
752                 pLink->Store( rStream, aHdr );
753         }
754     }
755 }
756 
LoadDdeLinks(SvStream & rStream)757 void ScDocument::LoadDdeLinks(SvStream& rStream)
758 {
759     sfx2::LinkManager* pMgr = GetDocLinkManager().getLinkManager(bAutoCalc);
760     if (!pMgr)
761         return;
762 
763     ScMultipleReadHeader aHdr( rStream );
764 
765     sal_uInt16 nCount(0);
766     rStream.ReadUInt16( nCount );
767 
768     const rtl_TextEncoding eCharSet = rStream.GetStreamCharSet();
769     const size_t nMinStringSize = eCharSet == RTL_TEXTENCODING_UNICODE ? sizeof(sal_uInt32) : sizeof(sal_uInt16);
770     const size_t nMinRecordSize = 1 + nMinStringSize*3;
771     const size_t nMaxRecords = rStream.remainingSize() / nMinRecordSize;
772     if (nCount > nMaxRecords)
773     {
774         SAL_WARN("sc", "Parsing error: " << nMaxRecords <<
775                  " max possible entries, but " << nCount << " claimed, truncating");
776         nCount = nMaxRecords;
777     }
778 
779     for (sal_uInt16 i=0; i<nCount; ++i)
780     {
781         ScDdeLink* pLink = new ScDdeLink( this, rStream, aHdr );
782         pMgr->InsertDDELink(pLink, pLink->GetAppl(), pLink->GetTopic(), pLink->GetItem());
783     }
784 }
785 
SetInLinkUpdate(bool bSet)786 void ScDocument::SetInLinkUpdate(bool bSet)
787 {
788     //  called from TableLink and AreaLink
789 
790     OSL_ENSURE( bInLinkUpdate != bSet, "SetInLinkUpdate twice" );
791     bInLinkUpdate = bSet;
792 }
793 
IsInLinkUpdate() const794 bool ScDocument::IsInLinkUpdate() const
795 {
796     return bInLinkUpdate || IsInDdeLinkUpdate();
797 }
798 
UpdateExternalRefLinks(weld::Window * pWin)799 void ScDocument::UpdateExternalRefLinks(weld::Window* pWin)
800 {
801     if (!pExternalRefMgr)
802         return;
803 
804     sfx2::LinkManager* pMgr = GetDocLinkManager().getLinkManager(bAutoCalc);
805     if (!pMgr)
806         return;
807 
808     const ::sfx2::SvBaseLinks& rLinks = pMgr->GetLinks();
809     sal_uInt16 nCount = rLinks.size();
810 
811     bool bAny = false;
812 
813     // Collect all the external ref links first.
814     std::vector<ScExternalRefLink*> aRefLinks;
815     for (sal_uInt16 i = 0; i < nCount; ++i)
816     {
817         ::sfx2::SvBaseLink* pBase = rLinks[i].get();
818         ScExternalRefLink* pRefLink = dynamic_cast<ScExternalRefLink*>(pBase);
819         if (pRefLink)
820             aRefLinks.push_back(pRefLink);
821     }
822 
823     weld::WaitObject aWaitSwitch(pWin);
824 
825     pExternalRefMgr->enableDocTimer(false);
826     ScProgress aProgress(GetDocumentShell(), ScResId(SCSTR_UPDATE_EXTDOCS), aRefLinks.size(), true);
827     for (size_t i = 0, n = aRefLinks.size(); i < n; ++i)
828     {
829         aProgress.SetState(i+1);
830 
831         ScExternalRefLink* pRefLink = aRefLinks[i];
832         if (pRefLink->Update())
833         {
834             bAny = true;
835             continue;
836         }
837 
838         // Update failed.  Notify the user.
839 
840         OUString aFile;
841         sfx2::LinkManager::GetDisplayNames(pRefLink, nullptr, &aFile);
842         // Decode encoded URL for display friendliness.
843         INetURLObject aUrl(aFile,INetURLObject::EncodeMechanism::WasEncoded);
844         aFile = aUrl.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous);
845 
846         OUString sMessage = ScResId(SCSTR_EXTDOC_NOT_LOADED) +
847             "\n\n" +
848             aFile;
849         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pWin,
850                                                   VclMessageType::Warning, VclButtonsType::Ok,
851                                                   sMessage));
852         xBox->run();
853     }
854 
855     pExternalRefMgr->enableDocTimer(true);
856 
857     if (bAny)
858     {
859         TrackFormulas();
860         mpShell->Broadcast( SfxHint(SfxHintId::ScDataChanged) );
861 
862         // #i101960# set document modified, as in TrackTimeHdl for DDE links
863         if (!mpShell->IsModified())
864         {
865             mpShell->SetModified();
866             SfxBindings* pBindings = GetViewBindings();
867             if (pBindings)
868             {
869                 pBindings->Invalidate( SID_SAVEDOC );
870                 pBindings->Invalidate( SID_DOC_MODIFIED );
871             }
872         }
873     }
874 }
875 
CopyDdeLinks(ScDocument * pDestDoc) const876 void ScDocument::CopyDdeLinks( ScDocument* pDestDoc ) const
877 {
878     if (bIsClip)        // Create from Stream
879     {
880         if (pClipData)
881         {
882             pClipData->Seek(0);
883             pDestDoc->LoadDdeLinks(*pClipData);
884         }
885 
886         return;
887     }
888 
889     const sfx2::LinkManager* pMgr = GetDocLinkManager().getExistingLinkManager();
890     if (!pMgr)
891         return;
892 
893     sfx2::LinkManager* pDestMgr = pDestDoc->GetDocLinkManager().getLinkManager(pDestDoc->bAutoCalc);
894     if (!pDestMgr)
895         return;
896 
897     const sfx2::SvBaseLinks& rLinks = pMgr->GetLinks();
898     for (const auto & rLink : rLinks)
899     {
900         const sfx2::SvBaseLink* pBase = rLink.get();
901         if (const ScDdeLink* p = dynamic_cast<const ScDdeLink*>(pBase))
902         {
903             ScDdeLink* pNew = new ScDdeLink(pDestDoc, *p);
904             pDestMgr->InsertDDELink(
905                 pNew, pNew->GetAppl(), pNew->GetTopic(), pNew->GetItem());
906         }
907     }
908 }
909 
910 namespace {
911 
912 /** Tries to find the specified DDE link.
913     @param pnDdePos  (out-param) if not 0, the index of the DDE link is returned here
914                      (does not include other links from link manager).
915     @return  The DDE link, if it exists, otherwise 0. */
lclGetDdeLink(const sfx2::LinkManager * pLinkManager,const OUString & rAppl,const OUString & rTopic,const OUString & rItem,sal_uInt8 nMode,size_t * pnDdePos=nullptr)916 ScDdeLink* lclGetDdeLink(
917         const sfx2::LinkManager* pLinkManager,
918         const OUString& rAppl, const OUString& rTopic, const OUString& rItem, sal_uInt8 nMode,
919         size_t* pnDdePos = nullptr )
920 {
921     if( pLinkManager )
922     {
923         const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
924         size_t nCount = rLinks.size();
925         if( pnDdePos ) *pnDdePos = 0;
926         for( size_t nIndex = 0; nIndex < nCount; ++nIndex )
927         {
928             ::sfx2::SvBaseLink* pLink = rLinks[ nIndex ].get();
929             if( ScDdeLink* pDdeLink = dynamic_cast<ScDdeLink*>( pLink )  )
930             {
931                 if( (pDdeLink->GetAppl() == rAppl) &&
932                     (pDdeLink->GetTopic() == rTopic) &&
933                     (pDdeLink->GetItem() == rItem) &&
934                     ((nMode == SC_DDE_IGNOREMODE) || (nMode == pDdeLink->GetMode())) )
935                     return pDdeLink;
936                 if( pnDdePos ) ++*pnDdePos;
937             }
938         }
939     }
940     return nullptr;
941 }
942 
943 /** Returns a pointer to the specified DDE link.
944     @param nDdePos  Index of the DDE link (does not include other links from link manager).
945     @return  The DDE link, if it exists, otherwise 0. */
lclGetDdeLink(const sfx2::LinkManager * pLinkManager,size_t nDdePos)946 ScDdeLink* lclGetDdeLink( const sfx2::LinkManager* pLinkManager, size_t nDdePos )
947 {
948     if( pLinkManager )
949     {
950         const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
951         size_t nCount = rLinks.size();
952         size_t nDdeIndex = 0;       // counts only the DDE links
953         for( size_t nIndex = 0; nIndex < nCount; ++nIndex )
954         {
955             ::sfx2::SvBaseLink* pLink = rLinks[ nIndex ].get();
956             if( ScDdeLink* pDdeLink = dynamic_cast<ScDdeLink*>( pLink )  )
957             {
958                 if( nDdeIndex == nDdePos )
959                     return pDdeLink;
960                 ++nDdeIndex;
961             }
962         }
963     }
964     return nullptr;
965 }
966 
967 } // namespace
968 
FindDdeLink(const OUString & rAppl,const OUString & rTopic,const OUString & rItem,sal_uInt8 nMode,size_t & rnDdePos)969 bool ScDocument::FindDdeLink( const OUString& rAppl, const OUString& rTopic, const OUString& rItem,
970         sal_uInt8 nMode, size_t& rnDdePos )
971 {
972     return lclGetDdeLink( GetLinkManager(), rAppl, rTopic, rItem, nMode, &rnDdePos ) != nullptr;
973 }
974 
GetDdeLinkData(size_t nDdePos,OUString & rAppl,OUString & rTopic,OUString & rItem) const975 bool ScDocument::GetDdeLinkData( size_t nDdePos, OUString& rAppl, OUString& rTopic, OUString& rItem ) const
976 {
977     if( const ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos ) )
978     {
979         rAppl  = pDdeLink->GetAppl();
980         rTopic = pDdeLink->GetTopic();
981         rItem  = pDdeLink->GetItem();
982         return true;
983     }
984     return false;
985 }
986 
GetDdeLinkMode(size_t nDdePos,sal_uInt8 & rnMode) const987 bool ScDocument::GetDdeLinkMode( size_t nDdePos, sal_uInt8& rnMode ) const
988 {
989     if( const ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos ) )
990     {
991         rnMode = pDdeLink->GetMode();
992         return true;
993     }
994     return false;
995 }
996 
GetDdeLinkResultMatrix(size_t nDdePos) const997 const ScMatrix* ScDocument::GetDdeLinkResultMatrix( size_t nDdePos ) const
998 {
999     const ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos );
1000     return pDdeLink ? pDdeLink->GetResult() : nullptr;
1001 }
1002 
CreateDdeLink(const OUString & rAppl,const OUString & rTopic,const OUString & rItem,sal_uInt8 nMode,const ScMatrixRef & pResults)1003 bool ScDocument::CreateDdeLink( const OUString& rAppl, const OUString& rTopic, const OUString& rItem, sal_uInt8 nMode, const ScMatrixRef& pResults )
1004 {
1005     /*  Create a DDE link without updating it (i.e. for Excel import), to prevent
1006         unwanted connections. First try to find existing link. Set result array
1007         on existing and new links. */
1008     //TODO: store DDE links additionally at document (for efficiency)?
1009     OSL_ENSURE( nMode != SC_DDE_IGNOREMODE, "ScDocument::CreateDdeLink - SC_DDE_IGNOREMODE not allowed here" );
1010 
1011     sfx2::LinkManager* pMgr = GetDocLinkManager().getLinkManager(bAutoCalc);
1012     if (!pMgr)
1013         return false;
1014 
1015     if (nMode != SC_DDE_IGNOREMODE)
1016     {
1017         ScDdeLink* pDdeLink = lclGetDdeLink(pMgr, rAppl, rTopic, rItem, nMode);
1018         if( !pDdeLink )
1019         {
1020             // create a new DDE link, but without TryUpdate
1021             pDdeLink = new ScDdeLink( this, rAppl, rTopic, rItem, nMode );
1022             pMgr->InsertDDELink(pDdeLink, rAppl, rTopic, rItem);
1023         }
1024 
1025         // insert link results
1026         if( pResults )
1027             pDdeLink->SetResult( pResults );
1028 
1029         return true;
1030     }
1031     return false;
1032 }
1033 
SetDdeLinkResultMatrix(size_t nDdePos,const ScMatrixRef & pResults)1034 bool ScDocument::SetDdeLinkResultMatrix( size_t nDdePos, const ScMatrixRef& pResults )
1035 {
1036     if( ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos ) )
1037     {
1038         pDdeLink->SetResult( pResults );
1039         return true;
1040     }
1041     return false;
1042 }
1043 
HasAreaLinks() const1044 bool ScDocument::HasAreaLinks() const
1045 {
1046     const sfx2::LinkManager* pMgr = GetDocLinkManager().getExistingLinkManager();
1047     if (!pMgr)
1048         return false;
1049 
1050     const ::sfx2::SvBaseLinks& rLinks = pMgr->GetLinks();
1051     sal_uInt16 nCount = rLinks.size();
1052     for (sal_uInt16 i=0; i<nCount; i++)
1053         if (nullptr != dynamic_cast<const ScAreaLink* >(rLinks[i].get()))
1054             return true;
1055 
1056     return false;
1057 }
1058 
UpdateAreaLinks()1059 void ScDocument::UpdateAreaLinks()
1060 {
1061     sfx2::LinkManager* pMgr = GetDocLinkManager().getLinkManager(false);
1062     if (!pMgr)
1063         return;
1064 
1065     const ::sfx2::SvBaseLinks& rLinks = pMgr->GetLinks();
1066     for (const auto & rLink : rLinks)
1067     {
1068         ::sfx2::SvBaseLink* pBase = rLink.get();
1069         if (dynamic_cast<const ScAreaLink*>( pBase) !=  nullptr)
1070             pBase->Update();
1071     }
1072 }
1073 
DeleteAreaLinksOnTab(SCTAB nTab)1074 void ScDocument::DeleteAreaLinksOnTab( SCTAB nTab )
1075 {
1076     sfx2::LinkManager* pMgr = GetDocLinkManager().getLinkManager(false);
1077     if (!pMgr)
1078         return;
1079 
1080     const ::sfx2::SvBaseLinks& rLinks = pMgr->GetLinks();
1081     sfx2::SvBaseLinks::size_type nPos = 0;
1082     while ( nPos < rLinks.size() )
1083     {
1084         const ::sfx2::SvBaseLink* pBase = rLinks[nPos].get();
1085         const ScAreaLink* pLink = dynamic_cast<const ScAreaLink*>(pBase);
1086         if (pLink && pLink->GetDestArea().aStart.Tab() == nTab)
1087             pMgr->Remove(nPos);
1088         else
1089             ++nPos;
1090     }
1091 }
1092 
UpdateRefAreaLinks(UpdateRefMode eUpdateRefMode,const ScRange & rRange,SCCOL nDx,SCROW nDy,SCTAB nDz)1093 void ScDocument::UpdateRefAreaLinks( UpdateRefMode eUpdateRefMode,
1094                              const ScRange& rRange, SCCOL nDx, SCROW nDy, SCTAB nDz )
1095 {
1096     sfx2::LinkManager* pMgr = GetDocLinkManager().getLinkManager(false);
1097     if (!pMgr)
1098         return;
1099 
1100     bool bAnyUpdate = false;
1101 
1102     const ::sfx2::SvBaseLinks& rLinks = pMgr->GetLinks();
1103     sal_uInt16 nCount = rLinks.size();
1104     for (sal_uInt16 i=0; i<nCount; i++)
1105     {
1106         ::sfx2::SvBaseLink* pBase = rLinks[i].get();
1107         if (ScAreaLink* pLink = dynamic_cast<ScAreaLink*>(pBase))
1108         {
1109             ScRange aOutRange = pLink->GetDestArea();
1110 
1111             SCCOL nCol1 = aOutRange.aStart.Col();
1112             SCROW nRow1 = aOutRange.aStart.Row();
1113             SCTAB nTab1 = aOutRange.aStart.Tab();
1114             SCCOL nCol2 = aOutRange.aEnd.Col();
1115             SCROW nRow2 = aOutRange.aEnd.Row();
1116             SCTAB nTab2 = aOutRange.aEnd.Tab();
1117 
1118             ScRefUpdateRes eRes =
1119                 ScRefUpdate::Update( this, eUpdateRefMode,
1120                     rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
1121                     rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
1122                     nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
1123             if ( eRes != UR_NOTHING )
1124             {
1125                 pLink->SetDestArea( ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ) );
1126                 bAnyUpdate = true;
1127             }
1128         }
1129     }
1130 
1131     if ( bAnyUpdate )
1132     {
1133         // #i52120# Look for duplicates (after updating all positions).
1134         // If several links start at the same cell, the one with the lower index is removed
1135         // (file format specifies only one link definition for a cell).
1136 
1137         sal_uInt16 nFirstIndex = 0;
1138         while ( nFirstIndex < nCount )
1139         {
1140             bool bFound = false;
1141             ::sfx2::SvBaseLink* pFirst = rLinks[nFirstIndex].get();
1142             if (ScAreaLink* pFirstLink = dynamic_cast<ScAreaLink*>(pFirst))
1143             {
1144                 ScAddress aFirstPos = pFirstLink->GetDestArea().aStart;
1145                 for ( sal_uInt16 nSecondIndex = nFirstIndex + 1; nSecondIndex < nCount && !bFound; ++nSecondIndex )
1146                 {
1147                     ::sfx2::SvBaseLink* pSecond = rLinks[nSecondIndex].get();
1148                     ScAreaLink* pSecondLink = dynamic_cast<ScAreaLink*>(pSecond);
1149                     if (pSecondLink && pSecondLink->GetDestArea().aStart == aFirstPos)
1150                     {
1151                         // remove the first link, exit the inner loop, don't increment nFirstIndex
1152                         pMgr->Remove(pFirst);
1153                         nCount = rLinks.size();
1154                         bFound = true;
1155                     }
1156                 }
1157             }
1158             if (!bFound)
1159                 ++nFirstIndex;
1160         }
1161     }
1162 }
1163 
CheckLinkFormulaNeedingCheck(const ScTokenArray & rCode)1164 void ScDocument::CheckLinkFormulaNeedingCheck( const ScTokenArray& rCode )
1165 {
1166     if (HasLinkFormulaNeedingCheck())
1167         return;
1168 
1169     // Prefer RPN over tokenized formula if available.
1170     if (rCode.GetCodeLen())
1171     {
1172         if (rCode.HasOpCodeRPN(ocDde) || rCode.HasOpCodeRPN(ocWebservice))
1173             SetLinkFormulaNeedingCheck(true);
1174     }
1175     else if (rCode.GetLen())
1176     {
1177         if (rCode.HasOpCode(ocDde) || rCode.HasOpCode(ocWebservice))
1178             SetLinkFormulaNeedingCheck(true);
1179     }
1180     else
1181     {
1182         // Possible with named expression without expression like Excel
1183         // internal print ranges, obscure user define names, ... formula error
1184         // cells without formula ...
1185         SAL_WARN("sc.core","ScDocument::CheckLinkFormulaNeedingCheck - called with empty ScTokenArray");
1186     }
1187 }
1188 
1189 // TimerDelays etc.
KeyInput()1190 void ScDocument::KeyInput()
1191 {
1192     if ( pChartListenerCollection->hasListeners() )
1193         pChartListenerCollection->StartTimer();
1194     if (apTemporaryChartLock)
1195         apTemporaryChartLock->StartOrContinueLocking();
1196 }
1197 
GetViewBindings()1198 SfxBindings* ScDocument::GetViewBindings()
1199 {
1200     //  used to invalidate slots after changes to this document
1201 
1202     if ( !mpShell )
1203         return nullptr;        // no ObjShell -> no view
1204 
1205     //  first check current view
1206     SfxViewFrame* pViewFrame = SfxViewFrame::Current();
1207     if ( pViewFrame && pViewFrame->GetObjectShell() != mpShell )     // wrong document?
1208         pViewFrame = nullptr;
1209 
1210     //  otherwise use first view for this doc
1211     if ( !pViewFrame )
1212         pViewFrame = SfxViewFrame::GetFirst( mpShell );
1213 
1214     if (pViewFrame)
1215         return &pViewFrame->GetBindings();
1216     else
1217         return nullptr;
1218 }
1219 
TransliterateText(const ScMarkData & rMultiMark,TransliterationFlags nType)1220 void ScDocument::TransliterateText( const ScMarkData& rMultiMark, TransliterationFlags nType )
1221 {
1222     OSL_ENSURE( rMultiMark.IsMultiMarked(), "TransliterateText: no selection" );
1223 
1224     utl::TransliterationWrapper aTransliterationWrapper( comphelper::getProcessComponentContext(), nType );
1225     bool bConsiderLanguage = aTransliterationWrapper.needLanguageForTheMode();
1226     LanguageType nLanguage = LANGUAGE_SYSTEM;
1227 
1228     std::unique_ptr<ScEditEngineDefaulter> pEngine;        // not using mpEditEngine member because of defaults
1229 
1230     SCTAB nCount = GetTableCount();
1231     for (const SCTAB& nTab : rMultiMark)
1232     {
1233         if (nTab >= nCount)
1234             break;
1235 
1236         if ( maTabs[nTab] )
1237         {
1238             SCCOL nCol = 0;
1239             SCROW nRow = 0;
1240 
1241             bool bFound = rMultiMark.IsCellMarked( nCol, nRow );
1242             if (!bFound)
1243                 bFound = GetNextMarkedCell( nCol, nRow, nTab, rMultiMark );
1244 
1245             while (bFound)
1246             {
1247                 ScRefCellValue aCell(*this, ScAddress(nCol, nRow, nTab));
1248 
1249                 // fdo#32786 TITLE_CASE/SENTENCE_CASE need the extra handling in EditEngine (loop over words/sentences).
1250                 // Still use TransliterationWrapper directly for text cells with other transliteration types,
1251                 // for performance reasons.
1252                 if (aCell.meType == CELLTYPE_EDIT ||
1253                     (aCell.meType == CELLTYPE_STRING &&
1254                      ( nType == TransliterationFlags::SENTENCE_CASE || nType == TransliterationFlags::TITLE_CASE)))
1255                 {
1256                     if (!pEngine)
1257                         pEngine.reset(new ScFieldEditEngine(this, GetEnginePool(), GetEditPool()));
1258 
1259                     // defaults from cell attributes must be set so right language is used
1260                     const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab );
1261                     std::unique_ptr<SfxItemSet> pDefaults(new SfxItemSet( pEngine->GetEmptyItemSet() ));
1262                     if ( ScStyleSheet* pPreviewStyle = GetPreviewCellStyle( nCol, nRow, nTab ) )
1263                     {
1264                         std::unique_ptr<ScPatternAttr> pPreviewPattern(new ScPatternAttr( *pPattern ));
1265                         pPreviewPattern->SetStyleSheet(pPreviewStyle);
1266                         pPreviewPattern->FillEditItemSet( pDefaults.get() );
1267                     }
1268                     else
1269                     {
1270                         SfxItemSet* pFontSet = GetPreviewFont( nCol, nRow, nTab );
1271                         pPattern->FillEditItemSet( pDefaults.get(), pFontSet );
1272                     }
1273                     pEngine->SetDefaults( std::move(pDefaults) );
1274                     if (aCell.meType == CELLTYPE_STRING)
1275                         pEngine->SetText(aCell.mpString->getString());
1276                     else if (aCell.mpEditText)
1277                         pEngine->SetText(*aCell.mpEditText);
1278 
1279                     pEngine->ClearModifyFlag();
1280 
1281                     sal_Int32 nLastPar = pEngine->GetParagraphCount();
1282                     if (nLastPar)
1283                         --nLastPar;
1284                     sal_Int32 nTxtLen = pEngine->GetTextLen(nLastPar);
1285                     ESelection aSelAll( 0, 0, nLastPar, nTxtLen );
1286 
1287                     pEngine->TransliterateText( aSelAll, nType );
1288 
1289                     if ( pEngine->IsModified() )
1290                     {
1291                         ScEditAttrTester aTester( pEngine.get() );
1292                         if ( aTester.NeedsObject() )
1293                         {
1294                             // remove defaults (paragraph attributes) before creating text object
1295                             pEngine->SetDefaults( std::make_unique<SfxItemSet>( pEngine->GetEmptyItemSet() ) );
1296 
1297                             // The cell will take ownership of the text object instance.
1298                             SetEditText(ScAddress(nCol,nRow,nTab), pEngine->CreateTextObject());
1299                         }
1300                         else
1301                         {
1302                             ScSetStringParam aParam;
1303                             aParam.setTextInput();
1304                             SetString(ScAddress(nCol,nRow,nTab), pEngine->GetText(), &aParam);
1305                         }
1306                     }
1307                 }
1308 
1309                 else if (aCell.meType == CELLTYPE_STRING)
1310                 {
1311                     OUString aOldStr = aCell.mpString->getString();
1312                     sal_Int32 nOldLen = aOldStr.getLength();
1313 
1314                     if ( bConsiderLanguage )
1315                     {
1316                         SvtScriptType nScript = GetStringScriptType( aOldStr );        //TODO: cell script type?
1317                         sal_uInt16 nWhich = ( nScript == SvtScriptType::ASIAN ) ? ATTR_CJK_FONT_LANGUAGE :
1318                                         ( ( nScript == SvtScriptType::COMPLEX ) ? ATTR_CTL_FONT_LANGUAGE :
1319                                                                                 ATTR_FONT_LANGUAGE );
1320                         nLanguage = static_cast<const SvxLanguageItem*>(GetAttr( nCol, nRow, nTab, nWhich ))->GetValue();
1321                     }
1322 
1323                     uno::Sequence<sal_Int32> aOffsets;
1324                     OUString aNewStr = aTransliterationWrapper.transliterate( aOldStr, nLanguage, 0, nOldLen, &aOffsets );
1325 
1326                     if ( aNewStr != aOldStr )
1327                     {
1328                         ScSetStringParam aParam;
1329                         aParam.setTextInput();
1330                         SetString(ScAddress(nCol,nRow,nTab), aNewStr, &aParam);
1331                     }
1332                 }
1333                 bFound = GetNextMarkedCell( nCol, nRow, nTab, rMultiMark );
1334             }
1335         }
1336     }
1337 }
1338 
1339 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1340