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