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 <com/sun/star/script/vba/XVBAEventProcessor.hpp>
21 #include <com/sun/star/sheet/TableValidationVisibility.hpp>
22 #include <scitems.hxx>
23 #include <editeng/langitem.hxx>
24 #include <svl/srchitem.hxx>
25 #include <sfx2/linkmgr.hxx>
26 #include <sfx2/bindings.hxx>
27 #include <sfx2/objsh.hxx>
28 #include <sfx2/viewsh.hxx>
29 #include <vcl/svapp.hxx>
30 #include <osl/thread.hxx>
31 #include <osl/diagnose.h>
32 #include <document.hxx>
33 #include <attrib.hxx>
34 #include <table.hxx>
35 #include <rangenam.hxx>
36 #include <dbdata.hxx>
37 #include <docpool.hxx>
38 #include <poolhelp.hxx>
39 #include <rangelst.hxx>
40 #include <chartlock.hxx>
41 #include <refupdat.hxx>
42 #include <docoptio.hxx>
43 #include <scmod.hxx>
44 #include <clipoptions.hxx>
45 #include <viewopti.hxx>
46 #include <scextopt.hxx>
47 #include <tablink.hxx>
48 #include <externalrefmgr.hxx>
49 #include <markdata.hxx>
50 #include <validat.hxx>
51 #include <dociter.hxx>
52 #include <detdata.hxx>
53 #include <inputopt.hxx>
54 #include <chartlis.hxx>
55 #include <sc.hrc>
56 #include <hints.hxx>
57 #include <dpobject.hxx>
58 #include <drwlayer.hxx>
59 #include <unoreflist.hxx>
60 #include <listenercalls.hxx>
61 #include <tabprotection.hxx>
62 #include <formulaparserpool.hxx>
63 #include <clipparam.hxx>
64 #include <sheetevents.hxx>
65 #include <queryentry.hxx>
66 #include <formulacell.hxx>
67 #include <refupdatecontext.hxx>
68 #include <scopetools.hxx>
69 #include <filterentries.hxx>
70 #include <queryparam.hxx>
71 
72 #include <globalnames.hxx>
73 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
74 #include <comphelper/lok.hxx>
75 #include <config_fuzzers.h>
76 #include <memory>
77 
78 using namespace com::sun::star;
79 
80 namespace {
81 
sortAndRemoveDuplicates(std::vector<ScTypedStrData> & rStrings,bool bCaseSens)82 void sortAndRemoveDuplicates(std::vector<ScTypedStrData>& rStrings, bool bCaseSens)
83 {
84     if (bCaseSens)
85     {
86         std::sort(rStrings.begin(), rStrings.end(), ScTypedStrData::LessCaseSensitive());
87         std::vector<ScTypedStrData>::iterator it =
88             std::unique(rStrings.begin(), rStrings.end(), ScTypedStrData::EqualCaseSensitive());
89         rStrings.erase(it, rStrings.end());
90     }
91     else
92     {
93         std::sort(rStrings.begin(), rStrings.end(), ScTypedStrData::LessCaseInsensitive());
94         std::vector<ScTypedStrData>::iterator it =
95             std::unique(rStrings.begin(), rStrings.end(), ScTypedStrData::EqualCaseInsensitive());
96         rStrings.erase(it, rStrings.end());
97     }
98 }
99 
100 }
101 
GetAllTabRangeNames(ScRangeName::TabNameCopyMap & rNames) const102 void ScDocument::GetAllTabRangeNames(ScRangeName::TabNameCopyMap& rNames) const
103 {
104     ScRangeName::TabNameCopyMap aNames;
105     for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); ++i)
106     {
107         if (!maTabs[i])
108             // no more tables to iterate through.
109             break;
110 
111         const ScRangeName* p = maTabs[i]->mpRangeName.get();
112         if (!p || p->empty())
113             // ignore empty ones.
114             continue;
115 
116         aNames.emplace(i, p);
117     }
118     rNames.swap(aNames);
119 }
120 
SetAllRangeNames(const std::map<OUString,std::unique_ptr<ScRangeName>> & rRangeMap)121 void ScDocument::SetAllRangeNames(const std::map<OUString, std::unique_ptr<ScRangeName>>& rRangeMap)
122 {
123     for (const auto& [rName, rxRangeName] : rRangeMap)
124     {
125         if (rName == STR_GLOBAL_RANGE_NAME)
126         {
127             pRangeName.reset();
128             const ScRangeName *const pName = rxRangeName.get();
129             if (!pName->empty())
130                 pRangeName.reset( new ScRangeName( *pName ) );
131         }
132         else
133         {
134             const ScRangeName *const pName = rxRangeName.get();
135             SCTAB nTab;
136             bool bFound = GetTable(rName, nTab);
137             assert(bFound); (void)bFound;   // fouled up?
138             if (pName->empty())
139                 SetRangeName( nTab, nullptr );
140             else
141                 SetRangeName( nTab, std::unique_ptr<ScRangeName>(new ScRangeName( *pName )) );
142         }
143     }
144 }
145 
GetRangeNameMap(std::map<OUString,ScRangeName * > & aRangeNameMap)146 void ScDocument::GetRangeNameMap(std::map<OUString, ScRangeName*>& aRangeNameMap)
147 {
148     for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); ++i)
149     {
150         if (!maTabs[i])
151             continue;
152         ScRangeName* p = maTabs[i]->GetRangeName();
153         if (!p )
154         {
155             p = new ScRangeName();
156             SetRangeName(i, std::unique_ptr<ScRangeName>(p));
157         }
158         OUString aTableName = maTabs[i]->GetName();
159         aRangeNameMap.insert(std::pair<OUString, ScRangeName*>(aTableName,p));
160     }
161     if (!pRangeName)
162     {
163         pRangeName.reset(new ScRangeName());
164     }
165     aRangeNameMap.insert(std::pair<OUString, ScRangeName*>(STR_GLOBAL_RANGE_NAME, pRangeName.get()));
166 }
167 
GetRangeName(SCTAB nTab) const168 ScRangeName* ScDocument::GetRangeName(SCTAB nTab) const
169 {
170     if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
171         return nullptr;
172 
173     return maTabs[nTab]->GetRangeName();
174 }
175 
GetRangeName() const176 ScRangeName* ScDocument::GetRangeName() const
177 {
178     if (!pRangeName)
179         pRangeName.reset(new ScRangeName);
180     return pRangeName.get();
181 }
182 
SetRangeName(SCTAB nTab,std::unique_ptr<ScRangeName> pNew)183 void ScDocument::SetRangeName(SCTAB nTab, std::unique_ptr<ScRangeName> pNew)
184 {
185     if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
186         return;
187 
188     return maTabs[nTab]->SetRangeName(std::move(pNew));
189 }
190 
SetRangeName(std::unique_ptr<ScRangeName> pNewRangeName)191 void ScDocument::SetRangeName( std::unique_ptr<ScRangeName> pNewRangeName )
192 {
193     pRangeName = std::move(pNewRangeName);
194 }
195 
IsAddressInRangeName(RangeNameScope eScope,const ScAddress & rAddress)196 bool ScDocument::IsAddressInRangeName( RangeNameScope eScope, const ScAddress& rAddress )
197 {
198     ScRangeName* pRangeNames;
199     ScRange aNameRange;
200 
201     if (eScope == RangeNameScope::GLOBAL)
202         pRangeNames= GetRangeName();
203     else
204         pRangeNames= GetRangeName(rAddress.Tab());
205 
206     for (const auto& rEntry : *pRangeNames)
207     {
208         if (rEntry.second->IsValidReference(aNameRange))
209         {
210             if (aNameRange.In(rAddress))
211                 return true;
212         }
213     }
214 
215     return false;
216 }
217 
InsertNewRangeName(const OUString & rName,const ScAddress & rPos,const OUString & rExpr)218 bool ScDocument::InsertNewRangeName( const OUString& rName, const ScAddress& rPos, const OUString& rExpr )
219 {
220     ScRangeName* pGlobalNames = GetRangeName();
221     if (!pGlobalNames)
222         return false;
223 
224     ScRangeData* pName = new ScRangeData(*this, rName, rExpr, rPos, ScRangeData::Type::Name, GetGrammar());
225     return pGlobalNames->insert(pName);
226 }
227 
InsertNewRangeName(SCTAB nTab,const OUString & rName,const ScAddress & rPos,const OUString & rExpr)228 bool ScDocument::InsertNewRangeName( SCTAB nTab, const OUString& rName, const ScAddress& rPos, const OUString& rExpr )
229 {
230     ScRangeName* pLocalNames = GetRangeName(nTab);
231     if (!pLocalNames)
232         return false;
233 
234     ScRangeData* pName = new ScRangeData(*this, rName, rExpr, rPos, ScRangeData::Type::Name, GetGrammar());
235     return pLocalNames->insert(pName);
236 }
237 
GetRangeAtBlock(const ScRange & rBlock,OUString & rName,bool * pSheetLocal) const238 const ScRangeData* ScDocument::GetRangeAtBlock( const ScRange& rBlock, OUString& rName, bool* pSheetLocal ) const
239 {
240     const ScRangeData* pData = nullptr;
241     if (rBlock.aStart.Tab() == rBlock.aEnd.Tab())
242     {
243         const ScRangeName* pLocalNames = GetRangeName(rBlock.aStart.Tab());
244         if (pLocalNames)
245         {
246             pData = pLocalNames->findByRange( rBlock );
247             if (pData)
248             {
249                 rName = pData->GetName();
250                 if (pSheetLocal)
251                     *pSheetLocal = true;
252                 return pData;
253             }
254         }
255     }
256     if ( pRangeName )
257     {
258         pData = pRangeName->findByRange( rBlock );
259         if (pData)
260         {
261             rName = pData->GetName();
262             if (pSheetLocal)
263                 *pSheetLocal = false;
264         }
265     }
266     return pData;
267 }
268 
FindRangeNameBySheetAndIndex(SCTAB nTab,sal_uInt16 nIndex) const269 ScRangeData* ScDocument::FindRangeNameBySheetAndIndex( SCTAB nTab, sal_uInt16 nIndex ) const
270 {
271     const ScRangeName* pRN = (nTab < 0 ? GetRangeName() : GetRangeName(nTab));
272     return (pRN ? pRN->findByIndex( nIndex) : nullptr);
273 }
274 
SetDBCollection(std::unique_ptr<ScDBCollection> pNewDBCollection,bool bRemoveAutoFilter)275 void ScDocument::SetDBCollection( std::unique_ptr<ScDBCollection> pNewDBCollection, bool bRemoveAutoFilter )
276 {
277     if (pDBCollection && bRemoveAutoFilter)
278     {
279         //  remove auto filter attribute if new db data don't contain auto filter flag
280         //  start position is also compared, so bRemoveAutoFilter must not be set from ref-undo!
281 
282         ScDBCollection::NamedDBs& rNamedDBs = pDBCollection->getNamedDBs();
283         for (const auto& rxNamedDB : rNamedDBs)
284         {
285             const ScDBData& rOldData = *rxNamedDB;
286             if (!rOldData.HasAutoFilter())
287                 continue;
288 
289             ScRange aOldRange;
290             rOldData.GetArea(aOldRange);
291 
292             bool bFound = false;
293             if (pNewDBCollection)
294             {
295                 ScDBData* pNewData = pNewDBCollection->getNamedDBs().findByUpperName(rOldData.GetUpperName());
296                 if (pNewData)
297                 {
298                     if (pNewData->HasAutoFilter())
299                     {
300                         ScRange aNewRange;
301                         pNewData->GetArea(aNewRange);
302                         if (aOldRange.aStart == aNewRange.aStart)
303                             bFound = true;
304                     }
305                 }
306             }
307 
308             if (!bFound)
309             {
310                 aOldRange.aEnd.SetRow(aOldRange.aStart.Row());
311                 RemoveFlagsTab( aOldRange.aStart.Col(), aOldRange.aStart.Row(),
312                                 aOldRange.aEnd.Col(),   aOldRange.aEnd.Row(),
313                                 aOldRange.aStart.Tab(), ScMF::Auto );
314                 RepaintRange( aOldRange );
315             }
316         }
317     }
318 
319     pDBCollection = std::move(pNewDBCollection);
320 }
321 
GetDBAtCursor(SCCOL nCol,SCROW nRow,SCTAB nTab,ScDBDataPortion ePortion) const322 const ScDBData* ScDocument::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
323 {
324     if (pDBCollection)
325         return pDBCollection->GetDBAtCursor(nCol, nRow, nTab, ePortion);
326     else
327         return nullptr;
328 }
329 
GetDBAtCursor(SCCOL nCol,SCROW nRow,SCTAB nTab,ScDBDataPortion ePortion)330 ScDBData* ScDocument::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion)
331 {
332     if (pDBCollection)
333         return pDBCollection->GetDBAtCursor(nCol, nRow, nTab, ePortion);
334     else
335         return nullptr;
336 }
337 
GetDBAtArea(SCTAB nTab,SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2) const338 const ScDBData* ScDocument::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
339 {
340     if (pDBCollection)
341         return pDBCollection->GetDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2);
342     else
343         return nullptr;
344 }
345 
GetDBAtArea(SCTAB nTab,SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2)346 ScDBData* ScDocument::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
347 {
348     if (pDBCollection)
349         return pDBCollection->GetDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2);
350     else
351         return nullptr;
352 }
353 
RefreshDirtyTableColumnNames()354 void ScDocument::RefreshDirtyTableColumnNames()
355 {
356     if (pDBCollection)
357         pDBCollection->RefreshDirtyTableColumnNames();
358 }
359 
HasPivotTable() const360 bool ScDocument::HasPivotTable() const
361 {
362     return pDPCollection && pDPCollection->GetCount();
363 }
364 
GetDPCollection()365 ScDPCollection* ScDocument::GetDPCollection()
366 {
367     if (!pDPCollection)
368         pDPCollection.reset( new ScDPCollection(*this) );
369     return pDPCollection.get();
370 }
371 
GetDPCollection() const372 const ScDPCollection* ScDocument::GetDPCollection() const
373 {
374     return pDPCollection.get();
375 }
376 
GetDPAtCursor(SCCOL nCol,SCROW nRow,SCTAB nTab) const377 ScDPObject* ScDocument::GetDPAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab) const
378 {
379     if (!pDPCollection)
380         return nullptr;
381 
382     sal_uInt16 nCount = pDPCollection->GetCount();
383     ScAddress aPos( nCol, nRow, nTab );
384     for (sal_uInt16 i=0; i<nCount; i++)
385         if ( (*pDPCollection)[i].GetOutRange().In( aPos ) )
386             return &(*pDPCollection)[i];
387 
388     return nullptr;
389 }
390 
GetDPAtBlock(const ScRange & rBlock) const391 ScDPObject* ScDocument::GetDPAtBlock( const ScRange & rBlock ) const
392 {
393     if (!pDPCollection)
394         return nullptr;
395 
396     /* Walk the collection in reverse order to get something of an
397      * approximation of MS Excels 'most recent' effect. */
398     sal_uInt16 i = pDPCollection->GetCount();
399     while ( i-- > 0 )
400         if ( (*pDPCollection)[i].GetOutRange().In( rBlock ) )
401             return &(*pDPCollection)[i];
402 
403     return nullptr;
404 }
405 
StopTemporaryChartLock()406 void ScDocument::StopTemporaryChartLock()
407 {
408     if (apTemporaryChartLock)
409         apTemporaryChartLock->StopLocking();
410 }
411 
SetChartListenerCollection(std::unique_ptr<ScChartListenerCollection> pNewChartListenerCollection,bool bSetChartRangeLists)412 void ScDocument::SetChartListenerCollection(
413             std::unique_ptr<ScChartListenerCollection> pNewChartListenerCollection,
414             bool bSetChartRangeLists )
415 {
416     std::unique_ptr<ScChartListenerCollection> pOld = std::move(pChartListenerCollection);
417     pChartListenerCollection = std::move(pNewChartListenerCollection);
418     if ( pChartListenerCollection )
419     {
420         if ( pOld )
421             pChartListenerCollection->SetDiffDirty( *pOld, bSetChartRangeLists );
422         pChartListenerCollection->StartAllListeners();
423     }
424 }
425 
SetScenario(SCTAB nTab,bool bFlag)426 void ScDocument::SetScenario( SCTAB nTab, bool bFlag )
427 {
428     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
429         maTabs[nTab]->SetScenario(bFlag);
430 }
431 
IsScenario(SCTAB nTab) const432 bool ScDocument::IsScenario( SCTAB nTab ) const
433 {
434     return ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] &&maTabs[nTab]->IsScenario();
435 }
436 
SetScenarioData(SCTAB nTab,const OUString & rComment,const Color & rColor,ScScenarioFlags nFlags)437 void ScDocument::SetScenarioData( SCTAB nTab, const OUString& rComment,
438                                         const Color& rColor, ScScenarioFlags nFlags )
439 {
440     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsScenario())
441     {
442         maTabs[nTab]->SetScenarioComment( rComment );
443         maTabs[nTab]->SetScenarioColor( rColor );
444         maTabs[nTab]->SetScenarioFlags( nFlags );
445     }
446 }
447 
GetTabBgColor(SCTAB nTab) const448 Color ScDocument::GetTabBgColor( SCTAB nTab ) const
449 {
450     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
451         return maTabs[nTab]->GetTabBgColor();
452     return COL_AUTO;
453 }
454 
SetTabBgColor(SCTAB nTab,const Color & rColor)455 void ScDocument::SetTabBgColor( SCTAB nTab, const Color& rColor )
456 {
457     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
458         maTabs[nTab]->SetTabBgColor(rColor);
459 }
460 
IsDefaultTabBgColor(SCTAB nTab) const461 bool ScDocument::IsDefaultTabBgColor( SCTAB nTab ) const
462 {
463     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
464         return maTabs[nTab]->GetTabBgColor() == COL_AUTO;
465     return true;
466 }
467 
GetScenarioData(SCTAB nTab,OUString & rComment,Color & rColor,ScScenarioFlags & rFlags) const468 void ScDocument::GetScenarioData( SCTAB nTab, OUString& rComment,
469                                         Color& rColor, ScScenarioFlags& rFlags ) const
470 {
471     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsScenario())
472     {
473         maTabs[nTab]->GetScenarioComment( rComment );
474         rColor = maTabs[nTab]->GetScenarioColor();
475         rFlags = maTabs[nTab]->GetScenarioFlags();
476     }
477 }
478 
GetScenarioFlags(SCTAB nTab,ScScenarioFlags & rFlags) const479 void ScDocument::GetScenarioFlags( SCTAB nTab, ScScenarioFlags& rFlags ) const
480 {
481     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsScenario())
482         rFlags = maTabs[nTab]->GetScenarioFlags();
483 }
484 
IsLinked(SCTAB nTab) const485 bool ScDocument::IsLinked( SCTAB nTab ) const
486 {
487     return ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsLinked();
488     // equivalent to
489     //if (ValidTab(nTab) && pTab[nTab])
490     //  return pTab[nTab]->IsLinked();
491     //return false;
492 }
493 
GetAddressConvention() const494 formula::FormulaGrammar::AddressConvention ScDocument::GetAddressConvention() const
495 {
496     return formula::FormulaGrammar::extractRefConvention(eGrammar);
497 }
498 
SetGrammar(formula::FormulaGrammar::Grammar eGram)499 void ScDocument::SetGrammar( formula::FormulaGrammar::Grammar eGram )
500 {
501     eGrammar = eGram;
502 }
503 
GetLinkMode(SCTAB nTab) const504 ScLinkMode ScDocument::GetLinkMode( SCTAB nTab ) const
505 {
506     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
507         return maTabs[nTab]->GetLinkMode();
508     return ScLinkMode::NONE;
509 }
510 
GetLinkDoc(SCTAB nTab) const511 OUString ScDocument::GetLinkDoc( SCTAB nTab ) const
512 {
513     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
514         return maTabs[nTab]->GetLinkDoc();
515     return OUString();
516 }
517 
GetLinkFlt(SCTAB nTab) const518 OUString ScDocument::GetLinkFlt( SCTAB nTab ) const
519 {
520     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
521         return maTabs[nTab]->GetLinkFlt();
522     return OUString();
523 }
524 
GetLinkOpt(SCTAB nTab) const525 OUString ScDocument::GetLinkOpt( SCTAB nTab ) const
526 {
527     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
528         return maTabs[nTab]->GetLinkOpt();
529     return OUString();
530 }
531 
GetLinkTab(SCTAB nTab) const532 OUString ScDocument::GetLinkTab( SCTAB nTab ) const
533 {
534     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
535         return maTabs[nTab]->GetLinkTab();
536     return OUString();
537 }
538 
GetLinkRefreshDelay(SCTAB nTab) const539 sal_uLong ScDocument::GetLinkRefreshDelay( SCTAB nTab ) const
540 {
541     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
542         return maTabs[nTab]->GetLinkRefreshDelay();
543     return 0;
544 }
545 
SetLink(SCTAB nTab,ScLinkMode nMode,const OUString & rDoc,const OUString & rFilter,const OUString & rOptions,const OUString & rTabName,sal_uLong nRefreshDelay)546 void ScDocument::SetLink( SCTAB nTab, ScLinkMode nMode, const OUString& rDoc,
547                             const OUString& rFilter, const OUString& rOptions,
548                             const OUString& rTabName, sal_uLong nRefreshDelay )
549 {
550     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
551         maTabs[nTab]->SetLink( nMode, rDoc, rFilter, rOptions, rTabName, nRefreshDelay );
552 }
553 
HasLink(std::u16string_view rDoc,std::u16string_view rFilter,std::u16string_view rOptions) const554 bool ScDocument::HasLink( std::u16string_view rDoc,
555                             std::u16string_view rFilter, std::u16string_view rOptions ) const
556 {
557     SCTAB nCount = static_cast<SCTAB>(maTabs.size());
558     for (SCTAB i=0; i<nCount; i++)
559         if (maTabs[i]->IsLinked()
560                 && maTabs[i]->GetLinkDoc() == rDoc
561                 && maTabs[i]->GetLinkFlt() == rFilter
562                 && maTabs[i]->GetLinkOpt() == rOptions)
563             return true;
564 
565     return false;
566 }
567 
LinkExternalTab(SCTAB & rTab,const OUString & aDocTab,const OUString & aFileName,const OUString & aTabName)568 bool ScDocument::LinkExternalTab( SCTAB& rTab, const OUString& aDocTab,
569         const OUString& aFileName, const OUString& aTabName )
570 {
571     if ( IsClipboard() )
572     {
573         OSL_FAIL( "LinkExternalTab in Clipboard" );
574         return false;
575     }
576     rTab = 0;
577 #if ENABLE_FUZZERS
578     return false;
579 #endif
580     OUString  aFilterName; // Is filled by the Loader
581     OUString  aOptions; // Filter options
582     sal_uInt32 nLinkCnt = pExtDocOptions ? pExtDocOptions->GetDocSettings().mnLinkCnt : 0;
583     ScDocumentLoader aLoader( aFileName, aFilterName, aOptions, nLinkCnt + 1 );
584     if ( aLoader.IsError() )
585         return false;
586     ScDocument* pSrcDoc = aLoader.GetDocument();
587 
588     // Copy table
589     SCTAB nSrcTab;
590     if ( pSrcDoc->GetTable( aTabName, nSrcTab ) )
591     {
592         if ( !InsertTab( SC_TAB_APPEND, aDocTab, true ) )
593         {
594             OSL_FAIL("can't insert external document table");
595             return false;
596         }
597         rTab = GetTableCount() - 1;
598         // Don't insert anew, just the results
599         TransferTab( *pSrcDoc, nSrcTab, rTab, false, true );
600     }
601     else
602         return false;
603 
604     sal_uLong nRefreshDelay = 0;
605 
606     bool bWasThere = HasLink( aFileName, aFilterName, aOptions );
607     SetLink( rTab, ScLinkMode::VALUE, aFileName, aFilterName, aOptions, aTabName, nRefreshDelay );
608     if ( !bWasThere ) // Add link only once per source document
609     {
610         ScTableLink* pLink = new ScTableLink( mpShell, aFileName, aFilterName, aOptions, nRefreshDelay );
611         pLink->SetInCreate( true );
612         OUString aFilName = aFilterName;
613         GetLinkManager()->InsertFileLink( *pLink, sfx2::SvBaseLinkObjectType::ClientFile, aFileName, &aFilName );
614         pLink->Update();
615         pLink->SetInCreate( false );
616         SfxBindings* pBindings = GetViewBindings();
617         if (pBindings)
618             pBindings->Invalidate( SID_LINKS );
619     }
620     return true;
621 }
622 
GetExternalRefManager() const623 ScExternalRefManager* ScDocument::GetExternalRefManager() const
624 {
625     ScDocument* pThis = const_cast<ScDocument*>(this);
626     if (!pExternalRefMgr)
627         pThis->pExternalRefMgr.reset( new ScExternalRefManager(*pThis));
628 
629     return pExternalRefMgr.get();
630 }
631 
IsInExternalReferenceMarking() const632 bool ScDocument::IsInExternalReferenceMarking() const
633 {
634     return pExternalRefMgr && pExternalRefMgr->isInReferenceMarking();
635 }
636 
MarkUsedExternalReferences()637 void ScDocument::MarkUsedExternalReferences()
638 {
639     if (!pExternalRefMgr)
640         return;
641     if (!pExternalRefMgr->hasExternalData())
642         return;
643     // Charts.
644     pExternalRefMgr->markUsedByLinkListeners();
645     // Formula cells.
646     pExternalRefMgr->markUsedExternalRefCells();
647 
648     /* NOTE: Conditional formats and validation objects are marked when
649      * collecting them during export. */
650 }
651 
GetFormulaParserPool() const652 ScFormulaParserPool& ScDocument::GetFormulaParserPool() const
653 {
654     if (!mxFormulaParserPool)
655         mxFormulaParserPool.reset( new ScFormulaParserPool( *this ) );
656     return *mxFormulaParserPool;
657 }
658 
GetSheetEvents(SCTAB nTab) const659 const ScSheetEvents* ScDocument::GetSheetEvents( SCTAB nTab ) const
660 {
661     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
662         return maTabs[nTab]->GetSheetEvents();
663     return nullptr;
664 }
665 
SetSheetEvents(SCTAB nTab,std::unique_ptr<ScSheetEvents> pNew)666 void ScDocument::SetSheetEvents( SCTAB nTab, std::unique_ptr<ScSheetEvents> pNew )
667 {
668     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
669         maTabs[nTab]->SetSheetEvents( std::move(pNew) );
670 }
671 
HasSheetEventScript(SCTAB nTab,ScSheetEventId nEvent,bool bWithVbaEvents) const672 bool ScDocument::HasSheetEventScript( SCTAB nTab, ScSheetEventId nEvent, bool bWithVbaEvents ) const
673 {
674     if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
675     {
676         // check if any event handler script has been configured
677         const ScSheetEvents* pEvents = maTabs[nTab]->GetSheetEvents();
678         if ( pEvents && pEvents->GetScript( nEvent ) )
679             return true;
680         // check if VBA event handlers exist
681         if (bWithVbaEvents && mxVbaEvents.is()) try
682         {
683             uno::Sequence< uno::Any > aArgs( 1 );
684             aArgs[ 0 ] <<= nTab;
685             if (mxVbaEvents->hasVbaEventHandler( ScSheetEvents::GetVbaSheetEventId( nEvent ), aArgs ) ||
686                 mxVbaEvents->hasVbaEventHandler( ScSheetEvents::GetVbaDocumentEventId( nEvent ), uno::Sequence< uno::Any >() ))
687                 return true;
688         }
689         catch( uno::Exception& )
690         {
691         }
692     }
693     return false;
694 }
695 
HasAnySheetEventScript(ScSheetEventId nEvent,bool bWithVbaEvents) const696 bool ScDocument::HasAnySheetEventScript( ScSheetEventId nEvent, bool bWithVbaEvents ) const
697 {
698     SCTAB nSize = static_cast<SCTAB>(maTabs.size());
699     for (SCTAB nTab = 0; nTab < nSize; nTab++)
700         if (HasSheetEventScript( nTab, nEvent, bWithVbaEvents ))
701             return true;
702     return false;
703 }
704 
HasAnyCalcNotification() const705 bool ScDocument::HasAnyCalcNotification() const
706 {
707     SCTAB nSize = static_cast<SCTAB>(maTabs.size());
708     for (SCTAB nTab = 0; nTab < nSize; nTab++)
709         if (maTabs[nTab] && maTabs[nTab]->GetCalcNotification())
710             return true;
711     return false;
712 }
713 
HasCalcNotification(SCTAB nTab) const714 bool ScDocument::HasCalcNotification( SCTAB nTab ) const
715 {
716     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
717         return maTabs[nTab]->GetCalcNotification();
718     return false;
719 }
720 
SetCalcNotification(SCTAB nTab)721 void ScDocument::SetCalcNotification( SCTAB nTab )
722 {
723     // set only if not set before
724     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && !maTabs[nTab]->GetCalcNotification())
725         maTabs[nTab]->SetCalcNotification(true);
726 }
727 
ResetCalcNotifications()728 void ScDocument::ResetCalcNotifications()
729 {
730     SCTAB nSize = static_cast<SCTAB>(maTabs.size());
731     for (SCTAB nTab = 0; nTab < nSize; nTab++)
732         if (maTabs[nTab] && maTabs[nTab]->GetCalcNotification())
733             maTabs[nTab]->SetCalcNotification(false);
734 }
735 
GetOutlineTable(SCTAB nTab,bool bCreate)736 ScOutlineTable* ScDocument::GetOutlineTable( SCTAB nTab, bool bCreate )
737 {
738     ScOutlineTable* pVal = nullptr;
739 
740     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
741         if (maTabs[nTab])
742         {
743             pVal = maTabs[nTab]->GetOutlineTable();
744             if (!pVal && bCreate)
745             {
746                 maTabs[nTab]->StartOutlineTable();
747                 pVal = maTabs[nTab]->GetOutlineTable();
748             }
749         }
750 
751     return pVal;
752 }
753 
SetOutlineTable(SCTAB nTab,const ScOutlineTable * pNewOutline)754 bool ScDocument::SetOutlineTable( SCTAB nTab, const ScOutlineTable* pNewOutline )
755 {
756     return ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->SetOutlineTable(pNewOutline);
757 }
758 
DoAutoOutline(SCCOL nStartCol,SCROW nStartRow,SCCOL nEndCol,SCROW nEndRow,SCTAB nTab)759 void ScDocument::DoAutoOutline( SCCOL nStartCol, SCROW nStartRow,
760                                 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
761 {
762     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
763         maTabs[nTab]->DoAutoOutline( nStartCol, nStartRow, nEndCol, nEndRow );
764 }
765 
TestRemoveSubTotals(SCTAB nTab,const ScSubTotalParam & rParam)766 bool ScDocument::TestRemoveSubTotals( SCTAB nTab, const ScSubTotalParam& rParam )
767 {
768     return ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->TestRemoveSubTotals( rParam );
769 }
770 
RemoveSubTotals(SCTAB nTab,ScSubTotalParam & rParam)771 void ScDocument::RemoveSubTotals( SCTAB nTab, ScSubTotalParam& rParam )
772 {
773     if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
774         maTabs[nTab]->RemoveSubTotals( rParam );
775 }
776 
DoSubTotals(SCTAB nTab,ScSubTotalParam & rParam)777 bool ScDocument::DoSubTotals( SCTAB nTab, ScSubTotalParam& rParam )
778 {
779     return ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->DoSubTotals( rParam );
780 }
781 
HasSubTotalCells(const ScRange & rRange)782 bool ScDocument::HasSubTotalCells( const ScRange& rRange )
783 {
784     ScCellIterator aIter(*this, rRange);
785     for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
786     {
787         if (aIter.getType() != CELLTYPE_FORMULA)
788             continue;
789 
790         if (aIter.getFormulaCell()->IsSubTotal())
791             return true;
792     }
793     return false;   // none found
794 }
795 
796 /**
797  * From this document this method copies the cells of positions at which
798  * there are also cells in pPosDoc to pDestDoc
799  */
CopyUpdated(ScDocument * pPosDoc,ScDocument * pDestDoc)800 void ScDocument::CopyUpdated( ScDocument* pPosDoc, ScDocument* pDestDoc )
801 {
802     SCTAB nCount = static_cast<SCTAB>(maTabs.size());
803     for (SCTAB nTab=0; nTab<nCount; nTab++)
804         if (maTabs[nTab] && pPosDoc->maTabs[nTab] && pDestDoc->maTabs[nTab])
805             maTabs[nTab]->CopyUpdated( pPosDoc->maTabs[nTab].get(), pDestDoc->maTabs[nTab].get() );
806 }
807 
CopyScenario(SCTAB nSrcTab,SCTAB nDestTab,bool bNewScenario)808 void ScDocument::CopyScenario( SCTAB nSrcTab, SCTAB nDestTab, bool bNewScenario )
809 {
810     if (!(ValidTab(nSrcTab) && ValidTab(nDestTab) && nSrcTab < static_cast<SCTAB>(maTabs.size())
811                 && nDestTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nSrcTab] && maTabs[nDestTab]))
812         return;
813 
814     // Set flags correctly for active scenarios
815     // and write current values back to recently active scenarios
816     ScRangeList aRanges = *maTabs[nSrcTab]->GetScenarioRanges();
817 
818     // nDestTab is the target table
819     for ( SCTAB nTab = nDestTab+1;
820             nTab< static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsScenario();
821             nTab++ )
822     {
823         if ( maTabs[nTab]->IsActiveScenario() ) // Even if it's the same scenario
824         {
825             bool bTouched = false;
826             for ( size_t nR=0, nRangeCount = aRanges.size(); nR < nRangeCount && !bTouched; nR++ )
827             {
828                 const ScRange& rRange = aRanges[ nR ];
829                 if ( maTabs[nTab]->HasScenarioRange( rRange ) )
830                     bTouched = true;
831             }
832             if (bTouched)
833             {
834                 maTabs[nTab]->SetActiveScenario(false);
835                 if ( maTabs[nTab]->GetScenarioFlags() & ScScenarioFlags::TwoWay )
836                     maTabs[nTab]->CopyScenarioFrom( maTabs[nDestTab].get() );
837             }
838         }
839     }
840 
841     maTabs[nSrcTab]->SetActiveScenario(true); // This is where it's from ...
842     if (!bNewScenario) // Copy data from the selected scenario
843     {
844         sc::AutoCalcSwitch aACSwitch(*this, false);
845         maTabs[nSrcTab]->CopyScenarioTo( maTabs[nDestTab].get() );
846 
847         sc::SetFormulaDirtyContext aCxt;
848         SetAllFormulasDirty(aCxt);
849     }
850 }
851 
MarkScenario(SCTAB nSrcTab,SCTAB nDestTab,ScMarkData & rDestMark,bool bResetMark,ScScenarioFlags nNeededBits) const852 void ScDocument::MarkScenario( SCTAB nSrcTab, SCTAB nDestTab, ScMarkData& rDestMark,
853                                 bool bResetMark, ScScenarioFlags nNeededBits ) const
854 {
855     if (bResetMark)
856         rDestMark.ResetMark();
857 
858     if (ValidTab(nSrcTab) && nSrcTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nSrcTab])
859         maTabs[nSrcTab]->MarkScenarioIn( rDestMark, nNeededBits );
860 
861     rDestMark.SetAreaTab( nDestTab );
862 }
863 
HasScenarioRange(SCTAB nTab,const ScRange & rRange) const864 bool ScDocument::HasScenarioRange( SCTAB nTab, const ScRange& rRange ) const
865 {
866     return ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->HasScenarioRange( rRange );
867 }
868 
GetScenarioRanges(SCTAB nTab) const869 const ScRangeList* ScDocument::GetScenarioRanges( SCTAB nTab ) const
870 {
871     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
872         return maTabs[nTab]->GetScenarioRanges();
873 
874     return nullptr;
875 }
876 
IsActiveScenario(SCTAB nTab) const877 bool ScDocument::IsActiveScenario( SCTAB nTab ) const
878 {
879     return ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsActiveScenario(  );
880 }
881 
SetActiveScenario(SCTAB nTab,bool bActive)882 void ScDocument::SetActiveScenario( SCTAB nTab, bool bActive )
883 {
884     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
885         maTabs[nTab]->SetActiveScenario( bActive );
886 }
887 
TestCopyScenario(SCTAB nSrcTab,SCTAB nDestTab) const888 bool ScDocument::TestCopyScenario( SCTAB nSrcTab, SCTAB nDestTab ) const
889 {
890     if (ValidTab(nSrcTab) && nSrcTab < static_cast<SCTAB>(maTabs.size())
891                 && nDestTab < static_cast<SCTAB>(maTabs.size())&& ValidTab(nDestTab))
892         return maTabs[nSrcTab]->TestCopyScenarioTo( maTabs[nDestTab].get() );
893 
894     OSL_FAIL("wrong table at TestCopyScenario");
895     return false;
896 }
897 
AddUnoObject(SfxListener & rObject)898 void ScDocument::AddUnoObject( SfxListener& rObject )
899 {
900     if (!pUnoBroadcaster)
901         pUnoBroadcaster.reset( new SfxBroadcaster );
902 
903     rObject.StartListening( *pUnoBroadcaster );
904 }
905 
RemoveUnoObject(SfxListener & rObject)906 void ScDocument::RemoveUnoObject( SfxListener& rObject )
907 {
908     if (pUnoBroadcaster)
909     {
910         rObject.EndListening( *pUnoBroadcaster );
911 
912         if ( bInUnoBroadcast )
913         {
914             // Broadcasts from ScDocument::BroadcastUno are the only way that
915             // uno object methods are called without holding a reference.
916             //
917             // If RemoveUnoObject is called from an object dtor in the finalizer thread
918             // while the main thread is calling BroadcastUno, the dtor thread must wait
919             // (or the object's Notify might try to access a deleted object).
920             // The SolarMutex can't be locked here because if a component is called from
921             // a VCL event, the main thread has the SolarMutex locked all the time.
922             //
923             // This check is done after calling EndListening, so a later BroadcastUno call
924             // won't touch this object.
925 
926             vcl::SolarMutexTryAndBuyGuard g;
927             if (g.isAcquired())
928             {
929                 // BroadcastUno is always called with the SolarMutex locked, so if it
930                 // can be acquired, this is within the same thread (should not happen)
931                 OSL_FAIL( "RemoveUnoObject called from BroadcastUno" );
932             }
933             else
934             {
935                 // Let the thread that called BroadcastUno continue
936                 while ( bInUnoBroadcast )
937                 {
938                     osl::Thread::yield();
939                 }
940             }
941         }
942     }
943     else
944     {
945         OSL_FAIL("No Uno broadcaster");
946     }
947 }
948 
BroadcastUno(const SfxHint & rHint)949 void ScDocument::BroadcastUno( const SfxHint &rHint )
950 {
951     if (!pUnoBroadcaster)
952         return;
953 
954     bInUnoBroadcast = true;
955     pUnoBroadcaster->Broadcast( rHint );
956     bInUnoBroadcast = false;
957 
958     // During Broadcast notification, Uno objects can add to pUnoListenerCalls.
959     // The listener calls must be processed after completing the broadcast,
960     // because they can add or remove objects from pUnoBroadcaster.
961 
962     if ( pUnoListenerCalls &&
963             rHint.GetId() == SfxHintId::DataChanged &&
964             !bInUnoListenerCall )
965     {
966         // Listener calls may lead to BroadcastUno calls again. The listener calls
967         // are not nested, instead the calls are collected in the list, and the
968         // outermost call executes them all.
969 
970         ScChartLockGuard aChartLockGuard(this);
971         bInUnoListenerCall = true;
972         pUnoListenerCalls->ExecuteAndClear();
973         bInUnoListenerCall = false;
974     }
975 }
976 
AddUnoListenerCall(const uno::Reference<util::XModifyListener> & rListener,const lang::EventObject & rEvent)977 void ScDocument::AddUnoListenerCall( const uno::Reference<util::XModifyListener>& rListener,
978                                         const lang::EventObject& rEvent )
979 {
980     OSL_ENSURE( bInUnoBroadcast, "AddUnoListenerCall is supposed to be called from BroadcastUno only" );
981 
982     if ( !pUnoListenerCalls )
983         pUnoListenerCalls.reset( new ScUnoListenerCalls );
984     pUnoListenerCalls->Add( rListener, rEvent );
985 }
986 
BeginUnoRefUndo()987 void ScDocument::BeginUnoRefUndo()
988 {
989     OSL_ENSURE( !pUnoRefUndoList, "BeginUnoRefUndo twice" );
990     pUnoRefUndoList.reset( new ScUnoRefList );
991 }
992 
EndUnoRefUndo()993 std::unique_ptr<ScUnoRefList> ScDocument::EndUnoRefUndo()
994 {
995     return std::move(pUnoRefUndoList);
996     // Must be deleted by caller!
997 }
998 
AddUnoRefChange(sal_Int64 nId,const ScRangeList & rOldRanges)999 void ScDocument::AddUnoRefChange( sal_Int64 nId, const ScRangeList& rOldRanges )
1000 {
1001     if ( pUnoRefUndoList )
1002         pUnoRefUndoList->Add( nId, rOldRanges );
1003 }
1004 
UpdateReference(sc::RefUpdateContext & rCxt,ScDocument * pUndoDoc,bool bIncludeDraw,bool bUpdateNoteCaptionPos)1005 void ScDocument::UpdateReference(
1006     sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, bool bIncludeDraw, bool bUpdateNoteCaptionPos )
1007 {
1008     if (!ValidRange(rCxt.maRange) && !(rCxt.meMode == URM_INSDEL &&
1009                 ((rCxt.mnColDelta < 0 &&    // convention from ScDocument::DeleteCol()
1010                   rCxt.maRange.aStart.Col() == MAXCOLCOUNT && rCxt.maRange.aEnd.Col() == MAXCOLCOUNT) ||
1011                  (rCxt.mnRowDelta < 0 &&    // convention from ScDocument::DeleteRow()
1012                   rCxt.maRange.aStart.Row() == GetSheetLimits().GetMaxRowCount() && rCxt.maRange.aEnd.Row() == GetSheetLimits().GetMaxRowCount()))))
1013         return;
1014 
1015     std::unique_ptr<sc::ExpandRefsSwitch> pExpandRefsSwitch;
1016     if (rCxt.isInserted())
1017         pExpandRefsSwitch.reset(new sc::ExpandRefsSwitch(*this, SC_MOD()->GetInputOptions().GetExpandRefs()));
1018 
1019     size_t nFirstTab, nLastTab;
1020     if (rCxt.meMode == URM_COPY)
1021     {
1022         nFirstTab = rCxt.maRange.aStart.Tab();
1023         nLastTab = rCxt.maRange.aEnd.Tab();
1024     }
1025     else
1026     {
1027         // TODO: Have these methods use the context object directly.
1028         ScRange aRange = rCxt.maRange;
1029         UpdateRefMode eUpdateRefMode = rCxt.meMode;
1030         SCCOL nDx = rCxt.mnColDelta;
1031         SCROW nDy = rCxt.mnRowDelta;
1032         SCTAB nDz = rCxt.mnTabDelta;
1033         SCCOL nCol1 = rCxt.maRange.aStart.Col(), nCol2 = rCxt.maRange.aEnd.Col();
1034         SCROW nRow1 = rCxt.maRange.aStart.Row(), nRow2 = rCxt.maRange.aEnd.Row();
1035         SCTAB nTab1 = rCxt.maRange.aStart.Tab(), nTab2 = rCxt.maRange.aEnd.Tab();
1036 
1037         xColNameRanges->UpdateReference( eUpdateRefMode, this, aRange, nDx, nDy, nDz );
1038         xRowNameRanges->UpdateReference( eUpdateRefMode, this, aRange, nDx, nDy, nDz );
1039         pDBCollection->UpdateReference( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz );
1040         if (pRangeName)
1041             pRangeName->UpdateReference(rCxt);
1042         if ( pDPCollection )
1043             pDPCollection->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
1044         UpdateChartRef( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz );
1045         UpdateRefAreaLinks( eUpdateRefMode, aRange, nDx, nDy, nDz );
1046         if ( pValidationList )
1047         {
1048             ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
1049             pValidationList->UpdateReference(rCxt);
1050         }
1051         if ( pDetOpList )
1052             pDetOpList->UpdateReference( this, eUpdateRefMode, aRange, nDx, nDy, nDz );
1053         if ( pUnoBroadcaster )
1054             pUnoBroadcaster->Broadcast( ScUpdateRefHint(
1055                                 eUpdateRefMode, aRange, nDx, nDy, nDz ) );
1056 
1057         nFirstTab = 0;
1058         nLastTab = maTabs.size()-1;
1059     }
1060 
1061     for (size_t i = nFirstTab, n = maTabs.size() ; i <= nLastTab && i < n; ++i)
1062     {
1063         if (!maTabs[i])
1064             continue;
1065 
1066         maTabs[i]->UpdateReference(rCxt, pUndoDoc, bIncludeDraw, bUpdateNoteCaptionPos);
1067     }
1068 
1069     if ( bIsEmbedded )
1070     {
1071         SCCOL theCol1;
1072         SCROW theRow1;
1073         SCTAB theTab1;
1074         SCCOL theCol2;
1075         SCROW theRow2;
1076         SCTAB theTab2;
1077         theCol1 = aEmbedRange.aStart.Col();
1078         theRow1 = aEmbedRange.aStart.Row();
1079         theTab1 = aEmbedRange.aStart.Tab();
1080         theCol2 = aEmbedRange.aEnd.Col();
1081         theRow2 = aEmbedRange.aEnd.Row();
1082         theTab2 = aEmbedRange.aEnd.Tab();
1083 
1084         // TODO: Have ScRefUpdate::Update() use the context object directly.
1085         UpdateRefMode eUpdateRefMode = rCxt.meMode;
1086         SCCOL nDx = rCxt.mnColDelta;
1087         SCROW nDy = rCxt.mnRowDelta;
1088         SCTAB nDz = rCxt.mnTabDelta;
1089         SCCOL nCol1 = rCxt.maRange.aStart.Col(), nCol2 = rCxt.maRange.aEnd.Col();
1090         SCROW nRow1 = rCxt.maRange.aStart.Row(), nRow2 = rCxt.maRange.aEnd.Row();
1091         SCTAB nTab1 = rCxt.maRange.aStart.Tab(), nTab2 = rCxt.maRange.aEnd.Tab();
1092 
1093         if ( ScRefUpdate::Update( this, eUpdateRefMode, nCol1,nRow1,nTab1, nCol2,nRow2,nTab2,
1094                                     nDx,nDy,nDz, theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) )
1095         {
1096             aEmbedRange = ScRange( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
1097         }
1098     }
1099 
1100     // After moving, no clipboard move ref-updates are possible
1101     if (rCxt.meMode != URM_COPY && IsClipboardSource())
1102     {
1103         ScDocument* pClipDoc = ScModule::GetClipDoc();
1104         if (pClipDoc)
1105             pClipDoc->GetClipParam().mbCutMode = false;
1106     }
1107 }
1108 
UpdateTranspose(const ScAddress & rDestPos,ScDocument * pClipDoc,const ScMarkData & rMark,ScDocument * pUndoDoc)1109 void ScDocument::UpdateTranspose( const ScAddress& rDestPos, ScDocument* pClipDoc,
1110                                         const ScMarkData& rMark, ScDocument* pUndoDoc )
1111 {
1112     OSL_ENSURE(pClipDoc->bIsClip, "UpdateTranspose: No Clip");
1113 
1114     ScRange aSource;
1115     ScClipParam& rClipParam = pClipDoc->GetClipParam();
1116     if (!rClipParam.maRanges.empty())
1117         aSource = rClipParam.maRanges.front();
1118     ScAddress aDest = rDestPos;
1119 
1120     SCTAB nClipTab = 0;
1121     for (SCTAB nDestTab=0; nDestTab< static_cast<SCTAB>(maTabs.size()) && maTabs[nDestTab]; nDestTab++)
1122         if (rMark.GetTableSelect(nDestTab))
1123         {
1124             while (!pClipDoc->maTabs[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
1125             aSource.aStart.SetTab( nClipTab );
1126             aSource.aEnd.SetTab( nClipTab );
1127             aDest.SetTab( nDestTab );
1128 
1129             // Like UpdateReference
1130             if (pRangeName)
1131                 pRangeName->UpdateTranspose( aSource, aDest ); // Before the cells!
1132             for (SCTAB i=0; i< static_cast<SCTAB>(maTabs.size()); i++)
1133                 if (maTabs[i])
1134                     maTabs[i]->UpdateTranspose( aSource, aDest, pUndoDoc );
1135 
1136             nClipTab = (nClipTab+1) % (MAXTAB+1);
1137         }
1138 }
1139 
UpdateGrow(const ScRange & rArea,SCCOL nGrowX,SCROW nGrowY)1140 void ScDocument::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
1141 {
1142     //TODO: pDBCollection
1143     //TODO: pPivotCollection
1144     //TODO: UpdateChartRef
1145 
1146     if (pRangeName)
1147         pRangeName->UpdateGrow( rArea, nGrowX, nGrowY );
1148 
1149     for (SCTAB i=0; i< static_cast<SCTAB>(maTabs.size()) && maTabs[i]; i++)
1150         maTabs[i]->UpdateGrow( rArea, nGrowX, nGrowY );
1151 }
1152 
Fill(SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2,ScProgress * pProgress,const ScMarkData & rMark,sal_uLong nFillCount,FillDir eFillDir,FillCmd eFillCmd,FillDateCmd eFillDateCmd,double nStepValue,double nMaxValue)1153 void ScDocument::Fill(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScProgress* pProgress, const ScMarkData& rMark,
1154                         sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
1155                         double nStepValue, double nMaxValue)
1156 {
1157     PutInOrder( nCol1, nCol2 );
1158     PutInOrder( nRow1, nRow2 );
1159     ScRange aRange;
1160     rMark.GetMarkArea(aRange);
1161     SCTAB nMax = maTabs.size();
1162     for (const auto& rTab : rMark)
1163     {
1164         if (rTab >= nMax)
1165             break;
1166         if (maTabs[rTab])
1167         {
1168             maTabs[rTab]->Fill(nCol1, nRow1, nCol2, nRow2,
1169                             nFillCount, eFillDir, eFillCmd, eFillDateCmd,
1170                             nStepValue, nMaxValue, pProgress);
1171             RefreshAutoFilter(aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(), rTab);
1172         }
1173     }
1174 }
1175 
GetAutoFillPreview(const ScRange & rSource,SCCOL nEndX,SCROW nEndY)1176 OUString ScDocument::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW nEndY )
1177 {
1178     SCTAB nTab = rSource.aStart.Tab();
1179     if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
1180         return maTabs[nTab]->GetAutoFillPreview( rSource, nEndX, nEndY );
1181 
1182     return OUString();
1183 }
1184 
AutoFormat(SCCOL nStartCol,SCROW nStartRow,SCCOL nEndCol,SCROW nEndRow,sal_uInt16 nFormatNo,const ScMarkData & rMark)1185 void ScDocument::AutoFormat( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1186                                     sal_uInt16 nFormatNo, const ScMarkData& rMark )
1187 {
1188     PutInOrder( nStartCol, nEndCol );
1189     PutInOrder( nStartRow, nEndRow );
1190     SCTAB nMax = maTabs.size();
1191     for (const auto& rTab : rMark)
1192     {
1193         if (rTab >= nMax)
1194             break;
1195         if (maTabs[rTab])
1196             maTabs[rTab]->AutoFormat( nStartCol, nStartRow, nEndCol, nEndRow, nFormatNo );
1197     }
1198 }
1199 
GetAutoFormatData(SCTAB nTab,SCCOL nStartCol,SCROW nStartRow,SCCOL nEndCol,SCROW nEndRow,ScAutoFormatData & rData)1200 void ScDocument::GetAutoFormatData(SCTAB nTab, SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1201                                     ScAutoFormatData& rData)
1202 {
1203     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
1204     {
1205         if (maTabs[nTab])
1206         {
1207             PutInOrder(nStartCol, nEndCol);
1208             PutInOrder(nStartRow, nEndRow);
1209             maTabs[nTab]->GetAutoFormatData(nStartCol, nStartRow, nEndCol, nEndRow, rData);
1210         }
1211     }
1212 }
1213 
GetSearchAndReplaceStart(const SvxSearchItem & rSearchItem,SCCOL & rCol,SCROW & rRow)1214 void ScDocument::GetSearchAndReplaceStart( const SvxSearchItem& rSearchItem,
1215         SCCOL& rCol, SCROW& rRow )
1216 {
1217     SvxSearchCmd nCommand = rSearchItem.GetCommand();
1218     bool bReplace = ( nCommand == SvxSearchCmd::REPLACE ||
1219         nCommand == SvxSearchCmd::REPLACE_ALL );
1220     if ( rSearchItem.GetBackward() )
1221     {
1222         if ( rSearchItem.GetRowDirection() )
1223         {
1224             if ( rSearchItem.GetPattern() )
1225             {
1226                 rCol = MaxCol();
1227                 rRow = MaxRow()+1;
1228             }
1229             else if ( bReplace )
1230             {
1231                 rCol = MaxCol();
1232                 rRow = MaxRow();
1233             }
1234             else
1235             {
1236                 rCol = MaxCol()+1;
1237                 rRow = MaxRow();
1238             }
1239         }
1240         else
1241         {
1242             if ( rSearchItem.GetPattern() )
1243             {
1244                 rCol = MaxCol()+1;
1245                 rRow = MaxRow();
1246             }
1247             else if ( bReplace )
1248             {
1249                 rCol = MaxCol();
1250                 rRow = MaxRow();
1251             }
1252             else
1253             {
1254                 rCol = MaxCol();
1255                 rRow = MaxRow()+1;
1256             }
1257         }
1258     }
1259     else
1260     {
1261         if ( rSearchItem.GetRowDirection() )
1262         {
1263             if ( rSearchItem.GetPattern() )
1264             {
1265                 rCol = 0;
1266                 rRow = SCROW(-1);
1267             }
1268             else if ( bReplace )
1269             {
1270                 rCol = 0;
1271                 rRow = 0;
1272             }
1273             else
1274             {
1275                 rCol = SCCOL(-1);
1276                 rRow = 0;
1277             }
1278         }
1279         else
1280         {
1281             if ( rSearchItem.GetPattern() )
1282             {
1283                 rCol = SCCOL(-1);
1284                 rRow = 0;
1285             }
1286             else if ( bReplace )
1287             {
1288                 rCol = 0;
1289                 rRow = 0;
1290             }
1291             else
1292             {
1293                 rCol = 0;
1294                 rRow = SCROW(-1);
1295             }
1296         }
1297     }
1298 }
1299 
1300 // static
IsEmptyCellSearch(const SvxSearchItem & rSearchItem)1301 bool ScDocument::IsEmptyCellSearch( const SvxSearchItem& rSearchItem )
1302 {
1303     return !rSearchItem.GetPattern() && (rSearchItem.GetCellType() != SvxSearchCellType::NOTE)
1304         && (rSearchItem.GetSearchOptions().searchString.isEmpty()
1305                 || (rSearchItem.GetRegExp() && rSearchItem.GetSearchOptions().searchString == "^$"));
1306 }
1307 
SearchAndReplace(const SvxSearchItem & rSearchItem,SCCOL & rCol,SCROW & rRow,SCTAB & rTab,const ScMarkData & rMark,ScRangeList & rMatchedRanges,OUString & rUndoStr,ScDocument * pUndoDoc)1308 bool ScDocument::SearchAndReplace(
1309     const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow, SCTAB& rTab,
1310     const ScMarkData& rMark, ScRangeList& rMatchedRanges,
1311     OUString& rUndoStr, ScDocument* pUndoDoc)
1312 {
1313     // FIXME: Manage separated marks per table!
1314     bool bFound = false;
1315     if (rTab >= static_cast<SCTAB>(maTabs.size()))
1316         OSL_FAIL("table out of range");
1317     if (ValidTab(rTab))
1318     {
1319         SCCOL nCol;
1320         SCROW nRow;
1321         SCTAB nTab;
1322         SvxSearchCmd nCommand = rSearchItem.GetCommand();
1323         if ( nCommand == SvxSearchCmd::FIND_ALL ||
1324              nCommand == SvxSearchCmd::REPLACE_ALL )
1325         {
1326             SCTAB nMax = maTabs.size();
1327             for (const auto& rMarkedTab : rMark)
1328             {
1329                 if (rMarkedTab >= nMax)
1330                     break;
1331                 if (maTabs[rMarkedTab])
1332                 {
1333                     nCol = 0;
1334                     nRow = 0;
1335                     bFound |= maTabs[rMarkedTab]->SearchAndReplace(
1336                         rSearchItem, nCol, nRow, rMark, rMatchedRanges, rUndoStr, pUndoDoc);
1337                 }
1338             }
1339 
1340             // Mark is set completely inside already
1341         }
1342         else
1343         {
1344             nCol = rCol;
1345             nRow = rRow;
1346             if (rSearchItem.GetBackward())
1347             {
1348                 for (nTab = rTab; (nTab >= 0) && !bFound; nTab--)
1349                     if (maTabs[nTab])
1350                     {
1351                         if (rMark.GetTableSelect(nTab))
1352                         {
1353                             bFound = maTabs[nTab]->SearchAndReplace(
1354                                 rSearchItem, nCol, nRow, rMark, rMatchedRanges, rUndoStr, pUndoDoc);
1355                             if (bFound)
1356                             {
1357                                 rCol = nCol;
1358                                 rRow = nRow;
1359                                 rTab = nTab;
1360                             }
1361                             else
1362                             {
1363                                 ScDocument::GetSearchAndReplaceStart(
1364                                     rSearchItem, nCol, nRow );
1365 
1366                                 // notify LibreOfficeKit about changed page
1367                                 if (comphelper::LibreOfficeKit::isActive())
1368                                 {
1369                                     OString aPayload = OString::number(nTab);
1370                                     if (SfxViewShell* pViewShell = SfxViewShell::Current())
1371                                         pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload.getStr());
1372                                 }
1373                             }
1374                         }
1375                     }
1376             }
1377             else
1378             {
1379                 for (nTab = rTab; (nTab < static_cast<SCTAB>(maTabs.size())) && !bFound; nTab++)
1380                     if (maTabs[nTab])
1381                     {
1382                         if (rMark.GetTableSelect(nTab))
1383                         {
1384                             bFound = maTabs[nTab]->SearchAndReplace(
1385                                 rSearchItem, nCol, nRow, rMark, rMatchedRanges, rUndoStr, pUndoDoc);
1386                             if (bFound)
1387                             {
1388                                 rCol = nCol;
1389                                 rRow = nRow;
1390                                 rTab = nTab;
1391                             }
1392                             else
1393                             {
1394                                 ScDocument::GetSearchAndReplaceStart(
1395                                     rSearchItem, nCol, nRow );
1396 
1397                                 // notify LibreOfficeKit about changed page
1398                                 if (comphelper::LibreOfficeKit::isActive())
1399                                 {
1400                                     OString aPayload = OString::number(nTab);
1401                                     if(SfxViewShell* pViewShell = SfxViewShell::Current())
1402                                         pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload.getStr());
1403                                 }
1404                             }
1405                         }
1406                     }
1407             }
1408         }
1409     }
1410     return bFound;
1411 }
1412 
1413 /**
1414  * Adapt Outline
1415  */
UpdateOutlineCol(SCCOL nStartCol,SCCOL nEndCol,SCTAB nTab,bool bShow)1416 bool ScDocument::UpdateOutlineCol( SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bShow )
1417 {
1418     if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
1419         return maTabs[nTab]->UpdateOutlineCol( nStartCol, nEndCol, bShow );
1420 
1421     OSL_FAIL("missing tab");
1422     return false;
1423 }
1424 
UpdateOutlineRow(SCROW nStartRow,SCROW nEndRow,SCTAB nTab,bool bShow)1425 bool ScDocument::UpdateOutlineRow( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bShow )
1426 {
1427     if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
1428         return maTabs[nTab]->UpdateOutlineRow( nStartRow, nEndRow, bShow );
1429 
1430     OSL_FAIL("missing tab");
1431     return false;
1432 }
1433 
Sort(SCTAB nTab,const ScSortParam & rSortParam,bool bKeepQuery,bool bUpdateRefs,ScProgress * pProgress,sc::ReorderParam * pUndo)1434 void ScDocument::Sort(
1435     SCTAB nTab, const ScSortParam& rSortParam, bool bKeepQuery, bool bUpdateRefs,
1436     ScProgress* pProgress, sc::ReorderParam* pUndo )
1437 {
1438     if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
1439     {
1440         bool bOldEnableIdle = IsIdleEnabled();
1441         EnableIdle(false);
1442         maTabs[nTab]->Sort(rSortParam, bKeepQuery, bUpdateRefs, pProgress, pUndo);
1443         EnableIdle(bOldEnableIdle);
1444     }
1445 }
1446 
Reorder(const sc::ReorderParam & rParam)1447 void ScDocument::Reorder( const sc::ReorderParam& rParam )
1448 {
1449     ScTable* pTab = FetchTable(rParam.maSortRange.aStart.Tab());
1450     if (!pTab)
1451         return;
1452 
1453     bool bOldEnableIdle = IsIdleEnabled();
1454     EnableIdle(false);
1455     pTab->Reorder(rParam);
1456     EnableIdle(bOldEnableIdle);
1457 }
1458 
PrepareQuery(SCTAB nTab,ScQueryParam & rQueryParam)1459 void ScDocument::PrepareQuery( SCTAB nTab, ScQueryParam& rQueryParam )
1460 {
1461     if( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
1462         maTabs[nTab]->PrepareQuery(rQueryParam);
1463     else
1464     {
1465         OSL_FAIL("missing tab");
1466         return;
1467     }
1468 }
1469 
Query(SCTAB nTab,const ScQueryParam & rQueryParam,bool bKeepSub)1470 SCSIZE ScDocument::Query(SCTAB nTab, const ScQueryParam& rQueryParam, bool bKeepSub)
1471 {
1472     if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
1473         return maTabs[nTab]->Query(rQueryParam, bKeepSub);
1474 
1475     OSL_FAIL("missing tab");
1476     return 0;
1477 }
1478 
GetUpperCellString(SCCOL nCol,SCROW nRow,SCTAB nTab,OUString & rStr)1479 void ScDocument::GetUpperCellString(SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rStr)
1480 {
1481     if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
1482         maTabs[nTab]->GetUpperCellString( nCol, nRow, rStr );
1483     else
1484         rStr.clear();
1485 }
1486 
CreateQueryParam(const ScRange & rRange,ScQueryParam & rQueryParam)1487 bool ScDocument::CreateQueryParam( const ScRange& rRange, ScQueryParam& rQueryParam )
1488 {
1489     ScTable* pTab = FetchTable(rRange.aStart.Tab());
1490     if (!pTab)
1491     {
1492         OSL_FAIL("missing tab");
1493         return false;
1494     }
1495 
1496     return pTab->CreateQueryParam(
1497         rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(), rQueryParam);
1498 }
1499 
HasAutoFilter(SCCOL nCurCol,SCROW nCurRow,SCTAB nCurTab)1500 bool ScDocument::HasAutoFilter( SCCOL nCurCol, SCROW nCurRow, SCTAB nCurTab )
1501 {
1502     const ScDBData* pDBData = GetDBAtCursor( nCurCol, nCurRow, nCurTab, ScDBDataPortion::AREA );
1503     bool bHasAutoFilter = (pDBData != nullptr);
1504 
1505     if ( pDBData )
1506     {
1507         if ( pDBData->HasHeader() )
1508         {
1509             SCCOL nCol;
1510             SCROW nRow;
1511             ScMF  nFlag;
1512 
1513             ScQueryParam aParam;
1514             pDBData->GetQueryParam( aParam );
1515             nRow = aParam.nRow1;
1516 
1517             for ( nCol=aParam.nCol1; nCol<=aParam.nCol2 && bHasAutoFilter; nCol++ )
1518             {
1519                 nFlag = GetAttr( nCol, nRow, nCurTab, ATTR_MERGE_FLAG )->GetValue();
1520 
1521                 if ( !(nFlag & ScMF::Auto) )
1522                     bHasAutoFilter = false;
1523             }
1524         }
1525         else
1526             bHasAutoFilter = false;
1527     }
1528 
1529     return bHasAutoFilter;
1530 }
1531 
HasColHeader(SCCOL nStartCol,SCROW nStartRow,SCCOL nEndCol,SCROW nEndRow,SCTAB nTab)1532 bool ScDocument::HasColHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1533                                     SCTAB nTab )
1534 {
1535     return ValidTab(nTab) && maTabs[nTab] && maTabs[nTab]->HasColHeader( nStartCol, nStartRow, nEndCol, nEndRow );
1536 }
1537 
HasRowHeader(SCCOL nStartCol,SCROW nStartRow,SCCOL nEndCol,SCROW nEndRow,SCTAB nTab)1538 bool ScDocument::HasRowHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1539                                     SCTAB nTab )
1540 {
1541     return ValidTab(nTab) && maTabs[nTab] && maTabs[nTab]->HasRowHeader( nStartCol, nStartRow, nEndCol, nEndRow );
1542 }
1543 
GetFilterSelCount(SCCOL nCol,SCROW nRow,SCTAB nTab,SCSIZE & nSelected,SCSIZE & nTotal)1544 void ScDocument::GetFilterSelCount( SCCOL nCol, SCROW nRow, SCTAB nTab, SCSIZE& nSelected, SCSIZE& nTotal )
1545 {
1546     nSelected = 0;
1547     nTotal = 0;
1548     if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
1549     {
1550         ScDBData* pDBData = GetDBAtCursor( nCol, nRow, nTab, ScDBDataPortion::AREA );
1551         if( pDBData && pDBData->HasAutoFilter() )
1552             pDBData->GetFilterSelCount( nSelected, nTotal );
1553     }
1554 }
1555 
1556 /**
1557  * Entries for AutoFilter listbox
1558  */
GetFilterEntries(SCCOL nCol,SCROW nRow,SCTAB nTab,ScFilterEntries & rFilterEntries)1559 void ScDocument::GetFilterEntries(
1560     SCCOL nCol, SCROW nRow, SCTAB nTab, ScFilterEntries& rFilterEntries )
1561 {
1562     if ( !(ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && pDBCollection) )
1563         return;
1564 
1565     ScDBData* pDBData = pDBCollection->GetDBAtCursor(nCol, nRow, nTab, ScDBDataPortion::AREA);  //!??
1566     if (!pDBData)
1567         return;
1568 
1569     pDBData->ExtendDataArea(*this);
1570     SCTAB nAreaTab;
1571     SCCOL nStartCol;
1572     SCROW nStartRow;
1573     SCCOL nEndCol;
1574     SCROW nEndRow;
1575     pDBData->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow );
1576 
1577     if (pDBData->HasHeader())
1578         ++nStartRow;
1579 
1580     ScQueryParam aParam;
1581     pDBData->GetQueryParam( aParam );
1582 
1583     // Return all filter entries, if a filter condition is connected with a boolean OR
1584     bool bFilter = true;
1585     SCSIZE nEntryCount = aParam.GetEntryCount();
1586     for ( SCSIZE i = 0; i < nEntryCount && aParam.GetEntry(i).bDoQuery; ++i )
1587     {
1588         ScQueryEntry& rEntry = aParam.GetEntry(i);
1589         if ( rEntry.eConnect != SC_AND )
1590         {
1591             bFilter = false;
1592             break;
1593         }
1594     }
1595 
1596     if ( bFilter )
1597     {
1598         maTabs[nTab]->GetFilteredFilterEntries( nCol, nStartRow, nEndRow, aParam, rFilterEntries, bFilter );
1599     }
1600     else
1601     {
1602         maTabs[nTab]->GetFilterEntries( nCol, nStartRow, nEndRow, rFilterEntries );
1603     }
1604 
1605     sortAndRemoveDuplicates( rFilterEntries.maStrData, aParam.bCaseSens);
1606 }
1607 
1608 /**
1609  * Entries for Filter dialog
1610  */
GetFilterEntriesArea(SCCOL nCol,SCROW nStartRow,SCROW nEndRow,SCTAB nTab,bool bCaseSens,ScFilterEntries & rFilterEntries)1611 void ScDocument::GetFilterEntriesArea(
1612     SCCOL nCol, SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bCaseSens,
1613     ScFilterEntries& rFilterEntries )
1614 {
1615     if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
1616     {
1617         maTabs[nTab]->GetFilterEntries( nCol, nStartRow, nEndRow, rFilterEntries, true );
1618         sortAndRemoveDuplicates( rFilterEntries.maStrData, bCaseSens);
1619     }
1620 }
1621 
1622 /**
1623  * Entries for selection list listbox (no numbers/formulas)
1624  */
GetDataEntries(SCCOL nCol,SCROW nRow,SCTAB nTab,std::vector<ScTypedStrData> & rStrings,bool bLimit)1625 void ScDocument::GetDataEntries(
1626     SCCOL nCol, SCROW nRow, SCTAB nTab,
1627     std::vector<ScTypedStrData>& rStrings, bool bLimit )
1628 {
1629     if( !bLimit )
1630     {
1631         /*  Try to generate the list from list validation. This part is skipped,
1632             if bLimit==true, because in that case this function is called to get
1633             cell values for auto completion on input. */
1634         sal_uInt32 nValidation = GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA )->GetValue();
1635         if( nValidation )
1636         {
1637             const ScValidationData* pData = GetValidationEntry( nValidation );
1638             if( pData && pData->FillSelectionList( rStrings, ScAddress( nCol, nRow, nTab ) ) )
1639             {
1640                 if (pData->GetListType() == css::sheet::TableValidationVisibility::SORTEDASCENDING)
1641                     sortAndRemoveDuplicates(rStrings, true/*bCaseSens*/);
1642 
1643                 return;
1644             }
1645         }
1646     }
1647 
1648     if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()))
1649         return;
1650 
1651     if (!maTabs[nTab])
1652         return;
1653 
1654     std::set<ScTypedStrData> aStrings;
1655     if (maTabs[nTab]->GetDataEntries(nCol, nRow, aStrings, bLimit))
1656     {
1657         rStrings.insert(rStrings.end(), aStrings.begin(), aStrings.end());
1658         sortAndRemoveDuplicates(rStrings, true/*bCaseSens*/);
1659     }
1660 }
1661 
1662 /**
1663  * Entries for Formula auto input
1664  */
GetFormulaEntries(ScTypedCaseStrSet & rStrings)1665 void ScDocument::GetFormulaEntries( ScTypedCaseStrSet& rStrings )
1666 {
1667 
1668     // Range name
1669     if ( pRangeName )
1670     {
1671         for (const auto& rEntry : *pRangeName)
1672             rStrings.insert(ScTypedStrData(rEntry.second->GetName(), 0.0, 0.0, ScTypedStrData::Name));
1673     }
1674 
1675     // Database collection
1676     if ( pDBCollection )
1677     {
1678         const ScDBCollection::NamedDBs& rDBs = pDBCollection->getNamedDBs();
1679         for (const auto& rxDB : rDBs)
1680             rStrings.insert(ScTypedStrData(rxDB->GetName(), 0.0, 0.0, ScTypedStrData::DbName));
1681     }
1682 
1683     // Content of name ranges
1684     ScRangePairList* pLists[2];
1685     pLists[0] = GetColNameRanges();
1686     pLists[1] = GetRowNameRanges();
1687     for (ScRangePairList* pList : pLists)
1688     {
1689         if (!pList)
1690             continue;
1691 
1692         for ( size_t i = 0, nPairs = pList->size(); i < nPairs; ++i )
1693         {
1694             const ScRangePair & rPair = (*pList)[i];
1695             const ScRange & rRange = rPair.GetRange(0);
1696             ScCellIterator aIter( *this, rRange );
1697             for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
1698             {
1699                 if (!aIter.hasString())
1700                     continue;
1701 
1702                 OUString aStr = aIter.getString();
1703                 rStrings.insert(ScTypedStrData(aStr, 0.0, 0.0, ScTypedStrData::Header));
1704             }
1705         }
1706     }
1707 }
1708 
GetEmbedded(ScRange & rRange) const1709 void ScDocument::GetEmbedded( ScRange& rRange ) const
1710 {
1711     rRange = aEmbedRange;
1712 }
1713 
GetEmbeddedRect() const1714 tools::Rectangle ScDocument::GetEmbeddedRect() const // 1/100 mm
1715 {
1716     tools::Rectangle aRect;
1717     ScTable* pTable = nullptr;
1718     if ( aEmbedRange.aStart.Tab() < static_cast<SCTAB>(maTabs.size()) )
1719         pTable = maTabs[aEmbedRange.aStart.Tab()].get();
1720     else
1721         OSL_FAIL("table out of range");
1722     if (!pTable)
1723     {
1724         OSL_FAIL("GetEmbeddedRect without a table");
1725     }
1726     else
1727     {
1728         SCCOL i;
1729 
1730         for (i=0; i<aEmbedRange.aStart.Col(); i++)
1731             aRect.AdjustLeft(pTable->GetColWidth(i) );
1732         aRect.AdjustTop(pTable->GetRowHeight( 0, aEmbedRange.aStart.Row() - 1) );
1733         aRect.SetRight( aRect.Left() );
1734         for (i=aEmbedRange.aStart.Col(); i<=aEmbedRange.aEnd.Col(); i++)
1735             aRect.AdjustRight(pTable->GetColWidth(i) );
1736         aRect.SetBottom( aRect.Top() );
1737         aRect.AdjustBottom(pTable->GetRowHeight( aEmbedRange.aStart.Row(), aEmbedRange.aEnd.Row()) );
1738 
1739         aRect.SetLeft( static_cast<tools::Long>( aRect.Left()   * HMM_PER_TWIPS ) );
1740         aRect.SetRight( static_cast<tools::Long>( aRect.Right()  * HMM_PER_TWIPS ) );
1741         aRect.SetTop( static_cast<tools::Long>( aRect.Top()    * HMM_PER_TWIPS ) );
1742         aRect.SetBottom( static_cast<tools::Long>( aRect.Bottom() * HMM_PER_TWIPS ) );
1743     }
1744     return aRect;
1745 }
1746 
SetEmbedded(const ScRange & rRange)1747 void ScDocument::SetEmbedded( const ScRange& rRange )
1748 {
1749     bIsEmbedded = true;
1750     aEmbedRange = rRange;
1751 }
1752 
ResetEmbedded()1753 void ScDocument::ResetEmbedded()
1754 {
1755     bIsEmbedded = false;
1756     aEmbedRange = ScRange();
1757 }
1758 
1759 /** Similar to ScViewData::AddPixelsWhile(), but add height twips and only
1760     while result is less than nStopTwips.
1761     @return true if advanced at least one row.
1762  */
lcl_AddTwipsWhile(tools::Long & rTwips,tools::Long nStopTwips,SCROW & rPosY,SCROW nEndRow,const ScTable * pTable,bool bHiddenAsZero)1763 static bool lcl_AddTwipsWhile( tools::Long & rTwips, tools::Long nStopTwips, SCROW & rPosY, SCROW nEndRow, const ScTable * pTable, bool bHiddenAsZero )
1764 {
1765     SCROW nRow = rPosY;
1766     bool bAdded = false;
1767     bool bStop = false;
1768     while (rTwips < nStopTwips && nRow <= nEndRow && !bStop)
1769     {
1770         SCROW nHeightEndRow;
1771         sal_uInt16 nHeight = pTable->GetRowHeight( nRow, nullptr, &nHeightEndRow, bHiddenAsZero );
1772         if (nHeightEndRow > nEndRow)
1773             nHeightEndRow = nEndRow;
1774         if (!nHeight)
1775             nRow = nHeightEndRow + 1;
1776         else
1777         {
1778             SCROW nRows = nHeightEndRow - nRow + 1;
1779             sal_Int64 nAdd = static_cast<sal_Int64>(nHeight) * nRows;
1780             if (nAdd + rTwips >= nStopTwips)
1781             {
1782                 sal_Int64 nDiff = nAdd + rTwips - nStopTwips;
1783                 nRows -= static_cast<SCROW>(nDiff / nHeight);
1784                 nAdd = static_cast<sal_Int64>(nHeight) * nRows;
1785                 // We're looking for a value that satisfies loop condition.
1786                 if (nAdd + rTwips >= nStopTwips)
1787                 {
1788                     --nRows;
1789                     nAdd -= nHeight;
1790                 }
1791                 bStop = true;
1792             }
1793             rTwips += static_cast<tools::Long>(nAdd);
1794             nRow += nRows;
1795         }
1796     }
1797     if (nRow > rPosY)
1798     {
1799         --nRow;
1800         bAdded = true;
1801     }
1802     rPosY = nRow;
1803     return bAdded;
1804 }
1805 
GetRange(SCTAB nTab,const tools::Rectangle & rMMRect,bool bHiddenAsZero) const1806 ScRange ScDocument::GetRange( SCTAB nTab, const tools::Rectangle& rMMRect, bool bHiddenAsZero ) const
1807 {
1808     ScTable* pTable = nullptr;
1809     if (nTab < static_cast<SCTAB>(maTabs.size()))
1810         pTable = maTabs[nTab].get();
1811     else
1812         OSL_FAIL("table out of range");
1813     if (!pTable)
1814     {
1815         OSL_FAIL("GetRange without a table");
1816         return ScRange();
1817     }
1818 
1819     tools::Rectangle aPosRect = rMMRect;
1820     if ( IsNegativePage( nTab ) )
1821         ScDrawLayer::MirrorRectRTL( aPosRect ); // Always with positive (LTR) values
1822 
1823     tools::Long nSize;
1824     tools::Long nTwips;
1825     tools::Long nAdd;
1826     bool bEnd;
1827 
1828     nSize = 0;
1829     nTwips = static_cast<tools::Long>(aPosRect.Left() / HMM_PER_TWIPS);
1830 
1831     SCCOL nX1 = 0;
1832     bEnd = false;
1833     while (!bEnd)
1834     {
1835         nAdd = static_cast<tools::Long>(pTable->GetColWidth(nX1, bHiddenAsZero));
1836         if (nSize+nAdd <= nTwips+1 && nX1<MaxCol())
1837         {
1838             nSize += nAdd;
1839             ++nX1;
1840         }
1841         else
1842             bEnd = true;
1843     }
1844 
1845 
1846     SCCOL nX2 = nX1;
1847     if (!aPosRect.IsEmpty())
1848     {
1849         bEnd = false;
1850         nTwips = static_cast<tools::Long>(aPosRect.Right() / HMM_PER_TWIPS);
1851         while (!bEnd)
1852         {
1853             nAdd = static_cast<tools::Long>(pTable->GetColWidth(nX2, bHiddenAsZero));
1854             if (nSize+nAdd < nTwips && nX2<MaxCol())
1855             {
1856                 nSize += nAdd;
1857                 ++nX2;
1858             }
1859             else
1860                 bEnd = true;
1861         }
1862     }
1863 
1864     nSize = 0;
1865     nTwips = static_cast<tools::Long>(aPosRect.Top() / HMM_PER_TWIPS);
1866 
1867     SCROW nY1 = 0;
1868     // Was if(nSize+nAdd<=nTwips+1) inside loop => if(nSize+nAdd<nTwips+2)
1869     if (lcl_AddTwipsWhile( nSize, nTwips+2, nY1, MaxRow(), pTable, bHiddenAsZero) && nY1 < MaxRow())
1870         ++nY1;  // original loop ended on last matched +1 unless that was rDoc.MaxRow()
1871 
1872     SCROW nY2 = nY1;
1873     if (!aPosRect.IsEmpty())
1874     {
1875         nTwips = static_cast<tools::Long>(aPosRect.Bottom() / HMM_PER_TWIPS);
1876         // Was if(nSize+nAdd<nTwips) inside loop => if(nSize+nAdd<nTwips)
1877         if (lcl_AddTwipsWhile( nSize, nTwips, nY2, MaxRow(), pTable, bHiddenAsZero) && nY2 < MaxRow())
1878             ++nY2;  // original loop ended on last matched +1 unless that was rDoc.MaxRow()
1879     }
1880 
1881     return ScRange( nX1,nY1,nTab, nX2,nY2,nTab );
1882 }
1883 
SetEmbedded(SCTAB nTab,const tools::Rectangle & rRect)1884 void ScDocument::SetEmbedded( SCTAB nTab, const tools::Rectangle& rRect ) // From VisArea (1/100 mm)
1885 {
1886     bIsEmbedded = true;
1887     aEmbedRange = GetRange( nTab, rRect );
1888 }
1889 
GetDocProtection() const1890 ScDocProtection* ScDocument::GetDocProtection() const
1891 {
1892     return pDocProtection.get();
1893 }
1894 
SetDocProtection(const ScDocProtection * pProtect)1895 void ScDocument::SetDocProtection(const ScDocProtection* pProtect)
1896 {
1897     if (pProtect)
1898         pDocProtection.reset(new ScDocProtection(*pProtect));
1899     else
1900         pDocProtection.reset();
1901 }
1902 
IsDocProtected() const1903 bool ScDocument::IsDocProtected() const
1904 {
1905     return pDocProtection && pDocProtection->isProtected();
1906 }
1907 
IsDocEditable() const1908 bool ScDocument::IsDocEditable() const
1909 {
1910     // Import into read-only document is possible
1911     return !IsDocProtected() && ( bImportingXML || mbChangeReadOnlyEnabled || !mpShell || !mpShell->IsReadOnly() );
1912 }
1913 
IsTabProtected(SCTAB nTab) const1914 bool ScDocument::IsTabProtected( SCTAB nTab ) const
1915 {
1916     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
1917         return maTabs[nTab]->IsProtected();
1918 
1919     OSL_FAIL("Wrong table number");
1920     return false;
1921 }
1922 
GetTabProtection(SCTAB nTab) const1923 const ScTableProtection* ScDocument::GetTabProtection(SCTAB nTab) const
1924 {
1925     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
1926         return maTabs[nTab]->GetProtection();
1927 
1928     return nullptr;
1929 }
1930 
SetTabProtection(SCTAB nTab,const ScTableProtection * pProtect)1931 void ScDocument::SetTabProtection(SCTAB nTab, const ScTableProtection* pProtect)
1932 {
1933     if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()))
1934         return;
1935 
1936     maTabs[nTab]->SetProtection(pProtect);
1937 }
1938 
CopyTabProtection(SCTAB nTabSrc,SCTAB nTabDest)1939 void ScDocument::CopyTabProtection(SCTAB nTabSrc, SCTAB nTabDest)
1940 {
1941     if (!ValidTab(nTabSrc) || nTabSrc >= static_cast<SCTAB>(maTabs.size()) || nTabDest >= static_cast<SCTAB>(maTabs.size()) || !ValidTab(nTabDest))
1942         return;
1943 
1944     maTabs[nTabDest]->SetProtection( maTabs[nTabSrc]->GetProtection() );
1945 }
1946 
GetDocOptions() const1947 const ScDocOptions& ScDocument::GetDocOptions() const
1948 {
1949     assert(pDocOptions && "No DocOptions! :-(");
1950     return *pDocOptions;
1951 }
1952 
SetDocOptions(const ScDocOptions & rOpt)1953 void ScDocument::SetDocOptions( const ScDocOptions& rOpt )
1954 {
1955     assert(pDocOptions && "No DocOptions! :-(");
1956 
1957     *pDocOptions = rOpt;
1958     mxPoolHelper->SetFormTableOpt(rOpt);
1959 }
1960 
GetViewOptions() const1961 const ScViewOptions& ScDocument::GetViewOptions() const
1962 {
1963     assert(pViewOptions && "No ViewOptions! :-(");
1964     return *pViewOptions;
1965 }
1966 
SetViewOptions(const ScViewOptions & rOpt)1967 void ScDocument::SetViewOptions( const ScViewOptions& rOpt )
1968 {
1969     assert(pViewOptions && "No ViewOptions! :-(");
1970     *pViewOptions = rOpt;
1971 }
1972 
GetLanguage(LanguageType & rLatin,LanguageType & rCjk,LanguageType & rCtl) const1973 void ScDocument::GetLanguage( LanguageType& rLatin, LanguageType& rCjk, LanguageType& rCtl ) const
1974 {
1975     rLatin = eLanguage;
1976     rCjk = eCjkLanguage;
1977     rCtl = eCtlLanguage;
1978 }
1979 
SetLanguage(LanguageType eLatin,LanguageType eCjk,LanguageType eCtl)1980 void ScDocument::SetLanguage( LanguageType eLatin, LanguageType eCjk, LanguageType eCtl )
1981 {
1982     eLanguage = eLatin;
1983     eCjkLanguage = eCjk;
1984     eCtlLanguage = eCtl;
1985     if ( mxPoolHelper.is() )
1986     {
1987         ScDocumentPool* pPool = mxPoolHelper->GetDocPool();
1988         pPool->SetPoolDefaultItem( SvxLanguageItem( eLanguage, ATTR_FONT_LANGUAGE ) );
1989         pPool->SetPoolDefaultItem( SvxLanguageItem( eCjkLanguage, ATTR_CJK_FONT_LANGUAGE ) );
1990         pPool->SetPoolDefaultItem( SvxLanguageItem( eCtlLanguage, ATTR_CTL_FONT_LANGUAGE ) );
1991     }
1992 
1993     UpdateDrawLanguages(); // Set edit engine defaults in drawing layer pool
1994 }
1995 
GetMMRect(SCCOL nStartCol,SCROW nStartRow,SCCOL nEndCol,SCROW nEndRow,SCTAB nTab,bool bHiddenAsZero) const1996 tools::Rectangle ScDocument::GetMMRect( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, bool bHiddenAsZero ) const
1997 {
1998     if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
1999     {
2000         OSL_FAIL("GetMMRect: wrong table");
2001         return tools::Rectangle(0,0,0,0);
2002     }
2003 
2004     SCCOL i;
2005     tools::Rectangle aRect;
2006 
2007     for (i=0; i<nStartCol; i++)
2008         aRect.AdjustLeft(GetColWidth(i,nTab, bHiddenAsZero ) );
2009     aRect.AdjustTop(GetRowHeight( 0, nStartRow-1, nTab, bHiddenAsZero ) );
2010 
2011     aRect.SetRight( aRect.Left() );
2012     aRect.SetBottom( aRect.Top() );
2013 
2014     for (i=nStartCol; i<=nEndCol; i++)
2015         aRect.AdjustRight(GetColWidth(i,nTab, bHiddenAsZero) );
2016     aRect.AdjustBottom(GetRowHeight( nStartRow, nEndRow, nTab, bHiddenAsZero ) );
2017 
2018     aRect.SetLeft( static_cast<tools::Long>(aRect.Left()   * HMM_PER_TWIPS) );
2019     aRect.SetRight( static_cast<tools::Long>(aRect.Right()  * HMM_PER_TWIPS) );
2020     aRect.SetTop( static_cast<tools::Long>(aRect.Top()    * HMM_PER_TWIPS) );
2021     aRect.SetBottom( static_cast<tools::Long>(aRect.Bottom() * HMM_PER_TWIPS) );
2022 
2023     if ( IsNegativePage( nTab ) )
2024         ScDrawLayer::MirrorRectRTL( aRect );
2025 
2026     return aRect;
2027 }
2028 
SetExtDocOptions(std::unique_ptr<ScExtDocOptions> pNewOptions)2029 void ScDocument::SetExtDocOptions( std::unique_ptr<ScExtDocOptions> pNewOptions )
2030 {
2031     pExtDocOptions = std::move(pNewOptions);
2032 }
2033 
SetClipOptions(std::unique_ptr<ScClipOptions> pClipOptions)2034 void ScDocument::SetClipOptions(std::unique_ptr<ScClipOptions> pClipOptions)
2035 {
2036     mpClipOptions = std::move(pClipOptions);
2037 }
2038 
DoMergeContents(SCTAB nTab,SCCOL nStartCol,SCROW nStartRow,SCCOL nEndCol,SCROW nEndRow)2039 void ScDocument::DoMergeContents( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
2040                                     SCCOL nEndCol, SCROW nEndRow )
2041 {
2042     OUStringBuffer aTotal;
2043     OUString aCellStr;
2044     SCCOL nCol;
2045     SCROW nRow;
2046     for (nRow=nStartRow; nRow<=nEndRow; nRow++)
2047         for (nCol=nStartCol; nCol<=nEndCol; nCol++)
2048         {
2049             aCellStr = GetString(nCol, nRow, nTab);
2050             if (!aCellStr.isEmpty())
2051             {
2052                 if (!aTotal.isEmpty())
2053                     aTotal.append(' ');
2054                 aTotal.append(aCellStr);
2055             }
2056             if (nCol != nStartCol || nRow != nStartRow)
2057                 SetString(nCol,nRow,nTab,"");
2058         }
2059 
2060     SetString(nStartCol,nStartRow,nTab,aTotal.makeStringAndClear());
2061 }
2062 
DoEmptyBlock(SCTAB nTab,SCCOL nStartCol,SCROW nStartRow,SCCOL nEndCol,SCROW nEndRow)2063 void ScDocument::DoEmptyBlock( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
2064                                SCCOL nEndCol, SCROW nEndRow )
2065 {
2066     SCCOL nCol;
2067     SCROW nRow;
2068     for (nRow=nStartRow; nRow<=nEndRow; nRow++)
2069         for (nCol=nStartCol; nCol<=nEndCol; nCol++)
2070         {  // empty block except first cell
2071             if (nCol != nStartCol || nRow != nStartRow)
2072                 SetString(nCol,nRow,nTab,"");
2073         }
2074 }
2075 
DoMerge(SCTAB nTab,SCCOL nStartCol,SCROW nStartRow,SCCOL nEndCol,SCROW nEndRow,bool bDeleteCaptions)2076 void ScDocument::DoMerge( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
2077                                     SCCOL nEndCol, SCROW nEndRow, bool bDeleteCaptions )
2078 {
2079     ScTable* pTab = FetchTable(nTab);
2080     if (!pTab)
2081         return;
2082 
2083     pTab->SetMergedCells(nStartCol, nStartRow, nEndCol, nEndRow);
2084 
2085     // Remove all covered notes (removed captions are collected by drawing undo if active)
2086     InsertDeleteFlags nDelFlag = InsertDeleteFlags::NOTE | (bDeleteCaptions ? InsertDeleteFlags::NONE : InsertDeleteFlags::NOCAPTIONS);
2087     if( nStartCol < nEndCol )
2088         DeleteAreaTab( nStartCol + 1, nStartRow, nEndCol, nStartRow, nTab, nDelFlag );
2089     if( nStartRow < nEndRow )
2090         DeleteAreaTab( nStartCol, nStartRow + 1, nEndCol, nEndRow, nTab, nDelFlag );
2091 }
2092 
RemoveMerge(SCCOL nCol,SCROW nRow,SCTAB nTab)2093 void ScDocument::RemoveMerge( SCCOL nCol, SCROW nRow, SCTAB nTab )
2094 {
2095     const ScMergeAttr* pAttr = GetAttr( nCol, nRow, nTab, ATTR_MERGE );
2096 
2097     if ( pAttr->GetColMerge() <= 1 && pAttr->GetRowMerge() <= 1 )
2098         return;
2099 
2100     SCCOL nEndCol = nCol + pAttr->GetColMerge() - 1;
2101     SCROW nEndRow = nRow + pAttr->GetRowMerge() - 1;
2102 
2103     RemoveFlagsTab( nCol, nRow, nEndCol, nEndRow, nTab, ScMF::Hor | ScMF::Ver );
2104 
2105     const ScMergeAttr* pDefAttr = &mxPoolHelper->GetDocPool()->GetDefaultItem( ATTR_MERGE );
2106     ApplyAttr( nCol, nRow, nTab, *pDefAttr );
2107 }
2108 
ExtendPrintArea(OutputDevice * pDev,SCTAB nTab,SCCOL nStartCol,SCROW nStartRow,SCCOL & rEndCol,SCROW nEndRow) const2109 void ScDocument::ExtendPrintArea( OutputDevice* pDev, SCTAB nTab,
2110                     SCCOL nStartCol, SCROW nStartRow, SCCOL& rEndCol, SCROW nEndRow ) const
2111 {
2112     if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
2113         maTabs[nTab]->ExtendPrintArea( pDev, nStartCol, nStartRow, rEndCol, nEndRow );
2114 }
2115 
GetPatternCount(SCTAB nTab,SCCOL nCol) const2116 SCSIZE ScDocument::GetPatternCount( SCTAB nTab, SCCOL nCol ) const
2117 {
2118     if( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
2119         return maTabs[nTab]->GetPatternCount( nCol );
2120     else
2121         return 0;
2122 }
2123 
GetPatternCount(SCTAB nTab,SCCOL nCol,SCROW nRow1,SCROW nRow2) const2124 SCSIZE ScDocument::GetPatternCount( SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const
2125 {
2126     if( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
2127         return maTabs[nTab]->GetPatternCount( nCol, nRow1, nRow2 );
2128     else
2129         return 0;
2130 }
2131 
ReservePatternCount(SCTAB nTab,SCCOL nCol,SCSIZE nReserve)2132 void ScDocument::ReservePatternCount( SCTAB nTab, SCCOL nCol, SCSIZE nReserve )
2133 {
2134     if( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
2135         maTabs[nTab]->ReservePatternCount( nCol, nReserve );
2136 }
2137 
GetSortParam(ScSortParam & rParam,SCTAB nTab)2138 void ScDocument::GetSortParam( ScSortParam& rParam, SCTAB nTab )
2139 {
2140     rParam = mSheetSortParams[ nTab ];
2141 }
2142 
SetSortParam(const ScSortParam & rParam,SCTAB nTab)2143 void ScDocument::SetSortParam( const ScSortParam& rParam, SCTAB nTab )
2144 {
2145     mSheetSortParams[ nTab ] = rParam;
2146 }
2147 
ClampToAllocatedColumns(SCTAB nTab,SCCOL nCol) const2148 SCCOL ScDocument::ClampToAllocatedColumns(SCTAB nTab, SCCOL nCol) const
2149 {
2150     return maTabs[nTab]->ClampToAllocatedColumns(nCol);
2151 }
2152 
GetAllocatedColumnsCount(SCTAB nTab) const2153 SCCOL ScDocument::GetAllocatedColumnsCount(SCTAB nTab) const
2154 {
2155     return maTabs[nTab]->GetAllocatedColumnsCount();
2156 }
2157 
2158 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2159