Bug Summary

File:home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx
Warning:line 2848, column 44
The right operand of '+' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name document.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SC_DLLIMPLEMENTATION -D SC_INFO_OSVERSION="LINUX" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/liborcus/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/mdds/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/clew/source/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sc/source/core/inc -I /home/maarten/src/libreoffice/core/sc/source/filter/inc -I /home/maarten/src/libreoffice/core/sc/source/ui/inc -I /home/maarten/src/libreoffice/core/sc/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sc/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <scitems.hxx>
21
22#include <editeng/boxitem.hxx>
23#include <editeng/editobj.hxx>
24#include <o3tl/safeint.hxx>
25#include <svx/sdrundomanager.hxx>
26#include <svx/svditer.hxx>
27#include <sfx2/objsh.hxx>
28#include <sfx2/viewsh.hxx>
29#include <sfx2/docfile.hxx>
30#include <svl/poolcach.hxx>
31#include <svl/zforlist.hxx>
32#include <unotools/charclass.hxx>
33#include <unotools/transliterationwrapper.hxx>
34#include <tools/urlobj.hxx>
35#include <sal/log.hxx>
36
37#include <com/sun/star/text/WritingMode2.hpp>
38#include <com/sun/star/script/vba/XVBACompatibility.hpp>
39#include <com/sun/star/sheet/TablePageBreakData.hpp>
40#include <com/sun/star/lang/NotInitializedException.hpp>
41
42#include <document.hxx>
43#include <table.hxx>
44#include <column.hxx>
45#include <attrib.hxx>
46#include <attarray.hxx>
47#include <patattr.hxx>
48#include <rangenam.hxx>
49#include <poolhelp.hxx>
50#include <docpool.hxx>
51#include <stlpool.hxx>
52#include <stlsheet.hxx>
53#include <globstr.hrc>
54#include <scresid.hxx>
55#include <dbdata.hxx>
56#include <chartlis.hxx>
57#include <rangelst.hxx>
58#include <markdata.hxx>
59#include <drwlayer.hxx>
60#include <validat.hxx>
61#include <prnsave.hxx>
62#include <chgtrack.hxx>
63#include <hints.hxx>
64#include <detdata.hxx>
65#include <dpobject.hxx>
66#include <detfunc.hxx>
67#include <scmod.hxx>
68#include <dociter.hxx>
69#include <progress.hxx>
70#include <autonamecache.hxx>
71#include <bcaslot.hxx>
72#include <postit.hxx>
73#include <clipparam.hxx>
74#include <defaultsoptions.hxx>
75#include <editutil.hxx>
76#include <stringutil.hxx>
77#include <formulaiter.hxx>
78#include <formulacell.hxx>
79#include <clipcontext.hxx>
80#include <listenercontext.hxx>
81#include <scopetools.hxx>
82#include <refupdatecontext.hxx>
83#include <formulagroup.hxx>
84#include <tokenstringcontext.hxx>
85#include <compressedarray.hxx>
86#include <docsh.hxx>
87#include <brdcst.hxx>
88#include <recursionhelper.hxx>
89
90#include <formula/vectortoken.hxx>
91
92#include <limits>
93#include <memory>
94#include <utility>
95
96#include <comphelper/lok.hxx>
97#include <LibreOfficeKit/LibreOfficeKitEnums.h>
98
99#include <vcl/uitest/logger.hxx>
100#include <vcl/uitest/eventdescription.hxx>
101
102#include <mtvelements.hxx>
103#include <sfx2/lokhelper.hxx>
104
105using ::editeng::SvxBorderLine;
106using namespace ::com::sun::star;
107
108namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
109using ::com::sun::star::uno::Sequence;
110using ::com::sun::star::sheet::TablePageBreakData;
111using ::std::set;
112
113namespace {
114
115std::pair<SCTAB,SCTAB> getMarkedTableRange(const std::vector<ScTableUniquePtr>& rTables, const ScMarkData& rMark)
116{
117 SCTAB nTabStart = MAXTAB;
118 SCTAB nTabEnd = 0;
119 SCTAB nMax = static_cast<SCTAB>(rTables.size());
120 for (const auto& rTab : rMark)
121 {
122 if (rTab >= nMax)
123 break;
124
125 if (!rTables[rTab])
126 continue;
127
128 if (rTab < nTabStart)
129 nTabStart = rTab;
130 nTabEnd = rTab;
131 }
132
133 return std::pair<SCTAB,SCTAB>(nTabStart,nTabEnd);
134}
135
136void collectUIInformation(const std::map<OUString, OUString>& aParameters, const OUString& rAction)
137{
138 EventDescription aDescription;
139 aDescription.aID = "grid_window";
140 aDescription.aAction = rAction;
141 aDescription.aParameters = aParameters;
142 aDescription.aParent = "MainWindow";
143 aDescription.aKeyWord = "ScGridWinUIObject";
144
145 UITestLogger::getInstance().logEvent(aDescription);
146}
147
148struct ScDefaultAttr
149{
150 const ScPatternAttr* pAttr;
151 SCROW nFirst;
152 SCSIZE nCount;
153 explicit ScDefaultAttr(const ScPatternAttr* pPatAttr) : pAttr(pPatAttr), nFirst(0), nCount(0) {}
154};
155
156struct ScLessDefaultAttr
157{
158 bool operator() (const ScDefaultAttr& rValue1, const ScDefaultAttr& rValue2) const
159 {
160 return rValue1.pAttr < rValue2.pAttr;
161 }
162};
163
164}
165
166typedef std::set<ScDefaultAttr, ScLessDefaultAttr> ScDefaultAttrSet;
167
168void ScDocument::MakeTable( SCTAB nTab,bool _bNeedsNameCheck )
169{
170 if ( !(ValidTab(nTab) && ( nTab >= static_cast<SCTAB>(maTabs.size()) ||!maTabs[nTab])) )
171 return;
172
173 // Get Custom prefix
174 const ScDefaultsOptions& rOpt = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetDefaultsOptions();
175 OUString aString = rOpt.GetInitTabPrefix() + OUString::number(nTab+1);
176 if ( _bNeedsNameCheck )
177 CreateValidTabName( aString ); // no doubles
178 if (nTab < static_cast<SCTAB>(maTabs.size()))
179 {
180 maTabs[nTab].reset( new ScTable(*this, nTab, aString) );
181 }
182 else
183 {
184 while(nTab > static_cast<SCTAB>(maTabs.size()))
185 maTabs.push_back(nullptr);
186 maTabs.emplace_back( new ScTable(*this, nTab, aString) );
187 }
188 maTabs[nTab]->SetLoadingMedium(bLoadingMedium);
189}
190
191bool ScDocument::HasTable( SCTAB nTab ) const
192{
193 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
194 if (maTabs[nTab])
195 return true;
196
197 return false;
198}
199
200bool ScDocument::GetHashCode( SCTAB nTab, sal_Int64& rHashCode ) const
201{
202 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
203 {
204 if (maTabs[nTab])
205 {
206 rHashCode = maTabs[nTab]->GetHashCode();
207 return true;
208 }
209 }
210 return false;
211}
212
213bool ScDocument::GetName( SCTAB nTab, OUString& rName ) const
214{
215 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
216 {
217 if (maTabs[nTab])
218 {
219 rName = maTabs[nTab]->GetName();
220 return true;
221 }
222 }
223 rName.clear();
224 return false;
225}
226
227OUString ScDocument::GetCopyTabName( SCTAB nTab ) const
228{
229 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabNames.size()))
230 return maTabNames[nTab];
231 return OUString();
232}
233
234bool ScDocument::SetCodeName( SCTAB nTab, const OUString& rName )
235{
236 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
237 {
238 if (maTabs[nTab])
239 {
240 maTabs[nTab]->SetCodeName( rName );
241 return true;
242 }
243 }
244 SAL_WARN("sc", "can't set code name " << rName )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sc")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "can't set code name " << rName) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "244" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "can't set code name " << rName)
, 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "can't set code name " << rName; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "244" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "can't set code name " << rName) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "244" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "can't set code name " << rName)
, 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "can't set code name " << rName; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "244" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
245 return false;
246}
247
248bool ScDocument::GetCodeName( SCTAB nTab, OUString& rName ) const
249{
250 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
251 if (maTabs[nTab])
252 {
253 rName = maTabs[nTab]->GetCodeName();
254 return true;
255 }
256 rName.clear();
257 return false;
258}
259
260bool ScDocument::GetTable( const OUString& rName, SCTAB& rTab ) const
261{
262 OUString aUpperName;
263 static OUString aCacheName, aCacheUpperName;
264
265 assert(!IsThreadedGroupCalcInProgress())(static_cast <bool> (!IsThreadedGroupCalcInProgress()) ?
void (0) : __assert_fail ("!IsThreadedGroupCalcInProgress()"
, "/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
, 265, __extension__ __PRETTY_FUNCTION__))
;
266 if (aCacheName != rName)
267 {
268 aCacheName = rName;
269 // surprisingly slow ...
270 aCacheUpperName = ScGlobal::getCharClassPtr()->uppercase(rName);
271 }
272 aUpperName = aCacheUpperName;
273
274 for (SCTAB i=0; i< static_cast<SCTAB>(maTabs.size()); i++)
275 if (maTabs[i])
276 {
277 if (aUpperName == maTabs[i]->GetUpperName())
278 {
279 rTab = i;
280 return true;
281 }
282 }
283 rTab = 0;
284 return false;
285}
286
287std::vector<OUString> ScDocument::GetAllTableNames() const
288{
289 std::vector<OUString> aNames;
290 aNames.reserve(maTabs.size());
291 for (const auto& a : maTabs)
292 {
293 // Positions need to be preserved for ScCompiler and address convention
294 // context, so still push an empty string for NULL tabs.
295 OUString aName;
296 if (a)
297 {
298 const ScTable& rTab = *a;
299 aName = rTab.GetName();
300 }
301 aNames.push_back(aName);
302 }
303
304 return aNames;
305}
306
307ScDBData* ScDocument::GetAnonymousDBData(SCTAB nTab)
308{
309 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
310 return maTabs[nTab]->GetAnonymousDBData();
311 return nullptr;
312}
313
314SCTAB ScDocument::GetTableCount() const
315{
316 return static_cast<SCTAB>(maTabs.size());
317}
318
319void ScDocument::SetAnonymousDBData(SCTAB nTab, std::unique_ptr<ScDBData> pDBData)
320{
321 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
322 maTabs[nTab]->SetAnonymousDBData(std::move(pDBData));
323}
324
325void ScDocument::SetAnonymousDBData( std::unique_ptr<ScDBData> pDBData )
326{
327 mpAnonymousDBData = std::move(pDBData);
328}
329
330ScDBData* ScDocument::GetAnonymousDBData()
331{
332 return mpAnonymousDBData.get();
333}
334
335bool ScDocument::ValidTabName( const OUString& rName )
336{
337 if (rName.isEmpty())
338 return false;
339 sal_Int32 nLen = rName.getLength();
340
341#if 1
342 // Restrict sheet names to what Excel accepts.
343 /* TODO: We may want to remove this restriction for full ODFF compliance.
344 * Merely loading and calculating ODF documents using these characters in
345 * sheet names is not affected by this, but all sheet name editing and
346 * copying functionality is, maybe falling back to "Sheet4" or similar. */
347 for (sal_Int32 i = 0; i < nLen; ++i)
348 {
349 const sal_Unicode c = rName[i];
350 switch (c)
351 {
352 case ':':
353 case '\\':
354 case '/':
355 case '?':
356 case '*':
357 case '[':
358 case ']':
359 // these characters are not allowed to match XL's convention.
360 return false;
361 case '\'':
362 if (i == 0 || i == nLen - 1)
363 // single quote is not allowed at the first or last
364 // character position.
365 return false;
366 break;
367 }
368 }
369#endif
370
371 return true;
372}
373
374bool ScDocument::ValidNewTabName( const OUString& rName ) const
375{
376 bool bValid = ValidTabName(rName);
377 if (!bValid)
378 return false;
379 OUString aUpperName = ScGlobal::getCharClassPtr()->uppercase(rName);
380 for (const auto& a : maTabs)
381 {
382 if (!a)
383 continue;
384 const OUString& rOldName = a->GetUpperName();
385 bValid = rOldName != aUpperName;
386 if (!bValid)
387 break;
388 }
389 return bValid;
390}
391
392void ScDocument::CreateValidTabName(OUString& rName) const
393{
394 if ( !ValidTabName(rName) )
395 {
396 // Find new one
397
398 // Get Custom prefix
399 const ScDefaultsOptions& rOpt = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetDefaultsOptions();
400 const OUString& aStrTable = rOpt.GetInitTabPrefix();
401
402 bool bOk = false;
403
404 // First test if the prefix is valid, if so only avoid doubles
405 bool bPrefix = ValidTabName( aStrTable );
406 OSL_ENSURE(bPrefix, "Invalid Table Name")do { if (true && (!(bPrefix))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "406" ": "), "%s", "Invalid Table Name"); } } while (false
)
;
407 SCTAB nDummy;
408
409 for ( SCTAB i = static_cast<SCTAB>(maTabs.size())+1; !bOk ; i++ )
410 {
411 rName = aStrTable + OUString::number(static_cast<sal_Int32>(i));
412 if (bPrefix)
413 bOk = ValidNewTabName( rName );
414 else
415 bOk = !GetTable( rName, nDummy );
416 }
417 }
418 else
419 {
420 // testing the supplied Name
421
422 if ( !ValidNewTabName(rName) )
423 {
424 SCTAB i = 1;
425 OUStringBuffer aName;
426 do
427 {
428 i++;
429 aName = rName;
430 aName.append('_');
431 aName.append(static_cast<sal_Int32>(i));
432 }
433 while (!ValidNewTabName(aName.toString()) && (i < MAXTAB+1));
434 rName = aName.makeStringAndClear();
435 }
436 }
437}
438
439void ScDocument::CreateValidTabNames(std::vector<OUString>& aNames, SCTAB nCount) const
440{
441 aNames.clear();//ensure that the vector is empty
442
443 // Get Custom prefix
444 const ScDefaultsOptions& rOpt = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetDefaultsOptions();
445 const OUString& aStrTable = rOpt.GetInitTabPrefix();
446
447 OUStringBuffer rName;
448
449 // First test if the prefix is valid, if so only avoid doubles
450 bool bPrefix = ValidTabName( aStrTable );
451 OSL_ENSURE(bPrefix, "Invalid Table Name")do { if (true && (!(bPrefix))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "451" ": "), "%s", "Invalid Table Name"); } } while (false
)
;
452 SCTAB nDummy;
453 SCTAB i = static_cast<SCTAB>(maTabs.size())+1;
454
455 for (SCTAB j = 0; j < nCount; ++j)
456 {
457 bool bOk = false;
458 while(!bOk)
459 {
460 rName = aStrTable;
461 rName.append(static_cast<sal_Int32>(i));
462 if (bPrefix)
463 bOk = ValidNewTabName( rName.toString() );
464 else
465 bOk = !GetTable( rName.toString(), nDummy );
466 i++;
467 }
468 aNames.push_back(rName.makeStringAndClear());
469 }
470}
471
472void ScDocument::AppendTabOnLoad(const OUString& rName)
473{
474 SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
475 if (!ValidTab(nTabCount))
476 // max table count reached. No more tables.
477 return;
478
479 OUString aName = rName;
480 CreateValidTabName(aName);
481 maTabs.emplace_back( new ScTable(*this, nTabCount, aName) );
482}
483
484void ScDocument::SetTabNameOnLoad(SCTAB nTab, const OUString& rName)
485{
486 if (!ValidTab(nTab) || static_cast<SCTAB>(maTabs.size()) <= nTab)
487 return;
488
489 if (!ValidTabName(rName))
490 return;
491
492 maTabs[nTab]->SetName(rName);
493}
494
495void ScDocument::InvalidateStreamOnSave()
496{
497 for (const auto& a : maTabs)
498 {
499 if (a)
500 a->SetStreamValid(false);
501 }
502}
503
504bool ScDocument::InsertTab(
505 SCTAB nPos, const OUString& rName, bool bExternalDocument, bool bUndoDeleteTab )
506{
507 SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
508 bool bValid = ValidTab(nTabCount);
509 if ( !bExternalDocument ) // else test rName == "'Doc'!Tab" first
510 bValid = (bValid && ValidNewTabName(rName));
511 if (bValid)
512 {
513 if (nPos == SC_TAB_APPEND || nPos >= nTabCount)
514 {
515 nPos = maTabs.size();
516 maTabs.emplace_back( new ScTable(*this, nTabCount, rName) );
517 if ( bExternalDocument )
518 maTabs[nTabCount]->SetVisible( false );
519 }
520 else
521 {
522 if (ValidTab(nPos) && (nPos < nTabCount))
523 {
524 sc::RefUpdateInsertTabContext aCxt( *this, nPos, 1);
525
526 ScRange aRange( 0,0,nPos, MaxCol(),MaxRow(),MAXTAB );
527 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
528 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
529 if (pRangeName)
530 pRangeName->UpdateInsertTab(aCxt);
531 pDBCollection->UpdateReference(
532 URM_INSDEL, 0,0,nPos, MaxCol(),MaxRow(),MAXTAB, 0,0,1 );
533 if (pDPCollection)
534 pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
535 if (pDetOpList)
536 pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,1 );
537 UpdateChartRef( URM_INSDEL, 0,0,nPos, MaxCol(),MaxRow(),MAXTAB, 0,0,1 );
538 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,1 );
539 if ( pUnoBroadcaster )
540 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,1 ) );
541
542 for (const auto& a : maTabs)
543 {
544 if (a)
545 a->UpdateInsertTab(aCxt);
546 }
547 maTabs.emplace(maTabs.begin() + nPos, new ScTable(*this, nPos, rName));
548
549 // UpdateBroadcastAreas must be called between UpdateInsertTab,
550 // which ends listening, and StartAllListeners, to not modify
551 // areas that are to be inserted by starting listeners.
552 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,1);
553 for (const auto& a : maTabs)
554 {
555 if (a)
556 a->UpdateCompile();
557 }
558
559 StartAllListeners();
560
561 if (pValidationList)
562 {
563 ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
564 pValidationList->UpdateInsertTab(aCxt);
565 }
566
567 bValid = true;
568 }
569 else
570 bValid = false;
571 }
572 }
573
574 if (bValid)
575 {
576 sc::SetFormulaDirtyContext aCxt;
577 aCxt.mbClearTabDeletedFlag = bUndoDeleteTab;
578 aCxt.mnTabDeletedStart = nPos;
579 aCxt.mnTabDeletedEnd = nPos;
580 SetAllFormulasDirty(aCxt);
581
582 if (comphelper::LibreOfficeKit::isActive() && GetDrawLayer())
583 {
584 ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>(this->GetDocumentShell()->GetModel());
585 SfxLokHelper::notifyDocumentSizeChangedAllViews(pModel);
586 }
587 }
588
589 return bValid;
590}
591
592bool ScDocument::InsertTabs( SCTAB nPos, const std::vector<OUString>& rNames,
593 bool bNamesValid )
594{
595 SCTAB nNewSheets = static_cast<SCTAB>(rNames.size());
596 SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
597 bool bValid = bNamesValid || ValidTab(nTabCount+nNewSheets);
598
599 if (bValid)
600 {
601 if (nPos == SC_TAB_APPEND || nPos >= nTabCount)
602 {
603 for ( SCTAB i = 0; i < nNewSheets; ++i )
604 {
605 maTabs.emplace_back( new ScTable(*this, nTabCount + i, rNames.at(i)) );
606 }
607 }
608 else
609 {
610 if (ValidTab(nPos) && (nPos < nTabCount))
611 {
612 sc::RefUpdateInsertTabContext aCxt( *this, nPos, nNewSheets);
613 ScRange aRange( 0,0,nPos, MaxCol(),MaxRow(),MAXTAB );
614 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,nNewSheets );
615 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,nNewSheets );
616 if (pRangeName)
617 pRangeName->UpdateInsertTab(aCxt);
618 pDBCollection->UpdateReference(
619 URM_INSDEL, 0,0,nPos, MaxCol(),MaxRow(),MAXTAB, 0,0,nNewSheets );
620 if (pDPCollection)
621 pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,nNewSheets );
622 if (pDetOpList)
623 pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,nNewSheets );
624 UpdateChartRef( URM_INSDEL, 0,0,nPos, MaxCol(),MaxRow(),MAXTAB, 0,0,nNewSheets );
625 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0, nNewSheets );
626 if ( pUnoBroadcaster )
627 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,nNewSheets ) );
628
629 for (const auto& a : maTabs)
630 {
631 if (a)
632 a->UpdateInsertTab(aCxt);
633 }
634 for (SCTAB i = 0; i < nNewSheets; ++i)
635 {
636 maTabs.emplace(maTabs.begin() + nPos + i, new ScTable(*this, nPos + i, rNames.at(i)) );
637 }
638
639 // UpdateBroadcastAreas must be called between UpdateInsertTab,
640 // which ends listening, and StartAllListeners, to not modify
641 // areas that are to be inserted by starting listeners.
642 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,nNewSheets);
643 for (const auto& a : maTabs)
644 {
645 if (a)
646 a->UpdateCompile();
647 }
648
649 StartAllListeners();
650
651 if (pValidationList)
652 {
653 ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
654 pValidationList->UpdateInsertTab(aCxt);
655 }
656
657 bValid = true;
658 }
659 else
660 bValid = false;
661 }
662 }
663
664 if (bValid)
665 {
666 sc::SetFormulaDirtyContext aCxt;
667 SetAllFormulasDirty(aCxt);
668 }
669
670 return bValid;
671}
672
673bool ScDocument::DeleteTab( SCTAB nTab )
674{
675 bool bValid = false;
676 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
677 {
678 if (maTabs[nTab])
679 {
680 SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
681 if (nTabCount > 1)
682 {
683 sc::AutoCalcSwitch aACSwitch(*this, false);
684 sc::RefUpdateDeleteTabContext aCxt( *this, nTab, 1);
685
686 ScRange aRange( 0, 0, nTab, MaxCol(), MaxRow(), nTab );
687 DelBroadcastAreasInRange( aRange );
688
689 // #i8180# remove database ranges etc. that are on the deleted tab
690 // (restored in undo with ScRefUndoData)
691
692 xColNameRanges->DeleteOnTab( nTab );
693 xRowNameRanges->DeleteOnTab( nTab );
694 pDBCollection->DeleteOnTab( nTab );
695 if (pDPCollection)
696 pDPCollection->DeleteOnTab( nTab );
697 if (pDetOpList)
698 pDetOpList->DeleteOnTab( nTab );
699 DeleteAreaLinksOnTab( nTab );
700
701 // normal reference update
702
703 aRange.aEnd.SetTab( static_cast<SCTAB>(maTabs.size())-1 );
704 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
705 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
706 if (pRangeName)
707 pRangeName->UpdateDeleteTab(aCxt);
708 pDBCollection->UpdateReference(
709 URM_INSDEL, 0,0,nTab, MaxCol(),MaxRow(),MAXTAB, 0,0,-1 );
710 if (pDPCollection)
711 pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
712 if (pDetOpList)
713 pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1 );
714 UpdateChartRef( URM_INSDEL, 0,0,nTab, MaxCol(),MaxRow(),MAXTAB, 0,0,-1 );
715 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1 );
716 if (pValidationList)
717 {
718 ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
719 pValidationList->UpdateDeleteTab(aCxt);
720 }
721 if ( pUnoBroadcaster )
722 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1 ) );
723
724 for (auto & pTab : maTabs)
725 if (pTab)
726 pTab->UpdateDeleteTab(aCxt);
727
728 maTabs.erase(maTabs.begin() + nTab);
729 // UpdateBroadcastAreas must be called between UpdateDeleteTab,
730 // which ends listening, and StartAllListeners, to not modify
731 // areas that are to be inserted by starting listeners.
732 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1);
733 for (const auto& a : maTabs)
734 {
735 if (a)
736 a->UpdateCompile();
737 }
738 // Excel-Filter deletes some Tables while loading, Listeners will
739 // only be triggered after the loading is done.
740 if ( !bInsertingFromOtherDoc )
741 {
742 StartAllListeners();
743
744 sc::SetFormulaDirtyContext aFormulaDirtyCxt;
745 SetAllFormulasDirty(aFormulaDirtyCxt);
746 }
747
748 if (comphelper::LibreOfficeKit::isActive())
749 {
750 ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>(this->GetDocumentShell()->GetModel());
751 SfxLokHelper::notifyDocumentSizeChangedAllViews(pModel);
752 }
753
754 bValid = true;
755 }
756 }
757 }
758 return bValid;
759}
760
761bool ScDocument::DeleteTabs( SCTAB nTab, SCTAB nSheets )
762{
763 bool bValid = false;
764 if (ValidTab(nTab) && (nTab + nSheets) <= static_cast<SCTAB>(maTabs.size()))
765 {
766 if (maTabs[nTab])
767 {
768 SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
769 if (nTabCount > nSheets)
770 {
771 sc::AutoCalcSwitch aACSwitch(*this, false);
772 sc::RefUpdateDeleteTabContext aCxt( *this, nTab, nSheets);
773
774 for (SCTAB aTab = 0; aTab < nSheets; ++aTab)
775 {
776 ScRange aRange( 0, 0, nTab, MaxCol(), MaxRow(), nTab + aTab );
777 DelBroadcastAreasInRange( aRange );
778
779 // #i8180# remove database ranges etc. that are on the deleted tab
780 // (restored in undo with ScRefUndoData)
781
782 xColNameRanges->DeleteOnTab( nTab + aTab );
783 xRowNameRanges->DeleteOnTab( nTab + aTab );
784 pDBCollection->DeleteOnTab( nTab + aTab );
785 if (pDPCollection)
786 pDPCollection->DeleteOnTab( nTab + aTab );
787 if (pDetOpList)
788 pDetOpList->DeleteOnTab( nTab + aTab );
789 DeleteAreaLinksOnTab( nTab + aTab );
790 }
791
792 if (pRangeName)
793 pRangeName->UpdateDeleteTab(aCxt);
794
795 // normal reference update
796
797 ScRange aRange( 0, 0, nTab, MaxCol(), MaxRow(), nTabCount - 1 );
798 xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1*nSheets );
799 xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1*nSheets );
800 pDBCollection->UpdateReference(
801 URM_INSDEL, 0,0,nTab, MaxCol(),MaxRow(),MAXTAB, 0,0,-1*nSheets );
802 if (pDPCollection)
803 pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1*nSheets );
804 if (pDetOpList)
805 pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1*nSheets );
806 UpdateChartRef( URM_INSDEL, 0,0,nTab, MaxCol(),MaxRow(),MAXTAB, 0,0,-1*nSheets );
807 UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1*nSheets );
808 if (pValidationList)
809 {
810 ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
811 pValidationList->UpdateDeleteTab(aCxt);
812 }
813 if ( pUnoBroadcaster )
814 pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1*nSheets ) );
815
816 for (auto & pTab : maTabs)
817 if (pTab)
818 pTab->UpdateDeleteTab(aCxt);
819
820 maTabs.erase(maTabs.begin() + nTab, maTabs.begin() + nTab + nSheets);
821 // UpdateBroadcastAreas must be called between UpdateDeleteTab,
822 // which ends listening, and StartAllListeners, to not modify
823 // areas that are to be inserted by starting listeners.
824 UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1*nSheets);
825 for (const auto& a : maTabs)
826 {
827 if (a)
828 a->UpdateCompile();
829 }
830 // Excel-Filter deletes some Tables while loading, Listeners will
831 // only be triggered after the loading is done.
832 if ( !bInsertingFromOtherDoc )
833 {
834 StartAllListeners();
835
836 sc::SetFormulaDirtyContext aFormulaDirtyCxt;
837 SetAllFormulasDirty(aFormulaDirtyCxt);
838 }
839
840 if (comphelper::LibreOfficeKit::isActive())
841 {
842 ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>(this->GetDocumentShell()->GetModel());
843 SfxLokHelper::notifyDocumentSizeChangedAllViews(pModel);
844 }
845
846 bValid = true;
847 }
848 }
849 }
850 return bValid;
851}
852
853bool ScDocument::RenameTab( SCTAB nTab, const OUString& rName, bool bExternalDocument )
854{
855 bool bValid = false;
856 SCTAB i;
857 if (ValidTab(nTab))
858 {
859 if (maTabs[nTab])
860 {
861 if ( bExternalDocument )
862 bValid = true; // composed name
863 else
864 bValid = ValidTabName(rName);
865 for (i=0; (i< static_cast<SCTAB>(maTabs.size())) && bValid; i++)
866 if (maTabs[i] && (i != nTab))
867 {
868 OUString aOldName = maTabs[i]->GetName();
869 bValid = !ScGlobal::GetpTransliteration()->isEqual( rName, aOldName );
870 }
871 if (bValid)
872 {
873 // #i75258# update charts before renaming, so they can get their live data objects.
874 // Once the charts are live, the sheet can be renamed without problems.
875 if ( pChartListenerCollection )
876 pChartListenerCollection->UpdateChartsContainingTab( nTab );
877 maTabs[nTab]->SetName(rName);
878
879 // If formulas refer to the renamed sheet, the TokenArray remains valid,
880 // but the XML stream must be re-generated.
881 for (const auto& a : maTabs)
882 {
883 if (a)
884 a->SetStreamValid( false );
885 }
886
887 if (comphelper::LibreOfficeKit::isActive() && GetDrawLayer())
888 {
889 ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>(this->GetDocumentShell()->GetModel());
890 SfxLokHelper::notifyDocumentSizeChangedAllViews(pModel);
891 }
892 }
893 }
894 }
895
896 collectUIInformation({{"NewName", rName}}, "Rename_Sheet");
897
898 return bValid;
899}
900
901void ScDocument::SetVisible( SCTAB nTab, bool bVisible )
902{
903 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
904 if (maTabs[nTab])
905 maTabs[nTab]->SetVisible(bVisible);
906}
907
908bool ScDocument::IsVisible( SCTAB nTab ) const
909{
910 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
911 if (maTabs[nTab])
912 return maTabs[nTab]->IsVisible();
913
914 return false;
915}
916
917bool ScDocument::IsStreamValid( SCTAB nTab ) const
918{
919 if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
920 return maTabs[nTab]->IsStreamValid();
921
922 return false;
923}
924
925void ScDocument::SetStreamValid( SCTAB nTab, bool bSet, bool bIgnoreLock )
926{
927 if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
928 maTabs[nTab]->SetStreamValid( bSet, bIgnoreLock );
929}
930
931void ScDocument::LockStreamValid( bool bLock )
932{
933 mbStreamValidLocked = bLock;
934}
935
936bool ScDocument::IsPendingRowHeights( SCTAB nTab ) const
937{
938 if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
939 return maTabs[nTab]->IsPendingRowHeights();
940
941 return false;
942}
943
944void ScDocument::SetPendingRowHeights( SCTAB nTab, bool bSet )
945{
946 if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
947 maTabs[nTab]->SetPendingRowHeights( bSet );
948}
949
950void ScDocument::SetLayoutRTL( SCTAB nTab, bool bRTL )
951{
952 if ( !(ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab]) )
953 return;
954
955 if ( bImportingXML )
956 {
957 // #i57869# only set the LoadingRTL flag, the real setting (including mirroring)
958 // is applied in SetImportingXML(false). This is so the shapes can be loaded in
959 // normal LTR mode.
960
961 maTabs[nTab]->SetLoadingRTL( bRTL );
962 return;
963 }
964
965 maTabs[nTab]->SetLayoutRTL( bRTL ); // only sets the flag
966 maTabs[nTab]->SetDrawPageSize();
967
968 // mirror existing objects:
969
970 if (!mpDrawLayer)
971 return;
972
973 SdrPage* pPage = mpDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
974 OSL_ENSURE(pPage,"Page ?")do { if (true && (!(pPage))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "974" ": "), "%s", "Page ?"); } } while (false)
;
975 if (!pPage)
976 return;
977
978 SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
979 SdrObject* pObject = aIter.Next();
980 while (pObject)
981 {
982 // objects with ScDrawObjData are re-positioned in SetPageSize,
983 // don't mirror again
984 ScDrawObjData* pData = ScDrawLayer::GetObjData( pObject );
985 if ( !pData )
986 mpDrawLayer->MirrorRTL( pObject );
987
988 pObject->SetContextWritingMode( bRTL ? WritingMode2::RL_TB : WritingMode2::LR_TB );
989
990 pObject = aIter.Next();
991 }
992}
993
994bool ScDocument::IsLayoutRTL( SCTAB nTab ) const
995{
996 if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
997 return maTabs[nTab]->IsLayoutRTL();
998
999 return false;
1000}
1001
1002bool ScDocument::IsNegativePage( SCTAB nTab ) const
1003{
1004 // Negative page area is always used for RTL layout.
1005 // The separate method is used to find all RTL handling of drawing objects.
1006 return IsLayoutRTL( nTab );
1007}
1008
1009/* ----------------------------------------------------------------------------
1010 used search area:
1011
1012 GetCellArea - Only Data
1013 GetTableArea - Data / Attributes
1014 GetPrintArea - intended for character objects,
1015 sweeps attributes all the way to bottom / right
1016---------------------------------------------------------------------------- */
1017
1018bool ScDocument::GetCellArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
1019{
1020 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
1021 if (maTabs[nTab])
1022 return maTabs[nTab]->GetCellArea( rEndCol, rEndRow );
1023
1024 rEndCol = 0;
1025 rEndRow = 0;
1026 return false;
1027}
1028
1029bool ScDocument::GetTableArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
1030{
1031 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
1032 if (maTabs[nTab])
1033 return maTabs[nTab]->GetTableArea( rEndCol, rEndRow );
1034
1035 rEndCol = 0;
1036 rEndRow = 0;
1037 return false;
1038}
1039
1040bool ScDocument::ShrinkToDataArea(SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow) const
1041{
1042 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB> (maTabs.size()) || !maTabs[nTab])
1043 return false;
1044
1045 SCCOL nCol1, nCol2;
1046 SCROW nRow1, nRow2;
1047 maTabs[nTab]->GetFirstDataPos(nCol1, nRow1);
1048 maTabs[nTab]->GetLastDataPos(nCol2, nRow2);
1049
1050 if (nCol1 > nCol2 || nRow1 > nRow2)
1051 // invalid range.
1052 return false;
1053
1054 // Make sure the area only shrinks, and doesn't grow.
1055 if (rStartCol < nCol1)
1056 rStartCol = nCol1;
1057 if (nCol2 < rEndCol)
1058 rEndCol = nCol2;
1059 if (rStartRow < nRow1)
1060 rStartRow = nRow1;
1061 if (nRow2 < rEndRow)
1062 rEndRow = nRow2;
1063
1064 if (rStartCol > rEndCol || rStartRow > rEndRow)
1065 // invalid range.
1066 return false;
1067
1068 return true; // success!
1069}
1070
1071bool ScDocument::ShrinkToUsedDataArea( bool& o_bShrunk, SCTAB nTab, SCCOL& rStartCol,
1072 SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly,
1073 bool bStickyTopRow, bool bStickyLeftCol, bool bConsiderCellNotes,
1074 bool bConsiderCellDrawObjects ) const
1075{
1076 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB> (maTabs.size()) || !maTabs[nTab])
1077 {
1078 o_bShrunk = false;
1079 return false;
1080 }
1081 return maTabs[nTab]->ShrinkToUsedDataArea( o_bShrunk, rStartCol, rStartRow, rEndCol, rEndRow,
1082 bColumnsOnly, bStickyTopRow, bStickyLeftCol, bConsiderCellNotes, bConsiderCellDrawObjects );
1083}
1084
1085SCROW ScDocument::GetLastDataRow( SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nLastRow ) const
1086{
1087 const ScTable* pTab = FetchTable(nTab);
1088 if (!pTab)
1089 return -1;
1090
1091 return pTab->GetLastDataRow(nCol1, nCol2, nLastRow);
1092}
1093
1094// connected area
1095
1096void ScDocument::GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
1097 SCCOL& rEndCol, SCROW& rEndRow, bool bIncludeOld, bool bOnlyDown ) const
1098{
1099 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab])
1100 maTabs[nTab]->GetDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bIncludeOld, bOnlyDown );
1101}
1102
1103bool ScDocument::GetDataAreaSubrange(ScRange& rRange) const
1104{
1105 SCTAB nTab = rRange.aStart.Tab();
1106 if (nTab != rRange.aEnd.Tab())
1107 return true;
1108
1109 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab])
1110 return maTabs[nTab]->GetDataAreaSubrange(rRange);
1111
1112 return true;
1113}
1114
1115void ScDocument::LimitChartArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
1116 SCCOL& rEndCol, SCROW& rEndRow )
1117{
1118 if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
1119 if (maTabs[nTab])
1120 maTabs[nTab]->LimitChartArea( rStartCol, rStartRow, rEndCol, rEndRow );
1121}
1122
1123void ScDocument::LimitChartIfAll( ScRangeListRef& rRangeList )
1124{
1125 ScRangeListRef aNew = new ScRangeList;
1126 if (rRangeList.is())
1127 {
1128 for ( size_t i = 0, nCount = rRangeList->size(); i < nCount; i++ )
1129 {
1130 ScRange aRange( (*rRangeList)[i] );
1131 if ( ( aRange.aStart.Col() == 0 && aRange.aEnd.Col() == MaxCol() ) ||
1132 ( aRange.aStart.Row() == 0 && aRange.aEnd.Row() == MaxRow() ) )
1133 {
1134 SCCOL nStartCol = aRange.aStart.Col();
1135 SCROW nStartRow = aRange.aStart.Row();
1136 SCCOL nEndCol = aRange.aEnd.Col();
1137 SCROW nEndRow = aRange.aEnd.Row();
1138 SCTAB nTab = aRange.aStart.Tab();
1139 if ( nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab])
1140 maTabs[nTab]->LimitChartArea(nStartCol, nStartRow, nEndCol, nEndRow);
1141 aRange.aStart.SetCol( nStartCol );
1142 aRange.aStart.SetRow( nStartRow );
1143 aRange.aEnd.SetCol( nEndCol );
1144 aRange.aEnd.SetRow( nEndRow );
1145 }
1146 aNew->push_back(aRange);
1147 }
1148 }
1149 else
1150 {
1151 OSL_FAIL("LimitChartIfAll: Ref==0")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "1151" ": "), "%s", "LimitChartIfAll: Ref==0"); } } while
(false)
;
1152 }
1153 rRangeList = aNew;
1154}
1155
1156static void lcl_GetFirstTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark, SCTAB aMaxTab )
1157{
1158 // without ScMarkData, leave start/end unchanged
1159 if ( !pTabMark )
1160 return;
1161
1162 for (SCTAB nTab=0; nTab< aMaxTab; ++nTab)
1163 if (pTabMark->GetTableSelect(nTab))
1164 {
1165 // find first range of consecutive selected sheets
1166 rTabRangeStart = pTabMark->GetFirstSelected();
1167 while ( nTab+1 < aMaxTab && pTabMark->GetTableSelect(nTab+1) )
1168 ++nTab;
1169 rTabRangeEnd = nTab;
1170 return;
1171 }
1172}
1173
1174static bool lcl_GetNextTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark, SCTAB aMaxTab )
1175{
1176 if ( pTabMark )
1177 {
1178 // find next range of consecutive selected sheets after rTabRangeEnd
1179 for (SCTAB nTab=rTabRangeEnd+1; nTab< aMaxTab; ++nTab)
1180 if (pTabMark->GetTableSelect(nTab))
1181 {
1182 rTabRangeStart = nTab;
1183 while ( nTab+1 < aMaxTab && pTabMark->GetTableSelect(nTab+1) )
1184 ++nTab;
1185 rTabRangeEnd = nTab;
1186 return true;
1187 }
1188 }
1189 return false;
1190}
1191
1192bool ScDocument::CanInsertRow( const ScRange& rRange ) const
1193{
1194 SCCOL nStartCol = rRange.aStart.Col();
1195 SCROW nStartRow = rRange.aStart.Row();
1196 SCTAB nStartTab = rRange.aStart.Tab();
1197 SCCOL nEndCol = rRange.aEnd.Col();
1198 SCROW nEndRow = rRange.aEnd.Row();
1199 SCTAB nEndTab = rRange.aEnd.Tab();
1200 PutInOrder( nStartCol, nEndCol );
1201 PutInOrder( nStartRow, nEndRow );
1202 PutInOrder( nStartTab, nEndTab );
1203 SCSIZE nSize = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
1204
1205 bool bTest = true;
1206 for (SCTAB i=nStartTab; i<=nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
1207 if (maTabs[i])
1208 bTest &= maTabs[i]->TestInsertRow( nStartCol, nEndCol, nStartRow, nSize );
1209
1210 return bTest;
1211}
1212
1213namespace {
1214
1215struct SetDirtyIfPostponedHandler
1216{
1217 void operator() (const ScTableUniquePtr & p)
1218 {
1219 if (p)
1220 p->SetDirtyIfPostponed();
1221 }
1222};
1223
1224struct BroadcastRecalcOnRefMoveHandler
1225{
1226 void operator() (const ScTableUniquePtr & p)
1227 {
1228 if (p)
1229 p->BroadcastRecalcOnRefMove();
1230 }
1231};
1232
1233struct BroadcastRecalcOnRefMoveGuard
1234{
1235 explicit BroadcastRecalcOnRefMoveGuard( ScDocument* pDoc ) :
1236 aSwitch( *pDoc, false),
1237 aBulk( pDoc->GetBASM(), SfxHintId::ScDataChanged)
1238 {
1239 }
1240
1241private:
1242 sc::AutoCalcSwitch aSwitch; // first for ctor/dtor order, destroy second
1243 ScBulkBroadcast aBulk; // second for ctor/dtor order, destroy first
1244};
1245
1246}
1247
1248bool ScDocument::InsertRow( SCCOL nStartCol, SCTAB nStartTab,
1249 SCCOL nEndCol, SCTAB nEndTab,
1250 SCROW nStartRow, SCSIZE nSize, ScDocument* pRefUndoDoc,
1251 const ScMarkData* pTabMark )
1252{
1253 SCTAB i;
1254
1255 PutInOrder( nStartCol, nEndCol );
1256 PutInOrder( nStartTab, nEndTab );
1257 if ( pTabMark )
1258 {
1259 nStartTab = 0;
1260 nEndTab = static_cast<SCTAB>(maTabs.size()) -1;
1261 }
1262
1263 bool bTest = true;
1264 bool bRet = false;
1265 bool bOldAutoCalc = GetAutoCalc();
1266 SetAutoCalc( false ); // avoid multiple calculations
1267 for ( i = nStartTab; i <= nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
1268 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1269 bTest &= maTabs[i]->TestInsertRow(nStartCol, nEndCol, nStartRow, nSize);
1270 if (bTest)
1271 {
1272 // UpdateBroadcastAreas have to be called before UpdateReference, so that entries
1273 // aren't shifted that would be rebuild at UpdateReference
1274
1275 // handle chunks of consecutive selected sheets together
1276 SCTAB nTabRangeStart = nStartTab;
1277 SCTAB nTabRangeEnd = nEndTab;
1278 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1279 ScRange aShiftedRange(nStartCol, nStartRow, nTabRangeStart, nEndCol, MaxRow(), nTabRangeEnd);
1280 sc::EndListeningContext aEndListenCxt(*this);
1281
1282 std::vector<ScAddress> aGroupPos;
1283 do
1284 {
1285 aShiftedRange.aStart.SetTab(nTabRangeStart);
1286 aShiftedRange.aEnd.SetTab(nTabRangeEnd);
1287
1288 // Collect all formula groups that will get split by the shifting,
1289 // and end all their listening. Record the position of the top
1290 // cell of the topmost group, and the position of the bottom cell
1291 // of the bottommost group.
1292 EndListeningIntersectedGroups(aEndListenCxt, aShiftedRange, &aGroupPos);
1293
1294 UpdateBroadcastAreas(URM_INSDEL, aShiftedRange, 0, static_cast<SCROW>(nSize), 0);
1295 }
1296 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1297
1298 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1299
1300 sc::RefUpdateContext aCxt(*this);
1301 aCxt.meMode = URM_INSDEL;
1302 aCxt.maRange = aShiftedRange;
1303 aCxt.mnRowDelta = nSize;
1304 do
1305 {
1306 aCxt.maRange.aStart.SetTab(nTabRangeStart);
1307 aCxt.maRange.aEnd.SetTab(nTabRangeEnd);
1308 UpdateReference(aCxt, pRefUndoDoc, false); // without drawing objects
1309 }
1310 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1311
1312 // UpdateReference should have set "needs listening" flags to those
1313 // whose references have been modified. We also need to set this flag
1314 // to those that were in the groups that got split by shifting.
1315 SetNeedsListeningGroups(aGroupPos);
1316
1317 for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
1318 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1319 maTabs[i]->InsertRow( nStartCol, nEndCol, nStartRow, nSize );
1320
1321 // UpdateRef for drawing layer must be after inserting,
1322 // when the new row heights are known.
1323 for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
1324 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1325 maTabs[i]->UpdateDrawRef( URM_INSDEL,
1326 nStartCol, nStartRow, nStartTab, nEndCol, MaxRow(), nEndTab,
1327 0, static_cast<SCROW>(nSize), 0 );
1328
1329 if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
1330 { // A new Listening is needed when references to deleted ranges are restored,
1331 // previous Listeners were removed in FormulaCell UpdateReference.
1332 StartAllListeners();
1333 }
1334 else
1335 { // Listeners have been removed in UpdateReference
1336 StartNeededListeners();
1337
1338 // At least all cells using range names pointing relative to the
1339 // moved range must be recalculated, and all cells marked postponed
1340 // dirty.
1341 for (const auto& a : maTabs)
1342 {
1343 if (a)
1344 a->SetDirtyIfPostponed();
1345 }
1346
1347 {
1348 BroadcastRecalcOnRefMoveGuard g(this);
1349 std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler());
1350 }
1351 }
1352 bRet = true;
1353 }
1354 SetAutoCalc( bOldAutoCalc );
1355 if ( bRet && pChartListenerCollection )
1356 pChartListenerCollection->UpdateDirtyCharts();
1357 return bRet;
1358}
1359
1360bool ScDocument::InsertRow( const ScRange& rRange )
1361{
1362 return InsertRow( rRange.aStart.Col(), rRange.aStart.Tab(),
1363 rRange.aEnd.Col(), rRange.aEnd.Tab(),
1364 rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1) );
1365}
1366
1367void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
1368 SCCOL nEndCol, SCTAB nEndTab,
1369 SCROW nStartRow, SCSIZE nSize,
1370 ScDocument* pRefUndoDoc, bool* pUndoOutline,
1371 const ScMarkData* pTabMark )
1372{
1373 SCTAB i;
1374
1375 PutInOrder( nStartCol, nEndCol );
1376 PutInOrder( nStartTab, nEndTab );
1377 if ( pTabMark )
1378 {
1379 nStartTab = 0;
1380 nEndTab = static_cast<SCTAB>(maTabs.size())-1;
1381 }
1382
1383 sc::AutoCalcSwitch aACSwitch(*this, false); // avoid multiple calculations
1384
1385 // handle chunks of consecutive selected sheets together
1386 SCTAB nTabRangeStart = nStartTab;
1387 SCTAB nTabRangeEnd = nEndTab;
1388 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1389 do
1390 {
1391 if ( ValidRow(nStartRow+nSize) )
1392 {
1393 DelBroadcastAreasInRange( ScRange(
1394 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1395 ScAddress( nEndCol, nStartRow+nSize-1, nTabRangeEnd ) ) );
1396 UpdateBroadcastAreas( URM_INSDEL, ScRange(
1397 ScAddress( nStartCol, nStartRow+nSize, nTabRangeStart ),
1398 ScAddress( nEndCol, MaxRow(), nTabRangeEnd )), 0, -static_cast<SCROW>(nSize), 0 );
1399 }
1400 else
1401 DelBroadcastAreasInRange( ScRange(
1402 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1403 ScAddress( nEndCol, MaxRow(), nTabRangeEnd ) ) );
1404 }
1405 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1406
1407 sc::RefUpdateContext aCxt(*this);
1408 const bool bLastRowIncluded = (static_cast<SCROW>(nStartRow + nSize) == GetSheetLimits().GetMaxRowCount() && ValidRow(nStartRow));
1409 if ( ValidRow(nStartRow+nSize) || bLastRowIncluded )
1410 {
1411 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1412 aCxt.meMode = URM_INSDEL;
1413 aCxt.mnRowDelta = -static_cast<SCROW>(nSize);
1414 if (bLastRowIncluded)
1415 {
1416 // Last row is included, shift a virtually non-existent row in.
1417 aCxt.maRange = ScRange( nStartCol, GetSheetLimits().GetMaxRowCount(), nTabRangeStart, nEndCol, GetSheetLimits().GetMaxRowCount(), nTabRangeEnd);
1418 }
1419 else
1420 {
1421 aCxt.maRange = ScRange( nStartCol, nStartRow+nSize, nTabRangeStart, nEndCol, MaxRow(), nTabRangeEnd);
1422 }
1423 do
1424 {
1425 UpdateReference(aCxt, pRefUndoDoc, true, false);
1426 }
1427 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1428 }
1429
1430 if (pUndoOutline)
1431 *pUndoOutline = false;
1432
1433 // Keep track of the positions of all formula groups that have been joined
1434 // during row deletion.
1435 std::vector<ScAddress> aGroupPos;
1436
1437 for ( i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
1438 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1439 maTabs[i]->DeleteRow(aCxt.maRegroupCols, nStartCol, nEndCol, nStartRow, nSize, pUndoOutline, &aGroupPos);
1440
1441 // Newly joined groups have some of their members still listening. We
1442 // need to make sure none of them are listening.
1443 EndListeningGroups(aGroupPos);
1444
1445 // Mark all joined groups for group listening.
1446 SetNeedsListeningGroups(aGroupPos);
1447
1448 if ( ValidRow(nStartRow+nSize) || bLastRowIncluded )
1449 {
1450 // Listeners have been removed in UpdateReference
1451 StartNeededListeners();
1452
1453 // At least all cells using range names pointing relative to the moved
1454 // range must be recalculated, and all cells marked postponed dirty.
1455 for (const auto& a : maTabs)
1456 {
1457 if (a)
1458 a->SetDirtyIfPostponed();
1459 }
1460
1461 {
1462 BroadcastRecalcOnRefMoveGuard g(this);
1463 std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler());
1464 }
1465 }
1466
1467 if (pChartListenerCollection)
1468 pChartListenerCollection->UpdateDirtyCharts();
1469}
1470
1471void ScDocument::DeleteRow( const ScRange& rRange )
1472{
1473 DeleteRow( rRange.aStart.Col(), rRange.aStart.Tab(),
1474 rRange.aEnd.Col(), rRange.aEnd.Tab(),
1475 rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1) );
1476}
1477
1478bool ScDocument::CanInsertCol( const ScRange& rRange ) const
1479{
1480 SCCOL nStartCol = rRange.aStart.Col();
1481 SCROW nStartRow = rRange.aStart.Row();
1482 SCTAB nStartTab = rRange.aStart.Tab();
1483 SCCOL nEndCol = rRange.aEnd.Col();
1484 SCROW nEndRow = rRange.aEnd.Row();
1485 SCTAB nEndTab = rRange.aEnd.Tab();
1486 PutInOrder( nStartCol, nEndCol );
1487 PutInOrder( nStartRow, nEndRow );
1488 PutInOrder( nStartTab, nEndTab );
1489 SCSIZE nSize = static_cast<SCSIZE>(nEndCol - nStartCol + 1);
1490
1491 bool bTest = true;
1492 for (SCTAB i=nStartTab; i<=nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
1493 if (maTabs[i])
1494 bTest &= maTabs[i]->TestInsertCol( nStartRow, nEndRow, nSize );
1495
1496 return bTest;
1497}
1498
1499bool ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
1500 SCROW nEndRow, SCTAB nEndTab,
1501 SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
1502 const ScMarkData* pTabMark )
1503{
1504 SCTAB i;
1505
1506 PutInOrder( nStartRow, nEndRow );
1507 PutInOrder( nStartTab, nEndTab );
1508 if ( pTabMark )
1509 {
1510 nStartTab = 0;
1511 nEndTab = static_cast<SCTAB>(maTabs.size())-1;
1512 }
1513
1514 bool bTest = true;
1515 bool bRet = false;
1516 bool bOldAutoCalc = GetAutoCalc();
1517 SetAutoCalc( false ); // avoid multiple calculations
1518 for ( i = nStartTab; i <= nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
1519 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1520 bTest &= maTabs[i]->TestInsertCol( nStartRow, nEndRow, nSize );
1521 if (bTest)
1522 {
1523 // handle chunks of consecutive selected sheets together
1524 SCTAB nTabRangeStart = nStartTab;
1525 SCTAB nTabRangeEnd = nEndTab;
1526 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1527 do
1528 {
1529 UpdateBroadcastAreas( URM_INSDEL, ScRange(
1530 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1531 ScAddress( MaxCol(), nEndRow, nTabRangeEnd )), static_cast<SCCOL>(nSize), 0, 0 );
1532 }
1533 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1534
1535 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1536
1537 sc::RefUpdateContext aCxt(*this);
1538 aCxt.meMode = URM_INSDEL;
1539 aCxt.maRange = ScRange(nStartCol, nStartRow, nTabRangeStart, MaxCol(), nEndRow, nTabRangeEnd);
1540 aCxt.mnColDelta = nSize;
1541 do
1542 {
1543 UpdateReference(aCxt, pRefUndoDoc, true, false);
1544 }
1545 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1546
1547 for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
1548 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1549 maTabs[i]->InsertCol(aCxt.maRegroupCols, nStartCol, nStartRow, nEndRow, nSize);
1550
1551 if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
1552 { // A new Listening is needed when references to deleted ranges are restored,
1553 // previous Listeners were removed in FormulaCell UpdateReference.
1554 StartAllListeners();
1555 }
1556 else
1557 {
1558 // Listeners have been removed in UpdateReference
1559 StartNeededListeners();
1560 // At least all cells using range names pointing relative to the
1561 // moved range must be recalculated, and all cells marked postponed
1562 // dirty.
1563 std::for_each(maTabs.begin(), maTabs.end(), SetDirtyIfPostponedHandler());
1564 // Cells containing functions such as CELL, COLUMN or ROW may have
1565 // changed their values on relocation. Broadcast them.
1566 {
1567 BroadcastRecalcOnRefMoveGuard g(this);
1568 std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler());
1569 }
1570 }
1571 bRet = true;
1572 }
1573 SetAutoCalc( bOldAutoCalc );
1574 if ( bRet && pChartListenerCollection )
1575 pChartListenerCollection->UpdateDirtyCharts();
1576 return bRet;
1577}
1578
1579bool ScDocument::InsertCol( const ScRange& rRange )
1580{
1581 return InsertCol( rRange.aStart.Row(), rRange.aStart.Tab(),
1582 rRange.aEnd.Row(), rRange.aEnd.Tab(),
1583 rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1) );
1584}
1585
1586void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTAB nEndTab,
1587 SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
1588 bool* pUndoOutline, const ScMarkData* pTabMark )
1589{
1590 SCTAB i;
1591
1592 PutInOrder( nStartRow, nEndRow );
1593 PutInOrder( nStartTab, nEndTab );
1594 if ( pTabMark )
1595 {
1596 nStartTab = 0;
1597 nEndTab = static_cast<SCTAB>(maTabs.size())-1;
1598 }
1599
1600 sc::AutoCalcSwitch aACSwitch(*this, false); // avoid multiple calculations
1601
1602 // handle chunks of consecutive selected sheets together
1603 SCTAB nTabRangeStart = nStartTab;
1604 SCTAB nTabRangeEnd = nEndTab;
1605 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1606 do
1607 {
1608 if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1609 {
1610 DelBroadcastAreasInRange( ScRange(
1611 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1612 ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize-1), nEndRow, nTabRangeEnd ) ) );
1613 UpdateBroadcastAreas( URM_INSDEL, ScRange(
1614 ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart ),
1615 ScAddress( MaxCol(), nEndRow, nTabRangeEnd )), -static_cast<SCCOL>(nSize), 0, 0 );
1616 }
1617 else
1618 DelBroadcastAreasInRange( ScRange(
1619 ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1620 ScAddress( MaxCol(), nEndRow, nTabRangeEnd ) ) );
1621 }
1622 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1623
1624 sc::RefUpdateContext aCxt(*this);
1625 const bool bLastColIncluded = (nStartCol + nSize == MAXCOLCOUNT && ValidCol(nStartCol));
1626 if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) || bLastColIncluded )
1627 {
1628 lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1629 aCxt.meMode = URM_INSDEL;
1630 aCxt.mnColDelta = -static_cast<SCCOL>(nSize);
1631 if (bLastColIncluded)
1632 {
1633 // Last column is included, shift a virtually non-existent column in.
1634 aCxt.maRange = ScRange( MAXCOLCOUNT, nStartRow, nTabRangeStart, MAXCOLCOUNT, nEndRow, nTabRangeEnd);
1635 }
1636 else
1637 {
1638 aCxt.maRange = ScRange( sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart,
1639 MaxCol(), nEndRow, nTabRangeEnd);
1640 }
1641 do
1642 {
1643 UpdateReference(aCxt, pRefUndoDoc, true, false);
1644 }
1645 while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1646 }
1647
1648 if (pUndoOutline)
1649 *pUndoOutline = false;
1650
1651 for (i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); ++i)
1652 {
1653 if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1654 maTabs[i]->DeleteCol(aCxt.maRegroupCols, nStartCol, nStartRow, nEndRow, nSize, pUndoOutline);
1655 }
1656
1657 if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) || bLastColIncluded )
1658 {
1659 // Listeners have been removed in UpdateReference
1660 StartNeededListeners();
1661
1662 // At least all cells using range names pointing relative to the moved
1663 // range must be recalculated, and all cells marked postponed dirty.
1664 for (const auto& a : maTabs)
1665 {
1666 if (a)
1667 a->SetDirtyIfPostponed();
1668 }
1669
1670 {
1671 BroadcastRecalcOnRefMoveGuard g(this);
1672 std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler());
1673 }
1674 }
1675
1676 if (pChartListenerCollection)
1677 pChartListenerCollection->UpdateDirtyCharts();
1678}
1679
1680void ScDocument::DeleteCol( const ScRange& rRange )
1681{
1682 DeleteCol( rRange.aStart.Row(), rRange.aStart.Tab(),
1683 rRange.aEnd.Row(), rRange.aEnd.Tab(),
1684 rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1) );
1685}
1686
1687// for Area-Links: Insert/delete cells, when the range is changed.
1688// (without Paint)
1689
1690static void lcl_GetInsDelRanges( const ScRange& rOld, const ScRange& rNew,
1691 ScRange& rColRange, bool& rInsCol, bool& rDelCol,
1692 ScRange& rRowRange, bool& rInsRow, bool& rDelRow )
1693{
1694 OSL_ENSURE( rOld.aStart == rNew.aStart, "FitBlock: Beginning is different" )do { if (true && (!(rOld.aStart == rNew.aStart))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "1694" ": "), "%s", "FitBlock: Beginning is different");
} } while (false)
;
1695
1696 rInsCol = rDelCol = rInsRow = rDelRow = false;
1697
1698 SCCOL nStartX = rOld.aStart.Col();
1699 SCROW nStartY = rOld.aStart.Row();
1700 SCCOL nOldEndX = rOld.aEnd.Col();
1701 SCROW nOldEndY = rOld.aEnd.Row();
1702 SCCOL nNewEndX = rNew.aEnd.Col();
1703 SCROW nNewEndY = rNew.aEnd.Row();
1704 SCTAB nTab = rOld.aStart.Tab();
1705
1706 // if more rows, columns are inserted/deleted at the old height.
1707 bool bGrowY = ( nNewEndY > nOldEndY );
1708 SCROW nColEndY = bGrowY ? nOldEndY : nNewEndY;
1709 SCCOL nRowEndX = bGrowY ? nNewEndX : nOldEndX;
1710
1711 // Columns
1712
1713 if ( nNewEndX > nOldEndX ) // Insert columns
1714 {
1715 rColRange = ScRange( nOldEndX+1, nStartY, nTab, nNewEndX, nColEndY, nTab );
1716 rInsCol = true;
1717 }
1718 else if ( nNewEndX < nOldEndX ) // Delete columns
1719 {
1720 rColRange = ScRange( nNewEndX+1, nStartY, nTab, nOldEndX, nColEndY, nTab );
1721 rDelCol = true;
1722 }
1723
1724 // Rows
1725
1726 if ( nNewEndY > nOldEndY ) // Insert rows
1727 {
1728 rRowRange = ScRange( nStartX, nOldEndY+1, nTab, nRowEndX, nNewEndY, nTab );
1729 rInsRow = true;
1730 }
1731 else if ( nNewEndY < nOldEndY ) // Delete rows
1732 {
1733 rRowRange = ScRange( nStartX, nNewEndY+1, nTab, nRowEndX, nOldEndY, nTab );
1734 rDelRow = true;
1735 }
1736}
1737
1738bool ScDocument::HasPartOfMerged( const ScRange& rRange )
1739{
1740 bool bPart = false;
1741 SCTAB nTab = rRange.aStart.Tab();
1742
1743 SCCOL nStartX = rRange.aStart.Col();
1744 SCROW nStartY = rRange.aStart.Row();
1745 SCCOL nEndX = rRange.aEnd.Col();
1746 SCROW nEndY = rRange.aEnd.Row();
1747
1748 if (HasAttrib( nStartX, nStartY, nTab, nEndX, nEndY, nTab,
1749 HasAttrFlags::Merged | HasAttrFlags::Overlapped ))
1750 {
1751 ExtendMerge( nStartX, nStartY, nEndX, nEndY, nTab );
1752 ExtendOverlapped( nStartX, nStartY, nEndX, nEndY, nTab );
1753
1754 bPart = ( nStartX != rRange.aStart.Col() || nEndX != rRange.aEnd.Col() ||
1755 nStartY != rRange.aStart.Row() || nEndY != rRange.aEnd.Row() );
1756 }
1757 return bPart;
1758}
1759
1760size_t ScDocument::GetFormulaHash( const ScAddress& rPos ) const
1761{
1762 SCTAB nTab = rPos.Tab();
1763 if (!ValidTab(nTab) || o3tl::make_unsigned(nTab) >= maTabs.size() || !maTabs[nTab])
1764 return 0;
1765
1766 return maTabs[nTab]->GetFormulaHash(rPos.Col(), rPos.Row());
1767}
1768
1769ScFormulaVectorState ScDocument::GetFormulaVectorState( const ScAddress& rPos ) const
1770{
1771 SCTAB nTab = rPos.Tab();
1772 if (!ValidTab(nTab) || o3tl::make_unsigned(nTab) >= maTabs.size() || !maTabs[nTab])
1773 return FormulaVectorUnknown;
1774
1775 return maTabs[nTab]->GetFormulaVectorState(rPos.Col(), rPos.Row());
1776}
1777
1778formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScAddress& rPos )
1779{
1780 SCTAB nTab = rPos.Tab();
1781 if (!TableExists(nTab))
1782 return formula::FormulaTokenRef();
1783
1784 return maTabs[nTab]->ResolveStaticReference(rPos.Col(), rPos.Row());
1785}
1786
1787formula::FormulaTokenRef ScDocument::ResolveStaticReference( const ScRange& rRange )
1788{
1789 SCTAB nTab = rRange.aStart.Tab();
1790 if (nTab != rRange.aEnd.Tab() || !TableExists(nTab))
1791 return formula::FormulaTokenRef();
1792
1793 return maTabs[nTab]->ResolveStaticReference(
1794 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
1795}
1796
1797formula::VectorRefArray ScDocument::FetchVectorRefArray( const ScAddress& rPos, SCROW nLength )
1798{
1799 SCTAB nTab = rPos.Tab();
1800 if (!TableExists(nTab))
1801 return formula::VectorRefArray();
1802
1803 return maTabs[nTab]->FetchVectorRefArray(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
1804}
1805
1806#ifdef DBG_UTIL
1807void ScDocument::AssertNoInterpretNeeded( const ScAddress& rPos, SCROW nLength )
1808{
1809 SCTAB nTab = rPos.Tab();
1810 assert(TableExists(nTab))(static_cast <bool> (TableExists(nTab)) ? void (0) : __assert_fail
("TableExists(nTab)", "/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
, 1810, __extension__ __PRETTY_FUNCTION__))
;
1811 return maTabs[nTab]->AssertNoInterpretNeeded(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
1812}
1813#endif
1814
1815void ScDocument::UnlockAdjustHeight()
1816{
1817 assert(nAdjustHeightLock > 0)(static_cast <bool> (nAdjustHeightLock > 0) ? void (
0) : __assert_fail ("nAdjustHeightLock > 0", "/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
, 1817, __extension__ __PRETTY_FUNCTION__))
;
1818 if(nAdjustHeightLock > 0)
1819 --nAdjustHeightLock;
1820}
1821
1822bool ScDocument::HandleRefArrayForParallelism( const ScAddress& rPos, SCROW nLength, const ScFormulaCellGroupRef& mxGroup )
1823{
1824 SCTAB nTab = rPos.Tab();
1825 if (!TableExists(nTab))
1826 return false;
1827
1828 return maTabs[nTab]->HandleRefArrayForParallelism(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1, mxGroup);
1829}
1830
1831bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
1832{
1833 if ( rOld == rNew )
1834 return true;
1835
1836 bool bOk = true;
1837 bool bInsCol,bDelCol,bInsRow,bDelRow;
1838 ScRange aColRange,aRowRange;
1839 lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
1840
1841 if ( bInsCol && !CanInsertCol( aColRange ) ) // Cells at the edge ?
1842 bOk = false;
1843 if ( bInsRow && !CanInsertRow( aRowRange ) ) // Cells at the edge ?
1844 bOk = false;
1845
1846 if ( bInsCol || bDelCol )
1847 {
1848 aColRange.aEnd.SetCol(MaxCol());
1849 if ( HasPartOfMerged(aColRange) )
1850 bOk = false;
1851 }
1852 if ( bInsRow || bDelRow )
1853 {
1854 aRowRange.aEnd.SetRow(MaxRow());
1855 if ( HasPartOfMerged(aRowRange) )
1856 bOk = false;
1857 }
1858
1859 return bOk;
1860}
1861
1862void ScDocument::FitBlock( const ScRange& rOld, const ScRange& rNew, bool bClear )
1863{
1864 if (bClear)
1865 DeleteAreaTab( rOld, InsertDeleteFlags::ALL );
1866
1867 bool bInsCol,bDelCol,bInsRow,bDelRow;
1868 ScRange aColRange,aRowRange;
1869 lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
1870
1871 if ( bInsCol )
1872 InsertCol( aColRange ); // First insert columns
1873 if ( bInsRow )
1874 InsertRow( aRowRange );
1875
1876 if ( bDelRow )
1877 DeleteRow( aRowRange ); // First delete rows
1878 if ( bDelCol )
1879 DeleteCol( aColRange );
1880
1881 // Expand references to inserted rows
1882
1883 if ( bInsCol || bInsRow )
1884 {
1885 ScRange aGrowSource = rOld;
1886 aGrowSource.aEnd.SetCol(std::min( rOld.aEnd.Col(), rNew.aEnd.Col() ));
1887 aGrowSource.aEnd.SetRow(std::min( rOld.aEnd.Row(), rNew.aEnd.Row() ));
1888 SCCOL nGrowX = bInsCol ? ( rNew.aEnd.Col() - rOld.aEnd.Col() ) : 0;
1889 SCROW nGrowY = bInsRow ? ( rNew.aEnd.Row() - rOld.aEnd.Row() ) : 0;
1890 UpdateGrow( aGrowSource, nGrowX, nGrowY );
1891 }
1892}
1893
1894void ScDocument::DeleteArea(
1895 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const ScMarkData& rMark,
1896 InsertDeleteFlags nDelFlag, bool bBroadcast, sc::ColumnSpanSet* pBroadcastSpans )
1897{
1898 sc::AutoCalcSwitch aACSwitch(*this, false);
1899
1900 PutInOrder( nCol1, nCol2 );
1901 PutInOrder( nRow1, nRow2 );
1902
1903 std::vector<ScAddress> aGroupPos;
1904 // Destroy and reconstruct listeners only if content is affected.
1905 bool bDelContent = ((nDelFlag & ~InsertDeleteFlags::CONTENTS) != nDelFlag);
1906 if (bDelContent)
1907 {
1908 // Record the positions of top and/or bottom formula groups that intersect
1909 // the area borders.
1910 sc::EndListeningContext aCxt(*this);
1911 ScRange aRange(nCol1, nRow1, 0, nCol2, nRow2, 0);
1912 for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); i++)
1913 {
1914 if (rMark.GetTableSelect(i))
1915 {
1916 aRange.aStart.SetTab(i);
1917 aRange.aEnd.SetTab(i);
1918
1919 EndListeningIntersectedGroups(aCxt, aRange, &aGroupPos);
1920 }
1921 }
1922 aCxt.purgeEmptyBroadcasters();
1923 }
1924
1925 for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); i++)
1926 if (maTabs[i])
1927 if ( rMark.GetTableSelect(i) || bIsUndo )
1928 maTabs[i]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag, bBroadcast, pBroadcastSpans);
1929
1930 if (!bDelContent)
1931 return;
1932
1933 // Re-start listeners on those top bottom groups that have been split.
1934 SetNeedsListeningGroups(aGroupPos);
1935 StartNeededListeners();
1936
1937 // If formula groups were split their listeners were destroyed and may
1938 // need to be notified now that they're restored, ScTable::DeleteArea()
1939 // couldn't do that.
1940 if (aGroupPos.empty())
1941 return;
1942
1943 ScRange aRange(nCol1, nRow1, 0, nCol2, nRow2, 0);
1944 for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); i++)
1945 {
1946 if (rMark.GetTableSelect(i))
1947 {
1948 aRange.aStart.SetTab(i);
1949 aRange.aEnd.SetTab(i);
1950 SetDirty( aRange, true);
1951 }
1952 }
1953}
1954
1955void ScDocument::DeleteAreaTab(SCCOL nCol1, SCROW nRow1,
1956 SCCOL nCol2, SCROW nRow2,
1957 SCTAB nTab, InsertDeleteFlags nDelFlag)
1958{
1959 PutInOrder( nCol1, nCol2 );
1960 PutInOrder( nRow1, nRow2 );
1961 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
1962 {
1963 bool bOldAutoCalc = GetAutoCalc();
1964 SetAutoCalc( false ); // avoid multiple calculations
1965 maTabs[nTab]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
1966 SetAutoCalc( bOldAutoCalc );
1967 }
1968}
1969
1970void ScDocument::DeleteAreaTab( const ScRange& rRange, InsertDeleteFlags nDelFlag )
1971{
1972 for ( SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); nTab++ )
1973 DeleteAreaTab( rRange.aStart.Col(), rRange.aStart.Row(),
1974 rRange.aEnd.Col(), rRange.aEnd.Row(),
1975 nTab, nDelFlag );
1976}
1977
1978void ScDocument::InitUndoSelected(const ScDocument& rSrcDoc, const ScMarkData& rTabSelection,
1979 bool bColInfo, bool bRowInfo )
1980{
1981 if (bIsUndo)
1982 {
1983 Clear();
1984
1985 SharePooledResources(&rSrcDoc);
1986
1987 for (SCTAB nTab = 0; nTab <= rTabSelection.GetLastSelected(); nTab++)
1988 if ( rTabSelection.GetTableSelect( nTab ) )
1989 {
1990 ScTableUniquePtr pTable(new ScTable(*this, nTab, OUString(), bColInfo, bRowInfo));
1991 if (nTab < static_cast<SCTAB>(maTabs.size()))
1992 maTabs[nTab] = std::move(pTable);
1993 else
1994 maTabs.push_back(std::move(pTable));
1995 }
1996 else
1997 {
1998 if (nTab < static_cast<SCTAB>(maTabs.size()))
1999 maTabs[nTab]=nullptr;
2000 else
2001 maTabs.push_back(nullptr);
2002 }
2003 }
2004 else
2005 {
2006 OSL_FAIL("InitUndo")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2006" ": "), "%s", "InitUndo"); } } while (false)
;
2007 }
2008}
2009
2010void ScDocument::InitUndo( const ScDocument& rSrcDoc, SCTAB nTab1, SCTAB nTab2,
2011 bool bColInfo, bool bRowInfo )
2012{
2013 if (!bIsUndo)
2014 {
2015 OSL_FAIL("InitUndo")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2015" ": "), "%s", "InitUndo"); } } while (false)
;
2016 return;
2017 }
2018
2019 Clear();
2020
2021 // Undo document shares its pooled resources with the source document.
2022 SharePooledResources(&rSrcDoc);
2023
2024 if (rSrcDoc.mpShell->GetMedium())
2025 maFileURL = rSrcDoc.mpShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
2026
2027 if ( nTab2 >= static_cast<SCTAB>(maTabs.size()))
2028 maTabs.resize(nTab2 + 1);
2029 for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
2030 {
2031 maTabs[nTab].reset(new ScTable(*this, nTab, OUString(), bColInfo, bRowInfo));
2032 }
2033}
2034
2035void ScDocument::AddUndoTab( SCTAB nTab1, SCTAB nTab2, bool bColInfo, bool bRowInfo )
2036{
2037 if (!bIsUndo)
2038 {
2039 OSL_FAIL("AddUndoTab")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2039" ": "), "%s", "AddUndoTab"); } } while (false)
;
2040 return;
2041 }
2042
2043 if (nTab2 >= static_cast<SCTAB>(maTabs.size()))
2044 {
2045 maTabs.resize(nTab2+1);
2046 }
2047
2048 for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
2049 if (!maTabs[nTab])
2050 {
2051 maTabs[nTab].reset( new ScTable(*this, nTab, OUString(), bColInfo, bRowInfo) );
2052 }
2053}
2054
2055void ScDocument::SetCutMode( bool bVal )
2056{
2057 if (bIsClip)
2058 GetClipParam().mbCutMode = bVal;
2059 else
2060 {
2061 OSL_FAIL("SetCutMode without bIsClip")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2061" ": "), "%s", "SetCutMode without bIsClip"); } } while
(false)
;
2062 }
2063}
2064
2065bool ScDocument::IsCutMode()
2066{
2067 if (bIsClip)
2068 return GetClipParam().mbCutMode;
2069 else
2070 {
2071 OSL_FAIL("IsCutMode without bIsClip")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2071" ": "), "%s", "IsCutMode without bIsClip"); } } while
(false)
;
2072 return false;
2073 }
2074}
2075
2076void ScDocument::CopyToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
2077 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
2078 InsertDeleteFlags nFlags, bool bOnlyMarked, ScDocument& rDestDoc,
2079 const ScMarkData* pMarks, bool bColRowFlags )
2080{
2081 if (ValidTab(nTab1) && ValidTab(nTab2))
2082 {
2083 ScRange aThisRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
2084 CopyToDocument(aThisRange, nFlags, bOnlyMarked, rDestDoc, pMarks, bColRowFlags);
2085 }
2086}
2087
2088void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
2089 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
2090 InsertDeleteFlags nFlags, bool bOnlyMarked, ScDocument& rDestDoc)
2091{
2092 PutInOrder( nCol1, nCol2 );
2093 PutInOrder( nRow1, nRow2 );
2094 PutInOrder( nTab1, nTab2 );
2095 if (!(ValidTab(nTab1) && ValidTab(nTab2)))
2096 return;
2097
2098 sc::AutoCalcSwitch aACSwitch(rDestDoc, false); // avoid multiple calculations
2099
2100 if (nTab1 > 0)
2101 CopyToDocument(0, 0, 0, MaxCol(), MaxRow(), nTab1-1, InsertDeleteFlags::FORMULA, false, rDestDoc);
2102
2103 sc::CopyToDocContext aCxt(rDestDoc);
2104 assert( nTab2 < static_cast<SCTAB>(maTabs.size()) && nTab2 < static_cast<SCTAB>(rDestDoc.maTabs.size()))(static_cast <bool> (nTab2 < static_cast<SCTAB>
(maTabs.size()) && nTab2 < static_cast<SCTAB>
(rDestDoc.maTabs.size())) ? void (0) : __assert_fail ("nTab2 < static_cast<SCTAB>(maTabs.size()) && nTab2 < static_cast<SCTAB>(rDestDoc.maTabs.size())"
, "/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
, 2104, __extension__ __PRETTY_FUNCTION__))
;
2105 for (SCTAB i = nTab1; i <= nTab2; i++)
2106 {
2107 if (maTabs[i] && rDestDoc.maTabs[i])
2108 maTabs[i]->UndoToTable(aCxt, nCol1, nRow1, nCol2, nRow2, nFlags,
2109 bOnlyMarked, rDestDoc.maTabs[i].get());
2110 }
2111
2112 if (nTab2 < MAXTAB)
2113 CopyToDocument(0, 0, nTab2+1, MaxCol(), MaxRow(), MAXTAB, InsertDeleteFlags::FORMULA, false, rDestDoc);
2114}
2115
2116void ScDocument::CopyToDocument(const ScRange& rRange,
2117 InsertDeleteFlags nFlags, bool bOnlyMarked, ScDocument& rDestDoc,
2118 const ScMarkData* pMarks, bool bColRowFlags)
2119{
2120 ScRange aNewRange = rRange;
2121 aNewRange.PutInOrder();
2122
2123 if (rDestDoc.aDocName.isEmpty())
2124 rDestDoc.aDocName = aDocName;
2125
2126 sc::AutoCalcSwitch aACSwitch(rDestDoc, false); // avoid multiple calculations
2127
2128 sc::CopyToDocContext aCxt(rDestDoc);
2129 aCxt.setStartListening(false);
2130
2131 SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), rDestDoc.maTabs.size()));
2132 for (SCTAB i = aNewRange.aStart.Tab(); i <= aNewRange.aEnd.Tab() && i < nMinSizeBothTabs; i++)
2133 {
2134 ScTable* pTab = FetchTable(i);
2135 ScTable* pDestTab = rDestDoc.FetchTable(i);
2136 if (!pTab || !pDestTab)
2137 continue;
2138
2139 pTab->CopyToTable(
2140 aCxt, aNewRange.aStart.Col(), aNewRange.aStart.Row(), aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
2141 nFlags, bOnlyMarked, pDestTab, pMarks, false, bColRowFlags,
2142 /*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true);
2143 }
2144
2145 rDestDoc.StartAllListeners(aNewRange);
2146}
2147
2148void ScDocument::UndoToDocument(const ScRange& rRange,
2149 InsertDeleteFlags nFlags, bool bOnlyMarked, ScDocument& rDestDoc)
2150{
2151 sc::AutoCalcSwitch aAutoCalcSwitch(*this, false);
2152
2153 ScRange aNewRange = rRange;
2154 aNewRange.PutInOrder();
2155 SCTAB nTab1 = aNewRange.aStart.Tab();
2156 SCTAB nTab2 = aNewRange.aEnd.Tab();
2157
2158 sc::CopyToDocContext aCxt(rDestDoc);
2159 if (nTab1 > 0)
2160 CopyToDocument(0, 0, 0, MaxCol(), MaxRow(), nTab1-1, InsertDeleteFlags::FORMULA, false, rDestDoc);
2161
2162 SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), rDestDoc.maTabs.size()));
2163 for (SCTAB i = nTab1; i <= nTab2 && i < nMinSizeBothTabs; i++)
2164 {
2165 if (maTabs[i] && rDestDoc.maTabs[i])
2166 maTabs[i]->UndoToTable(aCxt, aNewRange.aStart.Col(), aNewRange.aStart.Row(),
2167 aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
2168 nFlags, bOnlyMarked, rDestDoc.maTabs[i].get());
2169 }
2170
2171 if (nTab2 < static_cast<SCTAB>(maTabs.size()))
2172 CopyToDocument(0, 0 , nTab2+1, MaxCol(), MaxRow(), maTabs.size(), InsertDeleteFlags::FORMULA, false, rDestDoc);
2173}
2174
2175void ScDocument::CopyToClip(const ScClipParam& rClipParam,
2176 ScDocument* pClipDoc, const ScMarkData* pMarks,
2177 bool bKeepScenarioFlags, bool bIncludeObjects )
2178{
2179 OSL_ENSURE( pMarks, "CopyToClip: ScMarkData fails" )do { if (true && (!(pMarks))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2179" ": "), "%s", "CopyToClip: ScMarkData fails"); } }
while (false)
;
2180
2181 if (bIsClip)
2182 return;
2183
2184 if (!pClipDoc)
2185 {
2186 SAL_WARN("sc", "CopyToClip: no ClipDoc")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sc")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CopyToClip: no ClipDoc") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2186" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CopyToClip: no ClipDoc"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"CopyToClip: no ClipDoc"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2186" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CopyToClip: no ClipDoc") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2186" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CopyToClip: no ClipDoc"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"CopyToClip: no ClipDoc"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2186" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2187 pClipDoc = ScModule::GetClipDoc();
2188 }
2189
2190 if (mpShell->GetMedium())
2191 {
2192 pClipDoc->maFileURL = mpShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
2193 // for unsaved files use the title name and adjust during save of file
2194 if (pClipDoc->maFileURL.isEmpty())
2195 pClipDoc->maFileURL = mpShell->GetName();
2196 }
2197 else
2198 {
2199 pClipDoc->maFileURL = mpShell->GetName();
2200 }
2201
2202 //init maTabNames
2203 for (const auto& rxTab : maTabs)
2204 {
2205 if( rxTab )
2206 {
2207 OUString aTabName = rxTab->GetName();
2208 pClipDoc->maTabNames.push_back(aTabName);
2209 }
2210 else
2211 pClipDoc->maTabNames.emplace_back();
2212 }
2213
2214 pClipDoc->aDocName = aDocName;
2215 pClipDoc->SetClipParam(rClipParam);
2216 ScRange aClipRange = rClipParam.getWholeRange();
2217 SCTAB nEndTab = static_cast<SCTAB>(maTabs.size());
2218
2219 pClipDoc->ResetClip(this, pMarks);
2220
2221 sc::CopyToClipContext aCxt(*pClipDoc, bKeepScenarioFlags);
2222 CopyRangeNamesToClip(pClipDoc, aClipRange, pMarks);
2223
2224 for (SCTAB i = 0; i < nEndTab; ++i)
2225 {
2226 if (!maTabs[i] || i >= static_cast<SCTAB>(pClipDoc->maTabs.size()) || !pClipDoc->maTabs[i])
2227 continue;
2228
2229 if ( pMarks && !pMarks->GetTableSelect(i) )
2230 continue;
2231
2232 maTabs[i]->CopyToClip(aCxt, rClipParam.maRanges, pClipDoc->maTabs[i].get());
2233
2234 if (mpDrawLayer && bIncludeObjects)
2235 {
2236 // also copy drawing objects
2237 tools::Rectangle aObjRect = GetMMRect(
2238 aClipRange.aStart.Col(), aClipRange.aStart.Row(), aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i);
2239 mpDrawLayer->CopyToClip(pClipDoc, i, aObjRect);
2240 }
2241 }
2242
2243 // Make sure to mark overlapped cells.
2244 pClipDoc->ExtendMerge(aClipRange, true);
2245}
2246
2247void ScDocument::CopyStaticToDocument(const ScRange& rSrcRange, SCTAB nDestTab, ScDocument& rDestDoc)
2248{
2249 ScTable* pSrcTab = rSrcRange.aStart.Tab() < static_cast<SCTAB>(maTabs.size()) ? maTabs[rSrcRange.aStart.Tab()].get() : nullptr;
2250 ScTable* pDestTab = nDestTab < static_cast<SCTAB>(rDestDoc.maTabs.size()) ? rDestDoc.maTabs[nDestTab].get() : nullptr;
2251
2252 if (!pSrcTab || !pDestTab)
2253 return;
2254
2255 rDestDoc.GetFormatTable()->MergeFormatter(*GetFormatTable());
2256 SvNumberFormatterMergeMap aMap = rDestDoc.GetFormatTable()->ConvertMergeTableToMap();
2257
2258 pSrcTab->CopyStaticToDocument(
2259 rSrcRange.aStart.Col(), rSrcRange.aStart.Row(), rSrcRange.aEnd.Col(), rSrcRange.aEnd.Row(),
2260 aMap, pDestTab);
2261}
2262
2263void ScDocument::CopyCellToDocument( const ScAddress& rSrcPos, const ScAddress& rDestPos, ScDocument& rDestDoc )
2264{
2265 if (!TableExists(rSrcPos.Tab()) || !rDestDoc.TableExists(rDestPos.Tab()))
2266 return;
2267
2268 ScTable& rSrcTab = *maTabs[rSrcPos.Tab()];
2269 ScTable& rDestTab = *rDestDoc.maTabs[rDestPos.Tab()];
2270
2271 rSrcTab.CopyCellToDocument(rSrcPos.Col(), rSrcPos.Row(), rDestPos.Col(), rDestPos.Row(), rDestTab);
2272}
2273
2274void ScDocument::CopyTabToClip(SCCOL nCol1, SCROW nRow1,
2275 SCCOL nCol2, SCROW nRow2,
2276 SCTAB nTab, ScDocument* pClipDoc)
2277{
2278 if (bIsClip)
2279 return;
2280
2281 if (!pClipDoc)
2282 {
2283 SAL_WARN("sc", "CopyTabToClip: no ClipDoc")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sc")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CopyTabToClip: no ClipDoc") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2283" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CopyTabToClip: no ClipDoc"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"CopyTabToClip: no ClipDoc"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2283" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CopyTabToClip: no ClipDoc") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2283" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CopyTabToClip: no ClipDoc"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"CopyTabToClip: no ClipDoc"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2283" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2284 pClipDoc = ScModule::GetClipDoc();
2285 }
2286
2287 if (mpShell->GetMedium())
2288 {
2289 pClipDoc->maFileURL = mpShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
2290 // for unsaved files use the title name and adjust during save of file
2291 if (pClipDoc->maFileURL.isEmpty())
2292 pClipDoc->maFileURL = mpShell->GetName();
2293 }
2294 else
2295 {
2296 pClipDoc->maFileURL = mpShell->GetName();
2297 }
2298
2299 //init maTabNames
2300 for (const auto& rxTab : maTabs)
2301 {
2302 if( rxTab )
2303 {
2304 OUString aTabName = rxTab->GetName();
2305 pClipDoc->maTabNames.push_back(aTabName);
2306 }
2307 else
2308 pClipDoc->maTabNames.emplace_back();
2309 }
2310
2311 PutInOrder( nCol1, nCol2 );
2312 PutInOrder( nRow1, nRow2 );
2313
2314 ScClipParam& rClipParam = pClipDoc->GetClipParam();
2315 pClipDoc->aDocName = aDocName;
2316 rClipParam.maRanges.RemoveAll();
2317 rClipParam.maRanges.push_back(ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0));
2318 pClipDoc->ResetClip( this, nTab );
2319
2320 sc::CopyToClipContext aCxt(*pClipDoc, false);
2321 if (nTab < static_cast<SCTAB>(maTabs.size()) && nTab < static_cast<SCTAB>(pClipDoc->maTabs.size()))
2322 if (maTabs[nTab] && pClipDoc->maTabs[nTab])
2323 maTabs[nTab]->CopyToClip(aCxt, nCol1, nRow1, nCol2, nRow2, pClipDoc->maTabs[nTab].get());
2324
2325 pClipDoc->GetClipParam().mbCutMode = false;
2326}
2327
2328void ScDocument::TransposeClip( ScDocument* pTransClip, InsertDeleteFlags nFlags, bool bAsLink )
2329{
2330 OSL_ENSURE( bIsClip && pTransClip && pTransClip->bIsClip,do { if (true && (!(bIsClip && pTransClip &&
pTransClip->bIsClip))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2331" ": "), "%s", "TransposeClip with wrong Document")
; } } while (false)
2331 "TransposeClip with wrong Document" )do { if (true && (!(bIsClip && pTransClip &&
pTransClip->bIsClip))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2331" ": "), "%s", "TransposeClip with wrong Document")
; } } while (false)
;
2332
2333 // initialize
2334 // -> pTransClip has to be deleted before the original document!
2335
2336 pTransClip->ResetClip(this, nullptr); // all
2337
2338 // Take over range
2339
2340 if (pRangeName)
2341 {
2342 pTransClip->GetRangeName()->clear();
2343 for (const auto& rEntry : *pRangeName)
2344 {
2345 sal_uInt16 nIndex = rEntry.second->GetIndex();
2346 ScRangeData* pData = new ScRangeData(*rEntry.second);
2347 if (pTransClip->pRangeName->insert(pData))
2348 pData->SetIndex(nIndex);
2349 }
2350 }
2351
2352 // The data
2353
2354 ScRange aClipRange = GetClipParam().getWholeRange();
2355 if ( ValidRow(aClipRange.aEnd.Row()-aClipRange.aStart.Row()) )
2356 {
2357 for (SCTAB i=0; i< static_cast<SCTAB>(maTabs.size()); i++)
2358 if (maTabs[i])
2359 {
2360 OSL_ENSURE( pTransClip->maTabs[i], "TransposeClip: Table not there" )do { if (true && (!(pTransClip->maTabs[i]))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2360" ": "), "%s", "TransposeClip: Table not there"); }
} while (false)
;
2361 maTabs[i]->TransposeClip( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
2362 aClipRange.aEnd.Col(), aClipRange.aEnd.Row(),
2363 pTransClip->maTabs[i].get(), nFlags, bAsLink );
2364
2365 if ( mpDrawLayer && ( nFlags & InsertDeleteFlags::OBJECTS ) )
2366 {
2367 // Drawing objects are copied to the new area without transposing.
2368 // CopyFromClip is used to adjust the objects to the transposed block's
2369 // cell range area.
2370 // (mpDrawLayer in the original clipboard document is set only if there
2371 // are drawing objects to copy)
2372
2373 pTransClip->InitDrawLayer();
2374 tools::Rectangle aSourceRect = GetMMRect( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
2375 aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i );
2376 tools::Rectangle aDestRect = pTransClip->GetMMRect( 0, 0,
2377 static_cast<SCCOL>(aClipRange.aEnd.Row() - aClipRange.aStart.Row()),
2378 static_cast<SCROW>(aClipRange.aEnd.Col() - aClipRange.aStart.Col()), i );
2379 pTransClip->mpDrawLayer->CopyFromClip( mpDrawLayer.get(), i, aSourceRect, ScAddress(0,0,i), aDestRect );
2380 }
2381 }
2382
2383 pTransClip->SetClipParam(GetClipParam());
2384 pTransClip->GetClipParam().transpose();
2385 }
2386 else
2387 {
2388 SAL_WARN("sc", "TransposeClip: Too big")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sc")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "TransposeClip: Too big") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2388" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "TransposeClip: Too big"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"TransposeClip: Too big"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2388" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "TransposeClip: Too big") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2388" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "TransposeClip: Too big"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"TransposeClip: Too big"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2388" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2389 }
2390
2391 // This happens only when inserting...
2392
2393 GetClipParam().mbCutMode = false;
2394}
2395
2396namespace {
2397
2398void copyUsedNamesToClip(ScRangeName* pClipRangeName, ScRangeName* pRangeName,
2399 const sc::UpdatedRangeNames::NameIndicesType& rUsedNames)
2400{
2401 pClipRangeName->clear();
2402 for (const auto& rEntry : *pRangeName) //TODO: also DB and Pivot regions!!!
2403 {
2404 sal_uInt16 nIndex = rEntry.second->GetIndex();
2405 bool bInUse = (rUsedNames.count(nIndex) > 0);
2406 if (!bInUse)
2407 continue;
2408
2409 ScRangeData* pData = new ScRangeData(*rEntry.second);
2410 if (pClipRangeName->insert(pData))
2411 pData->SetIndex(nIndex);
2412 }
2413}
2414
2415}
2416
2417void ScDocument::CopyRangeNamesToClip(ScDocument* pClipDoc, const ScRange& rClipRange, const ScMarkData* pMarks)
2418{
2419 if (!pRangeName || pRangeName->empty())
2420 return;
2421
2422 sc::UpdatedRangeNames aUsedNames; // indexes of named ranges that are used in the copied cells
2423 SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), pClipDoc->maTabs.size()));
2424 for (SCTAB i = 0; i < nMinSizeBothTabs; ++i)
2425 if (maTabs[i] && pClipDoc->maTabs[i])
2426 if ( !pMarks || pMarks->GetTableSelect(i) )
2427 maTabs[i]->FindRangeNamesInUse(
2428 rClipRange.aStart.Col(), rClipRange.aStart.Row(),
2429 rClipRange.aEnd.Col(), rClipRange.aEnd.Row(), aUsedNames);
2430
2431 /* TODO: handle also sheet-local names */
2432 sc::UpdatedRangeNames::NameIndicesType aUsedGlobalNames( aUsedNames.getUpdatedNames(-1));
2433 copyUsedNamesToClip(pClipDoc->GetRangeName(), pRangeName.get(), aUsedGlobalNames);
2434}
2435
2436ScDocument::NumFmtMergeHandler::NumFmtMergeHandler(ScDocument& rDoc, const ScDocument& rSrcDoc)
2437 : mrDoc(rDoc)
2438{
2439 mrDoc.MergeNumberFormatter(rSrcDoc);
2440}
2441
2442ScDocument::NumFmtMergeHandler::~NumFmtMergeHandler()
2443{
2444 ScMutationGuard aGuard(mrDoc, ScMutationGuardFlags::CORE);
2445 mrDoc.pFormatExchangeList = nullptr;
2446}
2447
2448void ScDocument::PrepareFormulaCalc()
2449{
2450 ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
2451 mpFormulaGroupCxt.reset();
2452}
2453
2454SvtBroadcaster* ScDocument::GetBroadcaster( const ScAddress& rPos )
2455{
2456 ScTable* pTab = FetchTable(rPos.Tab());
2457 if (!pTab)
2458 return nullptr;
2459
2460 return pTab->GetBroadcaster(rPos.Col(), rPos.Row());
2461}
2462
2463const SvtBroadcaster* ScDocument::GetBroadcaster( const ScAddress& rPos ) const
2464{
2465 const ScTable* pTab = FetchTable(rPos.Tab());
2466 if (!pTab)
2467 return nullptr;
2468
2469 return pTab->GetBroadcaster(rPos.Col(), rPos.Row());
2470}
2471
2472void ScDocument::DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, const ScAddress& rTopPos, SCROW nLength )
2473{
2474 ScTable* pTab = FetchTable(rTopPos.Tab());
2475 if (!pTab || nLength <= 0)
2476 return;
2477
2478 pTab->DeleteBroadcasters(rBlockPos, rTopPos.Col(), rTopPos.Row(), rTopPos.Row()+nLength-1);
2479}
2480
2481#if DUMP_COLUMN_STORAGE0
2482void ScDocument::DumpColumnStorage( SCTAB nTab, SCCOL nCol ) const
2483{
2484 const ScTable* pTab = FetchTable(nTab);
2485 if (!pTab)
2486 return;
2487
2488 pTab->DumpColumnStorage(nCol);
2489}
2490#endif
2491
2492#if DEBUG_AREA_BROADCASTER0
2493void ScDocument::DumpAreaBroadcasters() const
2494{
2495 if (pBASM)
2496 pBASM->Dump();
2497}
2498#endif
2499
2500bool ScDocument::TableExists( SCTAB nTab ) const
2501{
2502 return ValidTab(nTab) && o3tl::make_unsigned(nTab) < maTabs.size() && maTabs[nTab];
2503}
2504
2505ScTable* ScDocument::FetchTable( SCTAB nTab )
2506{
2507 if (!TableExists(nTab))
2508 return nullptr;
2509
2510 return maTabs[nTab].get();
2511}
2512
2513const ScTable* ScDocument::FetchTable( SCTAB nTab ) const
2514{
2515 if (!TableExists(nTab))
2516 return nullptr;
2517
2518 return maTabs[nTab].get();
2519}
2520
2521ScColumnsRange ScDocument::GetColumnsRange( SCTAB nTab, SCCOL nColBegin, SCCOL nColEnd) const
2522{
2523 if (!TableExists(nTab))
2524 {
2525 std::vector<std::unique_ptr<ScColumn, o3tl::default_delete<ScColumn>>> aEmptyVector;
2526 return ScColumnsRange(ScColumnsRange::Iterator(aEmptyVector.begin()),
2527 ScColumnsRange::Iterator(aEmptyVector.end()));
2528 }
2529
2530 return maTabs[nTab]->GetColumnsRange(nColBegin, nColEnd);
2531}
2532
2533void ScDocument::MergeNumberFormatter(const ScDocument& rSrcDoc)
2534{
2535 SvNumberFormatter* pThisFormatter = mxPoolHelper->GetFormTable();
2536 SvNumberFormatter* pOtherFormatter = rSrcDoc.mxPoolHelper->GetFormTable();
2537 if (pOtherFormatter && pOtherFormatter != pThisFormatter)
2538 {
2539 SvNumberFormatterIndexTable* pExchangeList =
2540 pThisFormatter->MergeFormatter(*pOtherFormatter);
2541 if (!pExchangeList->empty())
2542 {
2543 ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
2544 pFormatExchangeList = pExchangeList;
2545 }
2546 }
2547}
2548
2549ScClipParam& ScDocument::GetClipParam()
2550{
2551 if (!mpClipParam)
2552 mpClipParam.reset(new ScClipParam);
2553
2554 return *mpClipParam;
2555}
2556
2557void ScDocument::SetClipParam(const ScClipParam& rParam)
2558{
2559 mpClipParam.reset(new ScClipParam(rParam));
2560}
2561
2562bool ScDocument::IsClipboardSource() const
2563{
2564 if (bIsClip || mpShell == nullptr || mpShell->IsLoading())
2565 return false;
2566
2567 ScDocument* pClipDoc = ScModule::GetClipDoc();
2568 return pClipDoc && pClipDoc->bIsClip && pClipDoc->mxPoolHelper.is() && mxPoolHelper.is() &&
2569 mxPoolHelper->GetDocPool() == pClipDoc->mxPoolHelper->GetDocPool();
2570}
2571
2572void ScDocument::StartListeningFromClip( SCCOL nCol1, SCROW nRow1,
2573 SCCOL nCol2, SCROW nRow2,
2574 const ScMarkData& rMark, InsertDeleteFlags nInsFlag )
2575{
2576 if (!(nInsFlag & InsertDeleteFlags::CONTENTS))
2577 return;
2578
2579 auto pSet = std::make_shared<sc::ColumnBlockPositionSet>(*this);
2580
2581 sc::StartListeningContext aStartCxt(*this, pSet);
2582 sc::EndListeningContext aEndCxt(*this, pSet, nullptr);
2583
2584 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
2585 for (const auto& rTab : rMark)
2586 {
2587 if (rTab >= nMax)
2588 break;
2589 if (maTabs[rTab])
2590 maTabs[rTab]->StartListeningFormulaCells(aStartCxt, aEndCxt, nCol1, nRow1, nCol2, nRow2);
2591 }
2592}
2593
2594void ScDocument::SetDirtyFromClip(
2595 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const ScMarkData& rMark,
2596 InsertDeleteFlags nInsFlag, sc::ColumnSpanSet& rBroadcastSpans )
2597{
2598 if (nInsFlag & InsertDeleteFlags::CONTENTS)
2599 {
2600 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
2601 for (const auto& rTab : rMark)
2602 {
2603 if (rTab >= nMax)
2604 break;
2605 if (maTabs[rTab])
2606 maTabs[rTab]->SetDirtyFromClip(nCol1, nRow1, nCol2, nRow2, rBroadcastSpans);
2607 }
2608 }
2609}
2610
2611bool ScDocument::InitColumnBlockPosition( sc::ColumnBlockPosition& rBlockPos, SCTAB nTab, SCCOL nCol )
2612{
2613 if (!TableExists(nTab))
2614 return false;
2615
2616 return maTabs[nTab]->InitColumnBlockPosition(rBlockPos, nCol);
2617}
2618
2619void ScDocument::CopyBlockFromClip(
2620 sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
2621 const ScMarkData& rMark, SCCOL nDx, SCROW nDy )
2622{
2623 TableContainer& rClipTabs = rCxt.getClipDoc()->maTabs;
2624 SCTAB nTabEnd = rCxt.getTabEnd();
2625 SCTAB nClipTab = 0;
2626 for (SCTAB i = rCxt.getTabStart(); i <= nTabEnd && i < static_cast<SCTAB>(maTabs.size()); i++)
2627 {
2628 if (maTabs[i] && rMark.GetTableSelect(i) )
2629 {
2630 while (!rClipTabs[nClipTab]) nClipTab = (nClipTab+1) % static_cast<SCTAB>(rClipTabs.size());
2631
2632 maTabs[i]->CopyFromClip(
2633 rCxt, nCol1, nRow1, nCol2, nRow2, nDx, nDy, rClipTabs[nClipTab].get());
2634
2635 if (rCxt.getClipDoc()->mpDrawLayer && (rCxt.getInsertFlag() & InsertDeleteFlags::OBJECTS))
2636 {
2637 // also copy drawing objects
2638
2639 // drawing layer must be created before calling CopyFromClip
2640 // (ScDocShell::MakeDrawLayer also does InitItems etc.)
2641 OSL_ENSURE( mpDrawLayer, "CopyBlockFromClip: No drawing layer" )do { if (true && (!(mpDrawLayer))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2641" ": "), "%s", "CopyBlockFromClip: No drawing layer"
); } } while (false)
;
2642 if ( mpDrawLayer )
2643 {
2644 // For GetMMRect, the row heights in the target document must already be valid
2645 // (copied in an extra step before pasting, or updated after pasting cells, but
2646 // before pasting objects).
2647
2648 tools::Rectangle aSourceRect = rCxt.getClipDoc()->GetMMRect(
2649 nCol1-nDx, nRow1-nDy, nCol2-nDx, nRow2-nDy, nClipTab );
2650 tools::Rectangle aDestRect = GetMMRect( nCol1, nRow1, nCol2, nRow2, i );
2651 mpDrawLayer->CopyFromClip(rCxt.getClipDoc()->mpDrawLayer.get(), nClipTab, aSourceRect,
2652 ScAddress( nCol1, nRow1, i ), aDestRect );
2653 }
2654 }
2655
2656 nClipTab = (nClipTab+1) % static_cast<SCTAB>(rClipTabs.size());
2657 }
2658 }
2659 if (!(rCxt.getInsertFlag() & InsertDeleteFlags::CONTENTS))
2660 return;
2661
2662 nClipTab = 0;
2663 for (SCTAB i = rCxt.getTabStart(); i <= nTabEnd && i < static_cast<SCTAB>(maTabs.size()); i++)
2664 {
2665 if (maTabs[i] && rMark.GetTableSelect(i) )
2666 {
2667 while (!rClipTabs[nClipTab]) nClipTab = (nClipTab+1) % static_cast<SCTAB>(rClipTabs.size());
2668 SCTAB nDz = i - nClipTab;
2669
2670 // ranges of consecutive selected tables (in clipboard and dest. doc)
2671 // must be handled in one UpdateReference call
2672 SCTAB nFollow = 0;
2673 while ( i + nFollow < nTabEnd
2674 && rMark.GetTableSelect( i + nFollow + 1 )
2675 && nClipTab + nFollow < MAXTAB
2676 && rClipTabs[(nClipTab + nFollow + 1) % static_cast<SCTAB>(rClipTabs.size())] )
2677 ++nFollow;
2678
2679 sc::RefUpdateContext aRefCxt(*this);
2680 aRefCxt.maRange = ScRange(nCol1, nRow1, i, nCol2, nRow2, i+nFollow);
2681 aRefCxt.mnColDelta = nDx;
2682 aRefCxt.mnRowDelta = nDy;
2683 aRefCxt.mnTabDelta = nDz;
2684 aRefCxt.setBlockPositionReference(rCxt.getBlockPositionSet()); // share mdds position caching
2685 if (rCxt.getClipDoc()->GetClipParam().mbCutMode)
2686 {
2687 // Update references only if cut originates from the same
2688 // document we are pasting into.
2689 if (rCxt.getClipDoc()->GetPool() == GetPool())
2690 {
2691 bool bOldInserting = IsInsertingFromOtherDoc();
2692 SetInsertingFromOtherDoc( true);
2693 aRefCxt.meMode = URM_MOVE;
2694 UpdateReference(aRefCxt, rCxt.getUndoDoc(), false);
2695
2696 // For URM_MOVE group listeners may have been removed,
2697 // re-establish them.
2698 if (!aRefCxt.maRegroupCols.empty())
2699 {
2700 /* TODO: holding the ColumnSet in a shared_ptr at
2701 * RefUpdateContext would eliminate the need of
2702 * copying it here. */
2703 auto pColSet = std::make_shared<sc::ColumnSet>( aRefCxt.maRegroupCols);
2704 StartNeededListeners( pColSet);
2705 }
2706
2707 SetInsertingFromOtherDoc( bOldInserting);
2708 }
2709 }
2710 else
2711 {
2712 aRefCxt.meMode = URM_COPY;
2713 UpdateReference(aRefCxt, rCxt.getUndoDoc(), false);
2714 }
2715
2716 nClipTab = (nClipTab+nFollow+1) % static_cast<SCTAB>(rClipTabs.size());
2717 i = sal::static_int_cast<SCTAB>( i + nFollow );
2718 }
2719 }
2720}
2721
2722void ScDocument::CopyNonFilteredFromClip(
2723 sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
2724 const ScMarkData& rMark, SCCOL nDx, SCROW & rClipStartRow )
2725{
2726 // call CopyBlockFromClip for ranges of consecutive non-filtered rows
2727 // nCol1/nRow1 etc. is in target doc
2728
2729 // filtered state is taken from first used table in clipboard (as in GetClipArea)
2730 SCTAB nFlagTab = 0;
2731 TableContainer& rClipTabs = rCxt.getClipDoc()->maTabs;
2732 while ( nFlagTab < static_cast<SCTAB>(rClipTabs.size()) && !rClipTabs[nFlagTab] )
2733 ++nFlagTab;
2734
2735 SCROW nSourceRow = rClipStartRow;
2736 SCROW nSourceEnd = 0;
2737 if (!rCxt.getClipDoc()->GetClipParam().maRanges.empty())
2738 nSourceEnd = rCxt.getClipDoc()->GetClipParam().maRanges.front().aEnd.Row();
2739 SCROW nDestRow = nRow1;
2740
2741 while ( nSourceRow <= nSourceEnd && nDestRow <= nRow2 )
2742 {
2743 // skip filtered rows
2744 nSourceRow = rCxt.getClipDoc()->FirstNonFilteredRow(nSourceRow, nSourceEnd, nFlagTab);
2745
2746 if ( nSourceRow <= nSourceEnd )
2747 {
2748 // look for more non-filtered rows following
2749 SCROW nLastRow = nSourceRow;
2750 (void)rCxt.getClipDoc()->RowFiltered(nSourceRow, nFlagTab, nullptr, &nLastRow);
2751 SCROW nFollow = nLastRow - nSourceRow;
2752
2753 if (nFollow > nSourceEnd - nSourceRow)
2754 nFollow = nSourceEnd - nSourceRow;
2755 if (nFollow > nRow2 - nDestRow)
2756 nFollow = nRow2 - nDestRow;
2757
2758 SCROW nNewDy = nDestRow - nSourceRow;
2759 CopyBlockFromClip(
2760 rCxt, nCol1, nDestRow, nCol2, nDestRow + nFollow, rMark, nDx, nNewDy);
2761
2762 nSourceRow += nFollow + 1;
2763 nDestRow += nFollow + 1;
2764 }
2765 }
2766 rClipStartRow = nSourceRow;
2767}
2768
2769namespace {
2770
2771class BroadcastAction : public sc::ColumnSpanSet::ColumnAction
2772{
2773 ScDocument& mrDoc;
2774 ScColumn* mpCol;
2775
2776public:
2777 explicit BroadcastAction( ScDocument& rDoc ) : mrDoc(rDoc), mpCol(nullptr) {}
2778
2779 virtual void startColumn( ScColumn* pCol ) override
2780 {
2781 mpCol = pCol;
2782 }
2783
2784 virtual void execute( SCROW nRow1, SCROW nRow2, bool bVal ) override
2785 {
2786 if (!bVal)
2787 return;
2788
2789 assert(mpCol)(static_cast <bool> (mpCol) ? void (0) : __assert_fail (
"mpCol", "/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
, 2789, __extension__ __PRETTY_FUNCTION__))
;
2790 ScRange aRange(mpCol->GetCol(), nRow1, mpCol->GetTab());
2791 aRange.aEnd.SetRow(nRow2);
2792 mrDoc.BroadcastCells(aRange, SfxHintId::ScDataChanged);
2793 };
2794};
2795
2796}
2797
2798void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMark,
2799 InsertDeleteFlags nInsFlag,
2800 ScDocument* pRefUndoDoc, ScDocument* pClipDoc, bool bResetCut,
2801 bool bAsLink, bool bIncludeFiltered, bool bSkipAttrForEmpty,
2802 const ScRangeList * pDestRanges )
2803{
2804 if (bIsClip)
1
Assuming field 'bIsClip' is false
2
Taking false branch
2805 return;
2806
2807 if (!pClipDoc)
3
Assuming 'pClipDoc' is non-null
4
Taking false branch
2808 {
2809 OSL_FAIL("CopyFromClip: no ClipDoc")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "2809" ": "), "%s", "CopyFromClip: no ClipDoc"); } } while
(false)
;
2810 pClipDoc = ScModule::GetClipDoc();
2811 }
2812
2813 if (!pClipDoc->bIsClip || !pClipDoc->GetTableCount())
5
Assuming field 'bIsClip' is true
6
Assuming the condition is false
7
Taking false branch
2814 return;
2815
2816 sc::AutoCalcSwitch aACSwitch(*this, false); // temporarily turn off auto calc.
2817
2818 NumFmtMergeHandler aNumFmtMergeHdl(*this, *pClipDoc);
2819
2820 SCCOL nAllCol1 = rDestRange.aStart.Col();
2821 SCROW nAllRow1 = rDestRange.aStart.Row();
2822 SCCOL nAllCol2 = rDestRange.aEnd.Col();
2823 SCROW nAllRow2 = rDestRange.aEnd.Row();
2824
2825 SCCOL nXw = 0;
2826 SCROW nYw = 0;
2827 ScRange aClipRange = pClipDoc->GetClipParam().getWholeRange();
2828 for (SCTAB nTab = 0; nTab < static_cast<SCTAB>(pClipDoc->maTabs.size()); nTab++) // find largest merge overlap
8
Assuming the condition is true
9
Loop condition is true. Entering loop body
11
Assuming the condition is false
12
Loop condition is false. Execution continues on line 2845
2829 if (pClipDoc->maTabs[nTab]) // all sheets of the clipboard content
10
Taking false branch
2830 {
2831 SCCOL nThisEndX = aClipRange.aEnd.Col();
2832 SCROW nThisEndY = aClipRange.aEnd.Row();
2833 pClipDoc->ExtendMerge( aClipRange.aStart.Col(),
2834 aClipRange.aStart.Row(),
2835 nThisEndX, nThisEndY, nTab );
2836 // only extra value from ExtendMerge
2837 nThisEndX = sal::static_int_cast<SCCOL>( nThisEndX - aClipRange.aEnd.Col() );
2838 nThisEndY = sal::static_int_cast<SCROW>( nThisEndY - aClipRange.aEnd.Row() );
2839 if ( nThisEndX > nXw )
2840 nXw = nThisEndX;
2841 if ( nThisEndY > nYw )
2842 nYw = nThisEndY;
2843 }
2844
2845 SCCOL nDestAddX;
13
'nDestAddX' declared without an initial value
2846 SCROW nDestAddY;
2847 pClipDoc->GetClipArea( nDestAddX, nDestAddY, bIncludeFiltered );
14
Calling 'ScDocument::GetClipArea'
20
Returning from 'ScDocument::GetClipArea'
2848 nXw = sal::static_int_cast<SCCOL>( nXw + nDestAddX );
21
The right operand of '+' is a garbage value
2849 nYw = sal::static_int_cast<SCROW>( nYw + nDestAddY ); // ClipArea, plus ExtendMerge value
2850
2851 /* Decide which contents to delete before copying. Delete all
2852 contents if nInsFlag contains any real content flag.
2853 #i102056# Notes are pasted from clipboard in a second pass,
2854 together with the special flag InsertDeleteFlags::ADDNOTES that states to not
2855 overwrite/delete existing cells but to insert the notes into
2856 these cells. In this case, just delete old notes from the
2857 destination area. */
2858 InsertDeleteFlags nDelFlag = InsertDeleteFlags::NONE;
2859 if ( (nInsFlag & (InsertDeleteFlags::CONTENTS | InsertDeleteFlags::ADDNOTES)) == (InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES) )
2860 nDelFlag |= InsertDeleteFlags::NOTE;
2861 else if ( nInsFlag & InsertDeleteFlags::CONTENTS )
2862 nDelFlag |= InsertDeleteFlags::CONTENTS;
2863
2864 if (nInsFlag & InsertDeleteFlags::ATTRIB)
2865 nDelFlag |= InsertDeleteFlags::ATTRIB;
2866
2867 sc::CopyFromClipContext aCxt(*this, pRefUndoDoc, pClipDoc, nInsFlag, bAsLink, bSkipAttrForEmpty);
2868 std::pair<SCTAB,SCTAB> aTabRanges = getMarkedTableRange(maTabs, rMark);
2869 aCxt.setTabRange(aTabRanges.first, aTabRanges.second);
2870 aCxt.setDeleteFlag(nDelFlag);
2871
2872 ScRangeList aLocalRangeList;
2873 if (!pDestRanges)
2874 {
2875 aLocalRangeList.push_back( rDestRange);
2876 pDestRanges = &aLocalRangeList;
2877 }
2878
2879 bInsertingFromOtherDoc = true; // No Broadcast/Listener created at Insert
2880
2881 sc::ColumnSpanSet aBroadcastSpans;
2882
2883 SCCOL nClipStartCol = aClipRange.aStart.Col();
2884 SCROW nClipStartRow = aClipRange.aStart.Row();
2885 SCROW nClipEndRow = aClipRange.aEnd.Row();
2886 for ( size_t nRange = 0; nRange < pDestRanges->size(); ++nRange )
2887 {
2888 const ScRange & rRange = (*pDestRanges)[nRange];
2889 SCCOL nCol1 = rRange.aStart.Col();
2890 SCROW nRow1 = rRange.aStart.Row();
2891 SCCOL nCol2 = rRange.aEnd.Col();
2892 SCROW nRow2 = rRange.aEnd.Row();
2893
2894 if (bSkipAttrForEmpty)
2895 {
2896 // Delete cells in the destination only if their corresponding clip cells are not empty.
2897 aCxt.setDestRange(nCol1, nRow1, nCol2, nRow2);
2898 DeleteBeforeCopyFromClip(aCxt, rMark, aBroadcastSpans);
2899 }
2900 else
2901 DeleteArea(nCol1, nRow1, nCol2, nRow2, rMark, nDelFlag, false, &aBroadcastSpans);
2902
2903 if (CopyOneCellFromClip(aCxt, nCol1, nRow1, nCol2, nRow2))
2904 continue;
2905
2906 SCCOL nC1 = nCol1;
2907 SCROW nR1 = nRow1;
2908 SCCOL nC2 = nC1 + nXw;
2909 if (nC2 > nCol2)
2910 nC2 = nCol2;
2911 SCROW nR2 = nR1 + nYw;
2912 if (nR2 > nRow2)
2913 nR2 = nRow2;
2914
2915 const SCCOLROW nThreshold = 8192;
2916 bool bPreallocatePattern = ((nInsFlag & InsertDeleteFlags::ATTRIB) && (nRow2 - nRow1 > nThreshold));
2917 std::vector< SCTAB > vTables;
2918
2919 if (bPreallocatePattern)
2920 {
2921 for (SCTAB i = aCxt.getTabStart(); i <= aCxt.getTabEnd(); ++i)
2922 if (maTabs[i] && rMark.GetTableSelect( i ) )
2923 vTables.push_back( i );
2924 }
2925
2926 do
2927 {
2928 // Pasting is done column-wise, when pasting to a filtered
2929 // area this results in partitioning and we have to
2930 // remember and reset the start row for each column until
2931 // it can be advanced for the next chunk of unfiltered
2932 // rows.
2933 SCROW nSaveClipStartRow = nClipStartRow;
2934 do
2935 {
2936 nClipStartRow = nSaveClipStartRow;
2937 SCCOL nDx = nC1 - nClipStartCol;
2938 SCROW nDy = nR1 - nClipStartRow;
2939 if ( bIncludeFiltered )
2940 {
2941 CopyBlockFromClip(
2942 aCxt, nC1, nR1, nC2, nR2, rMark, nDx, nDy);
2943 nClipStartRow += nR2 - nR1 + 1;
2944 }
2945 else
2946 {
2947 CopyNonFilteredFromClip(
2948 aCxt, nC1, nR1, nC2, nR2, rMark, nDx, nClipStartRow);
2949 }
2950 nC1 = nC2 + 1;
2951 nC2 = std::min(static_cast<SCCOL>(nC1 + nXw), nCol2);
2952 } while (nC1 <= nCol2);
2953 if (nClipStartRow > nClipEndRow)
2954 nClipStartRow = aClipRange.aStart.Row();
2955 nC1 = nCol1;
2956 nC2 = nC1 + nXw;
2957 if (nC2 > nCol2)
2958 nC2 = nCol2;
2959
2960 // Preallocate pattern memory once if further chunks are to be pasted.
2961 if (bPreallocatePattern && (nR2+1) <= nRow2)
2962 {
2963 SCROW nR3 = nR2 + 1;
2964 for (SCTAB nTab : vTables)
2965 {
2966 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
2967 {
2968 // Pattern count of the first chunk pasted.
2969 SCSIZE nChunk = GetPatternCount( nTab, nCol, nR1, nR2);
2970 // If it is only one pattern per chunk and chunks are
2971 // pasted consecutively then it will get its range
2972 // enlarged for each chunk and no further allocation
2973 // happens. For non-consecutive chunks we're out of
2974 // luck in this case.
2975 if (nChunk > 1)
2976 {
2977 SCSIZE nNeeded = nChunk * (nRow2 - nR3 + 1) / (nYw + 1);
2978 SCSIZE nRemain = GetPatternCount( nTab, nCol, nR3, nRow2);
2979 if (nNeeded > nRemain)
2980 {
2981 SCSIZE nCurr = GetPatternCount( nTab, nCol);
2982 ReservePatternCount( nTab, nCol, nCurr + nNeeded);
2983 }
2984 }
2985 }
2986 }
2987 bPreallocatePattern = false;
2988 }
2989
2990 nR1 = nR2 + 1;
2991 nR2 = std::min(static_cast<SCROW>(nR1 + nYw), nRow2);
2992 } while (nR1 <= nRow2);
2993 }
2994
2995 bInsertingFromOtherDoc = false;
2996
2997 // Create Listener after everything has been inserted
2998 StartListeningFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
2999
3000 {
3001 ScBulkBroadcast aBulkBroadcast( GetBASM(), SfxHintId::ScDataChanged);
3002
3003 // Set all formula cells dirty, and collect non-empty non-formula cell
3004 // positions so that we can broadcast on them below.
3005 SetDirtyFromClip(nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag, aBroadcastSpans);
3006
3007 BroadcastAction aAction(*this);
3008 aBroadcastSpans.executeColumnAction(*this, aAction);
3009 }
3010
3011 if (bResetCut)
3012 pClipDoc->GetClipParam().mbCutMode = false;
3013}
3014
3015void ScDocument::CopyMultiRangeFromClip(
3016 const ScAddress& rDestPos, const ScMarkData& rMark, InsertDeleteFlags nInsFlag, ScDocument* pClipDoc,
3017 bool bResetCut, bool bAsLink, bool /*bIncludeFiltered*/, bool bSkipAttrForEmpty)
3018{
3019 if (bIsClip)
3020 return;
3021
3022 if (!pClipDoc->bIsClip || !pClipDoc->GetTableCount())
3023 // There is nothing in the clip doc to copy.
3024 return;
3025
3026 // Right now, we don't allow pasting into filtered rows, so we don't even handle it here.
3027
3028 sc::AutoCalcSwitch aACSwitch(*this, false); // turn of auto calc temporarily.
3029 NumFmtMergeHandler aNumFmtMergeHdl(*this, *pClipDoc);
3030
3031 ScRange aDestRange;
3032 rMark.GetMarkArea(aDestRange);
3033
3034 bInsertingFromOtherDoc = true; // No Broadcast/Listener created at Insert
3035
3036 SCCOL nCol1 = rDestPos.Col();
3037 SCROW nRow1 = rDestPos.Row();
3038 ScClipParam& rClipParam = pClipDoc->GetClipParam();
3039
3040 sc::ColumnSpanSet aBroadcastSpans;
3041
3042 if (!bSkipAttrForEmpty)
3043 {
3044 // Do the deletion first.
3045 SCCOL nColSize = rClipParam.getPasteColSize();
3046 SCROW nRowSize = rClipParam.getPasteRowSize();
3047
3048 DeleteArea(nCol1, nRow1, nCol1+nColSize-1, nRow1+nRowSize-1, rMark, InsertDeleteFlags::CONTENTS, false, &aBroadcastSpans);
3049 }
3050
3051 sc::CopyFromClipContext aCxt(*this, nullptr, pClipDoc, nInsFlag, bAsLink, bSkipAttrForEmpty);
3052 std::pair<SCTAB,SCTAB> aTabRanges = getMarkedTableRange(maTabs, rMark);
3053 aCxt.setTabRange(aTabRanges.first, aTabRanges.second);
3054
3055 for (size_t i = 0, n = rClipParam.maRanges.size(); i < n; ++i)
3056 {
3057 const ScRange & rRange = rClipParam.maRanges[i];
3058
3059 SCROW nRowCount = rRange.aEnd.Row() - rRange.aStart.Row() + 1;
3060 SCCOL nDx = static_cast<SCCOL>(nCol1 - rRange.aStart.Col());
3061 SCROW nDy = static_cast<SCROW>(nRow1 - rRange.aStart.Row());
3062 SCCOL nCol2 = nCol1 + rRange.aEnd.Col() - rRange.aStart.Col();
3063 SCROW nEndRow = nRow1 + nRowCount - 1;
3064
3065 CopyBlockFromClip(aCxt, nCol1, nRow1, nCol2, nEndRow, rMark, nDx, nDy);
3066
3067 switch (rClipParam.meDirection)
3068 {
3069 case ScClipParam::Row:
3070 // Begin row for the next range being pasted.
3071 nRow1 += nRowCount;
3072 break;
3073 case ScClipParam::Column:
3074 nCol1 += rRange.aEnd.Col() - rRange.aStart.Col() + 1;
3075 break;
3076 default:
3077 ;
3078 }
3079 }
3080
3081 bInsertingFromOtherDoc = false;
3082
3083 // Create Listener after everything has been inserted
3084 StartListeningFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
3085 aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
3086
3087 {
3088 ScBulkBroadcast aBulkBroadcast( GetBASM(), SfxHintId::ScDataChanged);
3089
3090 // Set formula cells dirty and collect non-formula cells.
3091 SetDirtyFromClip(
3092 aDestRange.aStart.Col(), aDestRange.aStart.Row(), aDestRange.aEnd.Col(), aDestRange.aEnd.Row(),
3093 rMark, nInsFlag, aBroadcastSpans);
3094
3095 BroadcastAction aAction(*this);
3096 aBroadcastSpans.executeColumnAction(*this, aAction);
3097 }
3098
3099 if (bResetCut)
3100 pClipDoc->GetClipParam().mbCutMode = false;
3101}
3102
3103void ScDocument::SetClipArea( const ScRange& rArea, bool bCut )
3104{
3105 if (bIsClip)
3106 {
3107 ScClipParam& rClipParam = GetClipParam();
3108 rClipParam.maRanges.RemoveAll();
3109 rClipParam.maRanges.push_back(rArea);
3110 rClipParam.mbCutMode = bCut;
3111 }
3112 else
3113 {
3114 OSL_FAIL("SetClipArea: No Clip")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "3114" ": "), "%s", "SetClipArea: No Clip"); } } while (
false)
;
3115 }
3116}
3117
3118void ScDocument::GetClipArea(SCCOL& nClipX, SCROW& nClipY, bool bIncludeFiltered)
3119{
3120 if (!bIsClip)
15
Assuming field 'bIsClip' is false
16
Taking true branch
3121 {
3122 OSL_FAIL("GetClipArea: No Clip")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "3122" ": "), "%s", "GetClipArea: No Clip"); } } while (
false)
;
17
Taking true branch
18
Loop condition is false. Exiting loop
3123 return;
19
Returning without writing to 'nClipX'
3124 }
3125
3126 ScRangeList& rClipRanges = GetClipParam().maRanges;
3127 if (rClipRanges.empty())
3128 // No clip range. Bail out.
3129 return;
3130
3131 ScRange const & rRange = rClipRanges.front();
3132 SCCOL nStartCol = rRange.aStart.Col();
3133 SCCOL nEndCol = rRange.aEnd.Col();
3134 SCROW nStartRow = rRange.aStart.Row();
3135 SCROW nEndRow = rRange.aEnd.Row();
3136 for ( size_t i = 1, n = rClipRanges.size(); i < n; ++i )
3137 {
3138 ScRange const & rRange2 = rClipRanges[ i ];
3139 if (rRange2.aStart.Col() < nStartCol)
3140 nStartCol = rRange2.aStart.Col();
3141 if (rRange2.aStart.Row() < nStartRow)
3142 nStartRow = rRange2.aStart.Row();
3143 if (rRange2.aEnd.Col() > nEndCol)
3144 nEndCol = rRange2.aEnd.Col();
3145 if (rRange2.aEnd.Row() < nEndRow)
3146 nEndRow = rRange2.aEnd.Row();
3147 }
3148
3149 nClipX = nEndCol - nStartCol;
3150
3151 if ( bIncludeFiltered )
3152 nClipY = nEndRow - nStartRow;
3153 else
3154 {
3155 // count non-filtered rows
3156 // count on first used table in clipboard
3157 SCTAB nCountTab = 0;
3158 while ( nCountTab < static_cast<SCTAB>(maTabs.size()) && !maTabs[nCountTab] )
3159 ++nCountTab;
3160
3161 SCROW nResult = CountNonFilteredRows(nStartRow, nEndRow, nCountTab);
3162
3163 if ( nResult > 0 )
3164 nClipY = nResult - 1;
3165 else
3166 nClipY = 0; // always return at least 1 row
3167 }
3168}
3169
3170void ScDocument::GetClipStart(SCCOL& nClipX, SCROW& nClipY)
3171{
3172 if (bIsClip)
3173 {
3174 ScRangeList& rClipRanges = GetClipParam().maRanges;
3175 if ( !rClipRanges.empty() )
3176 {
3177 nClipX = rClipRanges.front().aStart.Col();
3178 nClipY = rClipRanges.front().aStart.Row();
3179 }
3180 }
3181 else
3182 {
3183 OSL_FAIL("GetClipStart: No Clip")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "3183" ": "), "%s", "GetClipStart: No Clip"); } } while (
false)
;
3184 }
3185}
3186
3187bool ScDocument::HasClipFilteredRows()
3188{
3189 // count on first used table in clipboard
3190 SCTAB nCountTab = 0;
3191 while ( nCountTab < static_cast<SCTAB>(maTabs.size()) && !maTabs[nCountTab] )
3192 ++nCountTab;
3193
3194 ScRangeList& rClipRanges = GetClipParam().maRanges;
3195 if ( rClipRanges.empty() )
3196 return false;
3197
3198 for ( size_t i = 0, n = rClipRanges.size(); i < n; ++i )
3199 {
3200 ScRange & rRange = rClipRanges[ i ];
3201 bool bAnswer = maTabs[nCountTab]->HasFilteredRows(rRange.aStart.Row(), rRange.aEnd.Row());
3202 if (bAnswer)
3203 return true;
3204 }
3205 return false;
3206}
3207
3208void ScDocument::MixDocument( const ScRange& rRange, ScPasteFunc nFunction, bool bSkipEmpty,
3209 ScDocument& rSrcDoc )
3210{
3211 SCTAB nTab1 = rRange.aStart.Tab();
3212 SCTAB nTab2 = rRange.aEnd.Tab();
3213 sc::MixDocContext aCxt(*this);
3214 SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), rSrcDoc.maTabs.size()));
3215 for (SCTAB i = nTab1; i <= nTab2 && i < nMinSizeBothTabs; i++)
3216 {
3217 ScTable* pTab = FetchTable(i);
3218 const ScTable* pSrcTab = rSrcDoc.FetchTable(i);
3219 if (!pTab || !pSrcTab)
3220 continue;
3221
3222 pTab->MixData(
3223 aCxt, rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(),
3224 nFunction, bSkipEmpty, pSrcTab);
3225 }
3226}
3227
3228void ScDocument::FillTab( const ScRange& rSrcArea, const ScMarkData& rMark,
3229 InsertDeleteFlags nFlags, ScPasteFunc nFunction,
3230 bool bSkipEmpty, bool bAsLink )
3231{
3232 InsertDeleteFlags nDelFlags = nFlags;
3233 if (nDelFlags & InsertDeleteFlags::CONTENTS)
3234 nDelFlags |= InsertDeleteFlags::CONTENTS; // Either all contents or delete nothing!
3235
3236 SCTAB nSrcTab = rSrcArea.aStart.Tab();
3237
3238 if (ValidTab(nSrcTab) && nSrcTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nSrcTab])
3239 {
3240 SCCOL nStartCol = rSrcArea.aStart.Col();
3241 SCROW nStartRow = rSrcArea.aStart.Row();
3242 SCCOL nEndCol = rSrcArea.aEnd.Col();
3243 SCROW nEndRow = rSrcArea.aEnd.Row();
3244 ScDocumentUniquePtr pMixDoc;
3245 bool bDoMix = ( bSkipEmpty || nFunction != ScPasteFunc::NONE ) && ( nFlags & InsertDeleteFlags::CONTENTS );
3246
3247 bool bOldAutoCalc = GetAutoCalc();
3248 SetAutoCalc( false ); // avoid multiple calculations
3249
3250 sc::CopyToDocContext aCxt(*this);
3251 sc::MixDocContext aMixDocCxt(*this);
3252
3253 SCTAB nCount = static_cast<SCTAB>(maTabs.size());
3254 for (const SCTAB& i : rMark)
3255 {
3256 if (i >= nCount)
3257 break;
3258 if (i != nSrcTab && maTabs[i])
3259 {
3260 if (bDoMix)
3261 {
3262 if (!pMixDoc)
3263 {
3264 pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
3265 pMixDoc->InitUndo( *this, i, i );
3266 }
3267 else
3268 pMixDoc->AddUndoTab( i, i );
3269
3270 // context used for copying content to the temporary mix document.
3271 sc::CopyToDocContext aMixCxt(*pMixDoc);
3272 maTabs[i]->CopyToTable(aMixCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3273 InsertDeleteFlags::CONTENTS, false, pMixDoc->maTabs[i].get(),
3274 /*pMarkData*/nullptr, /*bAsLink*/false, /*bColRowFlags*/true,
3275 /*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true );
3276 }
3277 maTabs[i]->DeleteArea( nStartCol,nStartRow, nEndCol,nEndRow, nDelFlags);
3278 maTabs[nSrcTab]->CopyToTable(aCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3279 nFlags, false, maTabs[i].get(), nullptr, bAsLink,
3280 /*bColRowFlags*/true, /*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true );
3281
3282 if (bDoMix)
3283 maTabs[i]->MixData(aMixDocCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3284 nFunction, bSkipEmpty, pMixDoc->maTabs[i].get() );
3285 }
3286 }
3287
3288 SetAutoCalc( bOldAutoCalc );
3289 }
3290 else
3291 {
3292 OSL_FAIL("wrong table")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "3292" ": "), "%s", "wrong table"); } } while (false)
;
3293 }
3294}
3295
3296void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
3297 InsertDeleteFlags nFlags, ScPasteFunc nFunction,
3298 bool bSkipEmpty, bool bAsLink )
3299{
3300 InsertDeleteFlags nDelFlags = nFlags;
3301 if (nDelFlags & InsertDeleteFlags::CONTENTS)
3302 nDelFlags |= InsertDeleteFlags::CONTENTS; // Either all contents or delete nothing!
3303
3304 if (ValidTab(nSrcTab) && nSrcTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nSrcTab])
3305 {
3306 ScDocumentUniquePtr pMixDoc;
3307 bool bDoMix = ( bSkipEmpty || nFunction != ScPasteFunc::NONE ) && ( nFlags & InsertDeleteFlags::CONTENTS );
3308
3309 bool bOldAutoCalc = GetAutoCalc();
3310 SetAutoCalc( false ); // avoid multiple calculations
3311
3312 ScRange aArea;
3313 rMark.GetMultiMarkArea( aArea );
3314 SCCOL nStartCol = aArea.aStart.Col();
3315 SCROW nStartRow = aArea.aStart.Row();
3316 SCCOL nEndCol = aArea.aEnd.Col();
3317 SCROW nEndRow = aArea.aEnd.Row();
3318
3319 sc::CopyToDocContext aCxt(*this);
3320 sc::MixDocContext aMixDocCxt(*this);
3321 SCTAB nCount = static_cast<SCTAB>(maTabs.size());
3322 for (const SCTAB& i : rMark)
3323 {
3324 if (i >= nCount)
3325 break;
3326 if ( i != nSrcTab && maTabs[i] )
3327 {
3328 if (bDoMix)
3329 {
3330 if (!pMixDoc)
3331 {
3332 pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
3333 pMixDoc->InitUndo( *this, i, i );
3334 }
3335 else
3336 pMixDoc->AddUndoTab( i, i );
3337
3338 sc::CopyToDocContext aMixCxt(*pMixDoc);
3339 maTabs[i]->CopyToTable(aMixCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3340 InsertDeleteFlags::CONTENTS, true, pMixDoc->maTabs[i].get(), &rMark,
3341 /*bAsLink*/false, /*bColRowFlags*/true, /*bGlobalNamesToLocal*/false,
3342 /*bCopyCaptions*/true );
3343 }
3344
3345 maTabs[i]->DeleteSelection( nDelFlags, rMark );
3346 maTabs[nSrcTab]->CopyToTable(aCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3347 nFlags, true, maTabs[i].get(), &rMark, bAsLink,
3348 /*bColRowFlags*/true, /*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true );
3349
3350 if (bDoMix)
3351 maTabs[i]->MixMarked(aMixDocCxt, rMark, nFunction, bSkipEmpty, pMixDoc->maTabs[i].get());
3352 }
3353 }
3354
3355 SetAutoCalc( bOldAutoCalc );
3356 }
3357 else
3358 {
3359 OSL_FAIL("wrong table")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "3359" ": "), "%s", "wrong table"); } } while (false)
;
3360 }
3361}
3362
3363bool ScDocument::SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString& rString,
3364 const ScSetStringParam* pParam )
3365{
3366 ScTable* pTab = FetchTable(nTab);
3367 if (!pTab)
3368 return false;
3369
3370 const ScFormulaCell* pCurCellFormula = pTab->GetFormulaCell(nCol, nRow);
3371 if (pCurCellFormula && pCurCellFormula->IsShared())
3372 {
3373 // In case setting this string affects an existing formula group, end
3374 // its listening to purge then empty cell broadcasters. Affected
3375 // remaining split group listeners will be set up again via
3376 // ScColumn::DetachFormulaCell() and
3377 // ScColumn::StartListeningUnshared().
3378
3379 sc::EndListeningContext aCxt(*this);
3380 ScAddress aPos(nCol, nRow, nTab);
3381 EndListeningIntersectedGroup(aCxt, aPos, nullptr);
3382 aCxt.purgeEmptyBroadcasters();
3383 }
3384
3385 return pTab->SetString(nCol, nRow, nTab, rString, pParam);
3386}
3387
3388bool ScDocument::SetString(
3389 const ScAddress& rPos, const OUString& rString, const ScSetStringParam* pParam )
3390{
3391 return SetString(rPos.Col(), rPos.Row(), rPos.Tab(), rString, pParam);
3392}
3393
3394bool ScDocument::SetEditText( const ScAddress& rPos, std::unique_ptr<EditTextObject> pEditText )
3395{
3396 if (!TableExists(rPos.Tab()))
3397 {
3398 return false;
3399 }
3400
3401 return maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), std::move(pEditText));
3402}
3403
3404void ScDocument::SetEditText( const ScAddress& rPos, const EditTextObject& rEditText, const SfxItemPool* pEditPool )
3405{
3406 if (!TableExists(rPos.Tab()))
3407 return;
3408
3409 maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), rEditText, pEditPool);
3410}
3411
3412void ScDocument::SetEditText( const ScAddress& rPos, const OUString& rStr )
3413{
3414 if (!TableExists(rPos.Tab()))
3415 return;
3416
3417 ScFieldEditEngine& rEngine = GetEditEngine();
3418 rEngine.SetTextCurrentDefaults(rStr);
3419 maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), rEngine.CreateTextObject());
3420}
3421
3422SCROW ScDocument::GetFirstEditTextRow( const ScRange& rRange ) const
3423{
3424 const ScTable* pTab = FetchTable(rRange.aStart.Tab());
3425 if (!pTab)
3426 return -1;
3427
3428 return pTab->GetFirstEditTextRow(rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
3429}
3430
3431void ScDocument::SetTextCell( const ScAddress& rPos, const OUString& rStr )
3432{
3433 if (!TableExists(rPos.Tab()))
3434 return;
3435
3436 if (ScStringUtil::isMultiline(rStr))
3437 {
3438 ScFieldEditEngine& rEngine = GetEditEngine();
3439 rEngine.SetTextCurrentDefaults(rStr);
3440 maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), rEngine.CreateTextObject());
3441 }
3442 else
3443 {
3444 ScSetStringParam aParam;
3445 aParam.setTextInput();
3446 maTabs[rPos.Tab()]->SetString(rPos.Col(), rPos.Row(), rPos.Tab(), rStr, &aParam);
3447 }
3448}
3449
3450void ScDocument::SetEmptyCell( const ScAddress& rPos )
3451{
3452 if (!TableExists(rPos.Tab()))
3453 return;
3454
3455 maTabs[rPos.Tab()]->SetEmptyCell(rPos.Col(), rPos.Row());
3456}
3457
3458void ScDocument::SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal )
3459{
3460 SetValue(ScAddress(nCol, nRow, nTab), rVal);
3461}
3462
3463void ScDocument::SetValue( const ScAddress& rPos, double fVal )
3464{
3465 ScTable* pTab = FetchTable(rPos.Tab());
3466 if (!pTab)
3467 return;
3468
3469 const ScFormulaCell* pCurCellFormula = pTab->GetFormulaCell(rPos.Col(), rPos.Row());
3470 if (pCurCellFormula && pCurCellFormula->IsShared())
3471 {
3472 // In case setting this value affects an existing formula group, end
3473 // its listening to purge then empty cell broadcasters. Affected
3474 // remaining split group listeners will be set up again via
3475 // ScColumn::DetachFormulaCell() and
3476 // ScColumn::StartListeningUnshared().
3477
3478 sc::EndListeningContext aCxt(*this);
3479 EndListeningIntersectedGroup(aCxt, rPos, nullptr);
3480 aCxt.purgeEmptyBroadcasters();
3481 }
3482
3483 pTab->SetValue(rPos.Col(), rPos.Row(), fVal);
3484}
3485
3486OUString ScDocument::GetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScInterpreterContext* pContext ) const
3487{
3488 if (TableExists(nTab))
3489 {
3490 OUString aStr;
3491 maTabs[nTab]->GetString(nCol, nRow, aStr, pContext);
3492 return aStr;
3493 }
3494 else
3495 return EMPTY_OUSTRINGScGlobal::GetEmptyOUString();
3496}
3497
3498OUString ScDocument::GetString( const ScAddress& rPos, const ScInterpreterContext* pContext ) const
3499{
3500 if (!TableExists(rPos.Tab()))
3501 return EMPTY_OUSTRINGScGlobal::GetEmptyOUString();
3502
3503 OUString aStr;
3504 maTabs[rPos.Tab()]->GetString(rPos.Col(), rPos.Row(), aStr, pContext);
3505 return aStr;
3506}
3507
3508double* ScDocument::GetValueCell( const ScAddress& rPos )
3509{
3510 if (!TableExists(rPos.Tab()))
3511 return nullptr;
3512
3513 return maTabs[rPos.Tab()]->GetValueCell(rPos.Col(), rPos.Row());
3514}
3515
3516svl::SharedString ScDocument::GetSharedString( const ScAddress& rPos ) const
3517{
3518 if (!TableExists(rPos.Tab()))
3519 return svl::SharedString();
3520
3521 return maTabs[rPos.Tab()]->GetSharedString(rPos.Col(), rPos.Row());
3522}
3523
3524std::shared_ptr<sc::FormulaGroupContext>& ScDocument::GetFormulaGroupContext()
3525{
3526 ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
3527 if (!mpFormulaGroupCxt)
3528 mpFormulaGroupCxt = std::make_shared<sc::FormulaGroupContext>();
3529
3530 return mpFormulaGroupCxt;
3531}
3532
3533void ScDocument::DiscardFormulaGroupContext()
3534{
3535 assert(!IsThreadedGroupCalcInProgress())(static_cast <bool> (!IsThreadedGroupCalcInProgress()) ?
void (0) : __assert_fail ("!IsThreadedGroupCalcInProgress()"
, "/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
, 3535, __extension__ __PRETTY_FUNCTION__))
;
3536 if( !mbFormulaGroupCxtBlockDiscard )
3537 mpFormulaGroupCxt.reset();
3538}
3539
3540void ScDocument::GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rString )
3541{
3542 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3543 maTabs[nTab]->GetInputString( nCol, nRow, rString );
3544 else
3545 rString.clear();
3546}
3547
3548FormulaError ScDocument::GetStringForFormula( const ScAddress& rPos, OUString& rString )
3549{
3550 // Used in formulas (add-in parameters etc), so it must use the same semantics as
3551 // ScInterpreter::GetCellString: always format values as numbers.
3552 // The return value is the error code.
3553
3554 ScRefCellValue aCell(*this, rPos);
3555 if (aCell.isEmpty())
3556 {
3557 rString = EMPTY_OUSTRINGScGlobal::GetEmptyOUString();
3558 return FormulaError::NONE;
3559 }
3560
3561 FormulaError nErr = FormulaError::NONE;
3562 OUString aStr;
3563 SvNumberFormatter* pFormatter = GetFormatTable();
3564 switch (aCell.meType)
3565 {
3566 case CELLTYPE_STRING:
3567 case CELLTYPE_EDIT:
3568 aStr = aCell.getString(this);
3569 break;
3570 case CELLTYPE_FORMULA:
3571 {
3572 ScFormulaCell* pFCell = aCell.mpFormula;
3573 nErr = pFCell->GetErrCode();
3574 if (pFCell->IsValue())
3575 {
3576 double fVal = pFCell->GetValue();
3577 sal_uInt32 nIndex = pFormatter->GetStandardFormat(
3578 SvNumFormatType::NUMBER,
3579 ScGlobal::eLnge);
3580 pFormatter->GetInputLineString(fVal, nIndex, aStr);
3581 }
3582 else
3583 aStr = pFCell->GetString().getString();
3584 }
3585 break;
3586 case CELLTYPE_VALUE:
3587 {
3588 double fVal = aCell.mfValue;
3589 sal_uInt32 nIndex = pFormatter->GetStandardFormat(
3590 SvNumFormatType::NUMBER,
3591 ScGlobal::eLnge);
3592 pFormatter->GetInputLineString(fVal, nIndex, aStr);
3593 }
3594 break;
3595 default:
3596 ;
3597 }
3598
3599 rString = aStr;
3600 return nErr;
3601}
3602
3603void ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, double& rValue ) const
3604{
3605 if (TableExists(nTab))
3606 rValue = maTabs[nTab]->GetValue( nCol, nRow );
3607 else
3608 rValue = 0.0;
3609}
3610
3611const EditTextObject* ScDocument::GetEditText( const ScAddress& rPos ) const
3612{
3613 SCTAB nTab = rPos.Tab();
3614 if (!TableExists(nTab))
3615 return nullptr;
3616
3617 return maTabs[nTab]->GetEditText(rPos.Col(), rPos.Row());
3618}
3619
3620void ScDocument::RemoveEditTextCharAttribs( const ScAddress& rPos, const ScPatternAttr& rAttr )
3621{
3622 if (!TableExists(rPos.Tab()))
3623 return;
3624
3625 return maTabs[rPos.Tab()]->RemoveEditTextCharAttribs(rPos.Col(), rPos.Row(), rAttr);
3626}
3627
3628double ScDocument::GetValue( const ScAddress& rPos ) const
3629{
3630 SCTAB nTab = rPos.Tab();
3631 if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3632 return maTabs[nTab]->GetValue(rPos.Col(), rPos.Row());
3633 return 0.0;
3634}
3635
3636double ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3637{
3638 ScAddress aAdr(nCol, nRow, nTab); return GetValue(aAdr);
3639}
3640
3641void ScDocument::GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab,
3642 sal_uInt32& rFormat ) const
3643{
3644 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
3645 if (maTabs[nTab])
3646 {
3647 rFormat = maTabs[nTab]->GetNumberFormat( nCol, nRow );
3648 return ;
3649 }
3650 rFormat = 0;
3651}
3652
3653sal_uInt32 ScDocument::GetNumberFormat( const ScRange& rRange ) const
3654{
3655 SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = rRange.aEnd.Tab();
3656 SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
3657 SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
3658
3659 if (!TableExists(nTab1) || !TableExists(nTab2))
3660 return 0;
3661
3662 sal_uInt32 nFormat = 0;
3663 bool bFirstItem = true;
3664 for (SCTAB nTab = nTab1; nTab <= nTab2 && nTab < static_cast<SCTAB>(maTabs.size()) ; ++nTab)
3665 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
3666 {
3667 sal_uInt32 nThisFormat = maTabs[nTab]->GetNumberFormat(nCol, nRow1, nRow2);
3668 if (bFirstItem)
3669 {
3670 nFormat = nThisFormat;
3671 bFirstItem = false;
3672 }
3673 else if (nThisFormat != nFormat)
3674 return 0;
3675 }
3676
3677 return nFormat;
3678}
3679
3680sal_uInt32 ScDocument::GetNumberFormat( const ScInterpreterContext& rContext, const ScAddress& rPos ) const
3681{
3682 SCTAB nTab = rPos.Tab();
3683 if (!TableExists(nTab))
3684 return 0;
3685
3686 return maTabs[nTab]->GetNumberFormat( rContext, rPos );
3687}
3688
3689void ScDocument::SetNumberFormat( const ScAddress& rPos, sal_uInt32 nNumberFormat )
3690{
3691 assert(!IsThreadedGroupCalcInProgress())(static_cast <bool> (!IsThreadedGroupCalcInProgress()) ?
void (0) : __assert_fail ("!IsThreadedGroupCalcInProgress()"
, "/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
, 3691, __extension__ __PRETTY_FUNCTION__))
;
3692 SCTAB nTab = rPos.Tab();
3693 if (!TableExists(nTab))
3694 return;
3695
3696 maTabs[nTab]->SetNumberFormat(rPos.Col(), rPos.Row(), nNumberFormat);
3697}
3698
3699void ScDocument::GetNumberFormatInfo( const ScInterpreterContext& rContext, SvNumFormatType& nType, sal_uInt32& nIndex,
3700 const ScAddress& rPos ) const
3701{
3702 SCTAB nTab = rPos.Tab();
3703 if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3704 {
3705 nIndex = maTabs[nTab]->GetNumberFormat( rContext, rPos );
3706 nType = rContext.GetNumberFormatType( nIndex );
3707 }
3708 else
3709 {
3710 nType = SvNumFormatType::UNDEFINED;
3711 nIndex = 0;
3712 }
3713}
3714
3715void ScDocument::GetFormula( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rFormula ) const
3716{
3717 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3718 maTabs[nTab]->GetFormula( nCol, nRow, rFormula );
3719 else
3720 rFormula.clear();
3721}
3722
3723const ScFormulaCell* ScDocument::GetFormulaCell( const ScAddress& rPos ) const
3724{
3725 if (!TableExists(rPos.Tab()))
3726 return nullptr;
3727
3728 return maTabs[rPos.Tab()]->GetFormulaCell(rPos.Col(), rPos.Row());
3729}
3730
3731ScFormulaCell* ScDocument::GetFormulaCell( const ScAddress& rPos )
3732{
3733 if (!TableExists(rPos.Tab()))
3734 return nullptr;
3735
3736 return maTabs[rPos.Tab()]->GetFormulaCell(rPos.Col(), rPos.Row());
3737}
3738
3739CellType ScDocument::GetCellType( const ScAddress& rPos ) const
3740{
3741 SCTAB nTab = rPos.Tab();
3742 if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3743 return maTabs[nTab]->GetCellType( rPos );
3744 return CELLTYPE_NONE;
3745}
3746
3747void ScDocument::GetCellType( SCCOL nCol, SCROW nRow, SCTAB nTab,
3748 CellType& rCellType ) const
3749{
3750 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
3751 rCellType = maTabs[nTab]->GetCellType( nCol, nRow );
3752 else
3753 rCellType = CELLTYPE_NONE;
3754}
3755
3756bool ScDocument::HasStringData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3757{
3758 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab]
3759 && nCol < maTabs[nTab]->GetAllocatedColumnsCount())
3760 return maTabs[nTab]->HasStringData( nCol, nRow );
3761 else
3762 return false;
3763}
3764
3765bool ScDocument::HasValueData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3766{
3767 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab]
3768 && nCol < maTabs[nTab]->GetAllocatedColumnsCount())
3769 return maTabs[nTab]->HasValueData( nCol, nRow );
3770 else
3771 return false;
3772}
3773
3774bool ScDocument::HasValueData( const ScAddress& rPos ) const
3775{
3776 return HasValueData(rPos.Col(), rPos.Row(), rPos.Tab());
3777}
3778
3779bool ScDocument::HasStringCells( const ScRange& rRange ) const
3780{
3781 // true, if String- or Edit cells in range
3782
3783 SCCOL nStartCol = rRange.aStart.Col();
3784 SCROW nStartRow = rRange.aStart.Row();
3785 SCTAB nStartTab = rRange.aStart.Tab();
3786 SCCOL nEndCol = rRange.aEnd.Col();
3787 SCROW nEndRow = rRange.aEnd.Row();
3788 SCTAB nEndTab = rRange.aEnd.Tab();
3789
3790 for ( SCTAB nTab=nStartTab; nTab<=nEndTab && nTab < static_cast<SCTAB>(maTabs.size()); nTab++ )
3791 if ( maTabs[nTab] && maTabs[nTab]->HasStringCells( nStartCol, nStartRow, nEndCol, nEndRow ) )
3792 return true;
3793
3794 return false;
3795}
3796
3797bool ScDocument::HasSelectionData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3798{
3799 sal_uInt32 nValidation = GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA )->GetValue();
3800 if( nValidation )
3801 {
3802 const ScValidationData* pData = GetValidationEntry( nValidation );
3803 if( pData && pData->HasSelectionList() )
3804 return true;
3805 }
3806 return HasStringCells( ScRange( nCol, 0, nTab, nCol, MaxRow(), nTab ) );
3807}
3808
3809bool ScDocument::HasValidationData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3810{
3811 sal_uInt32 nValidation = GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA )->GetValue();
3812 if( nValidation )
3813 {
3814 const ScValidationData* pData = GetValidationEntry( nValidation );
3815 if( pData && pData->GetDataMode() != ScValidationMode::SC_VALID_ANY )
3816 return true;
3817 }
3818 return false;
3819}
3820
3821void ScDocument::CheckVectorizationState()
3822{
3823 bool bOldAutoCalc = GetAutoCalc();
3824 bAutoCalc = false; // no multiple calculations
3825
3826 for (const auto& a : maTabs)
3827 {
3828 if (a)
3829 a->CheckVectorizationState();
3830 }
3831
3832 SetAutoCalc(bOldAutoCalc);
3833}
3834
3835void ScDocument::SetAllFormulasDirty( const sc::SetFormulaDirtyContext& rCxt )
3836{
3837 bool bOldAutoCalc = GetAutoCalc();
3838 bAutoCalc = false; // no multiple calculations
3839 { // scope for bulk broadcast
3840 ScBulkBroadcast aBulkBroadcast( GetBASM(), SfxHintId::ScDataChanged);
3841 for (const auto& a : maTabs)
3842 {
3843 if (a)
3844 a->SetAllFormulasDirty(rCxt);
3845 }
3846 }
3847
3848 // Although Charts are also set to dirty in Tracking without AutoCalc
3849 // if all formulas are dirty, the charts can no longer be caught
3850 // (#45205#) - that is why all Charts have to be explicitly handled again
3851 if (pChartListenerCollection)
3852 pChartListenerCollection->SetDirty();
3853
3854 SetAutoCalc( bOldAutoCalc );
3855}
3856
3857void ScDocument::SetDirty( const ScRange& rRange, bool bIncludeEmptyCells )
3858{
3859 bool bOldAutoCalc = GetAutoCalc();
3860 bAutoCalc = false; // no multiple calculations
3861 { // scope for bulk broadcast
3862 ScBulkBroadcast aBulkBroadcast( GetBASM(), SfxHintId::ScDataChanged);
3863 SCTAB nTab2 = rRange.aEnd.Tab();
3864 for (SCTAB i=rRange.aStart.Tab(); i<=nTab2 && i < static_cast<SCTAB>(maTabs.size()); i++)
3865 if (maTabs[i]) maTabs[i]->SetDirty( rRange,
3866 (bIncludeEmptyCells ? ScColumn::BROADCAST_BROADCASTERS : ScColumn::BROADCAST_DATA_POSITIONS));
3867
3868 /* TODO: this now also notifies conditional formatting and does a UNO
3869 * broadcast, which wasn't done here before. Is that an actually
3870 * desired side effect, or should we come up with a method that
3871 * doesn't? */
3872 if (bIncludeEmptyCells)
3873 BroadcastCells( rRange, SfxHintId::ScDataChanged, false);
3874 }
3875 SetAutoCalc( bOldAutoCalc );
3876}
3877
3878void ScDocument::SetTableOpDirty( const ScRange& rRange )
3879{
3880 bool bOldAutoCalc = GetAutoCalc();
3881 bAutoCalc = false; // no multiple recalculation
3882 SCTAB nTab2 = rRange.aEnd.Tab();
3883 for (SCTAB i=rRange.aStart.Tab(); i<=nTab2 && i < static_cast<SCTAB>(maTabs.size()); i++)
3884 if (maTabs[i]) maTabs[i]->SetTableOpDirty( rRange );
3885 SetAutoCalc( bOldAutoCalc );
3886}
3887
3888void ScDocument::InterpretDirtyCells( const ScRangeList& rRanges )
3889{
3890 if (!GetAutoCalc())
3891 return;
3892
3893 PrepareFormulaCalc();
3894
3895 for (size_t nPos=0, nRangeCount = rRanges.size(); nPos < nRangeCount; nPos++)
3896 {
3897 const ScRange& rRange = rRanges[nPos];
3898 for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
3899 {
3900 ScTable* pTab = FetchTable(nTab);
3901 if (!pTab)
3902 return;
3903
3904 pTab->InterpretDirtyCells(
3905 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
3906 }
3907 }
3908
3909 ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
3910 mpFormulaGroupCxt.reset();
3911}
3912
3913void ScDocument::AddTableOpFormulaCell( ScFormulaCell* pCell )
3914{
3915 if (m_TableOpList.empty())
3916 return;
3917
3918 ScInterpreterTableOpParams *const p = m_TableOpList.back();
3919 if ( p->bCollectNotifications )
3920 {
3921 if ( p->bRefresh )
3922 { // refresh pointers only
3923 p->aNotifiedFormulaCells.push_back( pCell );
3924 }
3925 else
3926 { // init both, address and pointer
3927 p->aNotifiedFormulaCells.push_back( pCell );
3928 p->aNotifiedFormulaPos.push_back( pCell->aPos );
3929 }
3930 }
3931}
3932
3933void ScDocument::CalcAll()
3934{
3935 PrepareFormulaCalc();
3936 ClearLookupCaches(); // Ensure we don't deliver zombie data.
3937 sc::AutoCalcSwitch aSwitch(*this, true);
3938 for (const auto& a : maTabs)
3939 {
3940 if (a)
3941 a->SetDirtyVar();
3942 }
3943 for (const auto& a : maTabs)
3944 {
3945 if (a)
3946 a->CalcAll();
3947 }
3948 ClearFormulaTree();
3949
3950 // In eternal hard recalc state caches were not added as listeners,
3951 // invalidate them so the next non-CalcAll() normal lookup will not be
3952 // presented with outdated data.
3953 if (GetHardRecalcState() == HardRecalcState::ETERNAL)
3954 ClearLookupCaches();
3955}
3956
3957void ScDocument::CompileAll()
3958{
3959 sc::CompileFormulaContext aCxt(*this);
3960 for (const auto& a : maTabs)
3961 {
3962 if (a)
3963 a->CompileAll(aCxt);
3964 }
3965
3966 sc::SetFormulaDirtyContext aFormulaDirtyCxt;
3967 SetAllFormulasDirty(aFormulaDirtyCxt);
3968}
3969
3970void ScDocument::CompileXML()
3971{
3972 bool bOldAutoCalc = GetAutoCalc();
3973 SetAutoCalc( false );
3974 ScProgress aProgress( GetDocumentShell(), ScResId(
3975 STR_PROGRESS_CALCULATINGreinterpret_cast<char const *>("STR_PROGRESS_CALCULATING"
"\004" u8"calculating")
), GetXMLImportedFormulaCount(), true );
3976
3977 sc::CompileFormulaContext aCxt(*this);
3978
3979 // set AutoNameCache to speed up automatic name lookup
3980 OSL_ENSURE( !pAutoNameCache, "AutoNameCache already set" )do { if (true && (!(!pAutoNameCache))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "3980" ": "), "%s", "AutoNameCache already set"); } } while
(false)
;
3981 pAutoNameCache.reset( new ScAutoNameCache( *this ) );
3982
3983 if (pRangeName)
3984 pRangeName->CompileUnresolvedXML(aCxt);
3985
3986 std::for_each(maTabs.begin(), maTabs.end(),
3987 [&](ScTableUniquePtr & pTab)
3988 {
3989 if (pTab)
3990 pTab->CompileXML(aCxt, aProgress);
3991 }
3992 );
3993 StartAllListeners();
3994
3995 pAutoNameCache.reset(); // valid only during CompileXML, where cell contents don't change
3996
3997 if ( pValidationList )
3998 {
3999 ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
4000 pValidationList->CompileXML();
4001 }
4002
4003 // Track all formula cells that were appended to the FormulaTrack during
4004 // import or CompileXML().
4005 TrackFormulas();
4006
4007 SetAutoCalc( bOldAutoCalc );
4008}
4009
4010bool ScDocument::CompileErrorCells(FormulaError nErrCode)
4011{
4012 bool bCompiled = false;
4013 sc::CompileFormulaContext aCxt(*this);
4014 for (const auto& a : maTabs)
4015 {
4016 if (!a)
4017 continue;
4018
4019 if (a->CompileErrorCells(aCxt, nErrCode))
4020 bCompiled = true;
4021 }
4022
4023 return bCompiled;
4024}
4025
4026void ScDocument::CalcAfterLoad( bool bStartListening )
4027{
4028 if (bIsClip) // Excel data is loaded from the Clipboard to a Clip-Doc
4029 return; // the calculation is then only performed when inserting into the real document
4030
4031 bCalcingAfterLoad = true;
4032 sc::CompileFormulaContext aCxt(*this);
4033 {
4034 for (const auto& a : maTabs)
4035 {
4036 if (a)
4037 a->CalcAfterLoad(aCxt, bStartListening);
4038 }
4039 for (const auto& a : maTabs)
4040 {
4041 if (a)
4042 a->SetDirtyAfterLoad();
4043 }
4044 }
4045 bCalcingAfterLoad = false;
4046
4047 SetDetectiveDirty(false); // No real changes yet
4048
4049 // #i112436# If formula cells are already dirty, they don't broadcast further changes.
4050 // So the source ranges of charts must be interpreted even if they are not visible,
4051 // similar to ScMyShapeResizer::CreateChartListener for loading own files (i104899).
4052 if (pChartListenerCollection)
4053 {
4054 const ScChartListenerCollection::ListenersType& rListeners = pChartListenerCollection->getListeners();
4055 for (auto const& it : rListeners)
4056 {
4057 const ScChartListener *const p = it.second.get();
4058 InterpretDirtyCells(*p->GetRangeList());
4059 }
4060 }
4061}
4062
4063FormulaError ScDocument::GetErrCode( const ScAddress& rPos ) const
4064{
4065 SCTAB nTab = rPos.Tab();
4066 if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4067 return maTabs[nTab]->GetErrCode( rPos );
4068 return FormulaError::NONE;
4069}
4070
4071void ScDocument::ResetChanged( const ScRange& rRange )
4072{
4073 SCTAB nTabSize = static_cast<SCTAB>(maTabs.size());
4074 SCTAB nTab1 = rRange.aStart.Tab();
4075 SCTAB nTab2 = rRange.aEnd.Tab();
4076 for (SCTAB nTab = nTab1; nTab1 <= nTab2 && nTab < nTabSize; ++nTab)
4077 if (maTabs[nTab])
4078 maTabs[nTab]->ResetChanged(rRange);
4079}
4080
4081// Column widths / Row heights --------------------------------------
4082
4083void ScDocument::SetColWidth( SCCOL nCol, SCTAB nTab, sal_uInt16 nNewWidth )
4084{
4085 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4086 maTabs[nTab]->SetColWidth( nCol, nNewWidth );
4087}
4088
4089void ScDocument::SetColWidthOnly( SCCOL nCol, SCTAB nTab, sal_uInt16 nNewWidth )
4090{
4091 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4092 maTabs[nTab]->SetColWidthOnly( nCol, nNewWidth );
4093}
4094
4095void ScDocument::SetRowHeight( SCROW nRow, SCTAB nTab, sal_uInt16 nNewHeight )
4096{
4097 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4098 maTabs[nTab]->SetRowHeight( nRow, nNewHeight );
4099}
4100
4101void ScDocument::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
4102{
4103 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4104 maTabs[nTab]->SetRowHeightRange
4105 ( nStartRow, nEndRow, nNewHeight, 1.0 );
4106}
4107
4108void ScDocument::SetRowHeightOnly( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
4109{
4110 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4111 maTabs[nTab]->SetRowHeightOnly( nStartRow, nEndRow, nNewHeight );
4112}
4113
4114void ScDocument::SetManualHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bManual )
4115{
4116 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4117 maTabs[nTab]->SetManualHeight( nStartRow, nEndRow, bManual );
4118}
4119
4120sal_uInt16 ScDocument::GetColWidth( SCCOL nCol, SCTAB nTab, bool bHiddenAsZero ) const
4121{
4122 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4123 return maTabs[nTab]->GetColWidth( nCol, bHiddenAsZero );
4124 OSL_FAIL("wrong table number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "4124" ": "), "%s", "wrong table number"); } } while (false
)
;
4125 return 0;
4126}
4127
4128sal_uLong ScDocument::GetColWidth( SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab ) const
4129{
4130 const ScTable* pTab = FetchTable(nTab);
4131 if (!pTab)
4132 return 0;
4133
4134 return pTab->GetColWidth(nStartCol, nEndCol);
4135}
4136
4137sal_uInt16 ScDocument::GetOriginalWidth( SCCOL nCol, SCTAB nTab ) const
4138{
4139 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4140 return maTabs[nTab]->GetOriginalWidth( nCol );
4141 OSL_FAIL("wrong table number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "4141" ": "), "%s", "wrong table number"); } } while (false
)
;
4142 return 0;
4143}
4144
4145sal_uInt16 ScDocument::GetCommonWidth( SCCOL nEndCol, SCTAB nTab ) const
4146{
4147 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4148 return maTabs[nTab]->GetCommonWidth( nEndCol );
4149 OSL_FAIL("Wrong table number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "4149" ": "), "%s", "Wrong table number"); } } while (false
)
;
4150 return 0;
4151}
4152
4153sal_uInt16 ScDocument::GetOriginalHeight( SCROW nRow, SCTAB nTab ) const
4154{
4155 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4156 return maTabs[nTab]->GetOriginalHeight( nRow );
4157 OSL_FAIL("Wrong table number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "4157" ": "), "%s", "Wrong table number"); } } while (false
)
;
4158 return 0;
4159}
4160
4161sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, bool bHiddenAsZero ) const
4162{
4163 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4164 return maTabs[nTab]->GetRowHeight( nRow, nullptr, nullptr, bHiddenAsZero );
4165 OSL_FAIL("Wrong sheet number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "4165" ": "), "%s", "Wrong sheet number"); } } while (false
)
;
4166 return 0;
4167}
4168
4169sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, SCROW* pStartRow, SCROW* pEndRow ) const
4170{
4171 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4172 return maTabs[nTab]->GetRowHeight( nRow, pStartRow, pEndRow );
4173 OSL_FAIL("Wrong sheet number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "4173" ": "), "%s", "Wrong sheet number"); } } while (false
)
;
4174 return 0;
4175}
4176
4177sal_uLong ScDocument::GetRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHiddenAsZero ) const
4178{
4179 if (nStartRow == nEndRow)
4180 return GetRowHeight( nStartRow, nTab, bHiddenAsZero ); // faster for a single row
4181
4182 // check bounds because this method replaces former for(i=start;i<=end;++i) loops
4183 if (nStartRow > nEndRow)
4184 return 0;
4185
4186 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4187 return maTabs[nTab]->GetRowHeight( nStartRow, nEndRow, bHiddenAsZero );
4188
4189 OSL_FAIL("wrong sheet number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "4189" ": "), "%s", "wrong sheet number"); } } while (false
)
;
4190 return 0;
4191}
4192
4193SCROW ScDocument::GetRowForHeight( SCTAB nTab, sal_uLong nHeight ) const
4194{
4195 return maTabs[nTab]->GetRowForHeight(nHeight);
4196}
4197
4198sal_uLong ScDocument::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow,
4199 SCTAB nTab, double fScale, const sal_uLong* pnMaxHeight ) const
4200{
4201 // faster for a single row
4202 if (nStartRow == nEndRow)
4203 return static_cast<sal_uLong>(GetRowHeight( nStartRow, nTab) * fScale);
4204
4205 // check bounds because this method replaces former for(i=start;i<=end;++i) loops
4206 if (nStartRow > nEndRow)
4207 return 0;
4208
4209 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4210 return maTabs[nTab]->GetScaledRowHeight( nStartRow, nEndRow, fScale, pnMaxHeight );
4211
4212 OSL_FAIL("wrong sheet number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "4212" ": "), "%s", "wrong sheet number"); } } while (false
)
;
4213 return 0;
4214}
4215
4216SCROW ScDocument::GetHiddenRowCount( SCROW nRow, SCTAB nTab ) const
4217{
4218 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4219 return maTabs[nTab]->GetHiddenRowCount( nRow );
4220 OSL_FAIL("wrong table number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "4220" ": "), "%s", "wrong table number"); } } while (false
)
;
4221 return 0;
4222}
4223
4224sal_uLong ScDocument::GetColOffset( SCCOL nCol, SCTAB nTab, bool bHiddenAsZero ) const
4225{
4226 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4227 return maTabs[nTab]->GetColOffset( nCol, bHiddenAsZero );
4228 OSL_FAIL("wrong table number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "4228" ": "), "%s", "wrong table number"); } } while (false
)
;
4229 return 0;
4230}
4231
4232sal_uLong ScDocument::GetRowOffset( SCROW nRow, SCTAB nTab, bool bHiddenAsZero ) const
4233{
4234 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4235 return maTabs[nTab]->GetRowOffset( nRow, bHiddenAsZero );
4236 OSL_FAIL("wrong table number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "4236" ": "), "%s", "wrong table number"); } } while (false
)
;
4237 return 0;
4238}
4239
4240sal_uInt16 ScDocument::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, OutputDevice* pDev,
4241 double nPPTX, double nPPTY,
4242 const Fraction& rZoomX, const Fraction& rZoomY,
4243 bool bFormula, const ScMarkData* pMarkData,
4244 const ScColWidthParam* pParam )
4245{
4246 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4247 return maTabs[nTab]->GetOptimalColWidth( nCol, pDev, nPPTX, nPPTY,
4248 rZoomX, rZoomY, bFormula, pMarkData, pParam );
4249 OSL_FAIL("wrong table number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "4249" ": "), "%s", "wrong table number"); } } while (false
)
;
4250 return 0;
4251}
4252
4253long ScDocument::GetNeededSize( SCCOL nCol, SCROW nRow, SCTAB nTab,
4254 OutputDevice* pDev,
4255 double nPPTX, double nPPTY,
4256 const Fraction& rZoomX, const Fraction& rZoomY,
4257 bool bWidth, bool bTotalSize, bool bInPrintTwips )
4258{
4259 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4260 return maTabs[nTab]->GetNeededSize
4261 ( nCol, nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, bTotalSize, bInPrintTwips );
4262 OSL_FAIL("wrong table number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "4262" ": "), "%s", "wrong table number"); } } while (false
)
;
4263 return 0;
4264}
4265
4266bool ScDocument::SetOptimalHeight( sc::RowHeightContext& rCxt, SCROW nStartRow, SCROW nEndRow, SCTAB nTab )
4267{
4268 ScTable* pTab = FetchTable(nTab);
4269 if (!pTab)
4270 return false;
4271
4272 return pTab->SetOptimalHeight(rCxt, nStartRow, nEndRow);
4273}
4274
4275void ScDocument::UpdateAllRowHeights( sc::RowHeightContext& rCxt, const ScMarkData* pTabMark )
4276{
4277 // one progress across all (selected) sheets
4278
4279 sal_uLong nCellCount = 0;
4280 for ( SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()); nTab++ )
4281 if ( maTabs[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
4282 nCellCount += maTabs[nTab]->GetWeightedCount();
4283
4284 ScProgress aProgress( GetDocumentShell(), ScResId(STR_PROGRESS_HEIGHTINGreinterpret_cast<char const *>("STR_PROGRESS_HEIGHTING"
"\004" u8"Adapt row height")
), nCellCount, true );
4285
4286 sal_uLong nProgressStart = 0;
4287 for ( SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()); nTab++ )
4288 if ( maTabs[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
4289 {
4290 maTabs[nTab]->SetOptimalHeightOnly(rCxt, 0, MaxRow(), &aProgress, nProgressStart);
4291 maTabs[nTab]->SetDrawPageSize();
4292 nProgressStart += maTabs[nTab]->GetWeightedCount();
4293 }
4294}
4295
4296// Column/Row - Flags ----------------------------------------------
4297
4298void ScDocument::ShowCol(SCCOL nCol, SCTAB nTab, bool bShow)
4299{
4300 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4301 maTabs[nTab]->ShowCol( nCol, bShow );
4302}
4303
4304void ScDocument::ShowRow(SCROW nRow, SCTAB nTab, bool bShow)
4305{
4306 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4307 maTabs[nTab]->ShowRow( nRow, bShow );
4308}
4309
4310void ScDocument::ShowRows(SCROW nRow1, SCROW nRow2, SCTAB nTab, bool bShow)
4311{
4312 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4313 maTabs[nTab]->ShowRows( nRow1, nRow2, bShow );
4314}
4315
4316void ScDocument::SetRowFlags( SCROW nRow, SCTAB nTab, CRFlags nNewFlags )
4317{
4318 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4319 maTabs[nTab]->SetRowFlags( nRow, nNewFlags );
4320}
4321
4322void ScDocument::SetRowFlags( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, CRFlags nNewFlags )
4323{
4324 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4325 maTabs[nTab]->SetRowFlags( nStartRow, nEndRow, nNewFlags );
4326}
4327
4328CRFlags ScDocument::GetColFlags( SCCOL nCol, SCTAB nTab ) const
4329{
4330 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4331 return maTabs[nTab]->GetColFlags( nCol );
4332 OSL_FAIL("wrong table number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "4332" ": "), "%s", "wrong table number"); } } while (false
)
;
4333 return CRFlags::NONE;
4334}
4335
4336CRFlags ScDocument::GetRowFlags( SCROW nRow, SCTAB nTab ) const
4337{
4338 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4339 return maTabs[nTab]->GetRowFlags( nRow );
4340 OSL_FAIL("wrong table number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "4340" ": "), "%s", "wrong table number"); } } while (false
)
;
4341 return CRFlags::NONE;
4342}
4343
4344void ScDocument::GetAllRowBreaks(set<SCROW>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
4345{
4346 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4347 return;
4348 maTabs[nTab]->GetAllRowBreaks(rBreaks, bPage, bManual);
4349}
4350
4351void ScDocument::GetAllColBreaks(set<SCCOL>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
4352{
4353 if (!ValidTab(nTab) || !maTabs[nTab])
4354 return;
4355
4356 maTabs[nTab]->GetAllColBreaks(rBreaks, bPage, bManual);
4357}
4358
4359ScBreakType ScDocument::HasRowBreak(SCROW nRow, SCTAB nTab) const
4360{
4361 ScBreakType nType = ScBreakType::NONE;
4362 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
4363 return nType;
4364
4365 if (maTabs[nTab]->HasRowPageBreak(nRow))
4366 nType |= ScBreakType::Page;
4367
4368 if (maTabs[nTab]->HasRowManualBreak(nRow))
4369 nType |= ScBreakType::Manual;
4370
4371 return nType;
4372}
4373
4374ScBreakType ScDocument::HasColBreak(SCCOL nCol, SCTAB nTab) const
4375{
4376 ScBreakType nType = ScBreakType::NONE;
4377 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
4378 return nType;
4379
4380 if (maTabs[nTab]->HasColPageBreak(nCol))
4381 nType |= ScBreakType::Page;
4382
4383 if (maTabs[nTab]->HasColManualBreak(nCol))
4384 nType |= ScBreakType::Manual;
4385
4386 return nType;
4387}
4388
4389void ScDocument::SetRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
4390{
4391 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
4392 return;
4393
4394 maTabs[nTab]->SetRowBreak(nRow, bPage, bManual);
4395}
4396
4397void ScDocument::SetColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
4398{
4399 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
4400 return;
4401
4402 maTabs[nTab]->SetColBreak(nCol, bPage, bManual);
4403}
4404
4405void ScDocument::RemoveRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
4406{
4407 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
4408 return;
4409
4410 maTabs[nTab]->RemoveRowBreak(nRow, bPage, bManual);
4411}
4412
4413void ScDocument::RemoveColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
4414{
4415 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
4416 return;
4417
4418 maTabs[nTab]->RemoveColBreak(nCol, bPage, bManual);
4419}
4420
4421Sequence<TablePageBreakData> ScDocument::GetRowBreakData(SCTAB nTab) const
4422{
4423 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4424 return Sequence<TablePageBreakData>();
4425
4426 return maTabs[nTab]->GetRowBreakData();
4427}
4428
4429bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow) const
4430{
4431 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4432 return false;
4433
4434 return maTabs[nTab]->RowHidden(nRow, pFirstRow, pLastRow);
4435}
4436
4437bool ScDocument::HasHiddenRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4438{
4439 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4440 return false;
4441
4442 return maTabs[nTab]->HasHiddenRows(nStartRow, nEndRow);
4443}
4444
4445bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol) const
4446{
4447 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4448 {
4449 if (pFirstCol)
4450 *pFirstCol = nCol;
4451 if (pLastCol)
4452 *pLastCol = nCol;
4453 return false;
4454 }
4455
4456 return maTabs[nTab]->ColHidden(nCol, pFirstCol, pLastCol);
4457}
4458
4459void ScDocument::SetRowHidden(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHidden)
4460{
4461 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4462 return;
4463
4464 maTabs[nTab]->SetRowHidden(nStartRow, nEndRow, bHidden);
4465}
4466
4467void ScDocument::SetColHidden(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bHidden)
4468{
4469 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4470 return;
4471
4472 maTabs[nTab]->SetColHidden(nStartCol, nEndCol, bHidden);
4473}
4474
4475SCROW ScDocument::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4476{
4477 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4478 return ::std::numeric_limits<SCROW>::max();
4479
4480 return maTabs[nTab]->FirstVisibleRow(nStartRow, nEndRow);
4481}
4482
4483SCROW ScDocument::LastVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4484{
4485 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4486 return ::std::numeric_limits<SCROW>::max();
4487
4488 return maTabs[nTab]->LastVisibleRow(nStartRow, nEndRow);
4489}
4490
4491SCROW ScDocument::CountVisibleRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4492{
4493 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4494 return 0;
4495
4496 return maTabs[nTab]->CountVisibleRows(nStartRow, nEndRow);
4497}
4498
4499bool ScDocument::RowFiltered(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow) const
4500{
4501 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4502 return false;
4503
4504 return maTabs[nTab]->RowFiltered(nRow, pFirstRow, pLastRow);
4505}
4506
4507bool ScDocument::HasFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4508{
4509 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4510 return false;
4511
4512 return maTabs[nTab]->HasFilteredRows(nStartRow, nEndRow);
4513}
4514
4515bool ScDocument::ColFiltered(SCCOL nCol, SCTAB nTab) const
4516{
4517 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4518 return false;
4519
4520 return maTabs[nTab]->ColFiltered(nCol);
4521}
4522
4523void ScDocument::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bFiltered)
4524{
4525 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4526 return;
4527
4528 maTabs[nTab]->SetRowFiltered(nStartRow, nEndRow, bFiltered);
4529}
4530
4531SCROW ScDocument::FirstNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4532{
4533 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4534 return ::std::numeric_limits<SCROW>::max();
4535
4536 return maTabs[nTab]->FirstNonFilteredRow(nStartRow, nEndRow);
4537}
4538
4539SCROW ScDocument::LastNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4540{
4541 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4542 return ::std::numeric_limits<SCROW>::max();
4543
4544 return maTabs[nTab]->LastNonFilteredRow(nStartRow, nEndRow);
4545}
4546
4547SCROW ScDocument::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4548{
4549 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4550 return 0;
4551
4552 return maTabs[nTab]->CountNonFilteredRows(nStartRow, nEndRow);
4553}
4554
4555bool ScDocument::IsManualRowHeight(SCROW nRow, SCTAB nTab) const
4556{
4557 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4558 return false;
4559
4560 return maTabs[nTab]->IsManualRowHeight(nRow);
4561}
4562
4563void ScDocument::SyncColRowFlags()
4564{
4565 for (const auto& a : maTabs)
4566 {
4567 if (a)
4568 a->SyncColRowFlags();
4569 }
4570}
4571
4572SCROW ScDocument::GetLastFlaggedRow( SCTAB nTab ) const
4573{
4574 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4575 return maTabs[nTab]->GetLastFlaggedRow();
4576 return 0;
4577}
4578
4579SCCOL ScDocument::GetLastChangedCol( SCTAB nTab ) const
4580{
4581 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4582 return maTabs[nTab]->GetLastChangedCol();
4583 return 0;
4584}
4585
4586SCROW ScDocument::GetLastChangedRow( SCTAB nTab ) const
4587{
4588 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4589 return maTabs[nTab]->GetLastChangedRow();
4590 return 0;
4591}
4592
4593SCCOL ScDocument::GetNextDifferentChangedCol( SCTAB nTab, SCCOL nStart) const
4594{
4595 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4596 {
4597 CRFlags nStartFlags = maTabs[nTab]->GetColFlags(nStart);
4598 sal_uInt16 nStartWidth = maTabs[nTab]->GetOriginalWidth(nStart);
4599 for (SCCOL nCol : maTabs[nTab]->GetColumnsRange( nStart + 1, MaxCol()))
4600 {
4601 if (((nStartFlags & CRFlags::ManualBreak) != (maTabs[nTab]->GetColFlags(nCol) & CRFlags::ManualBreak)) ||
4602 (nStartWidth != maTabs[nTab]->GetOriginalWidth(nCol)) ||
4603 ((nStartFlags & CRFlags::Hidden) != (maTabs[nTab]->GetColFlags(nCol) & CRFlags::Hidden)) )
4604 return nCol;
4605 }
4606 return MaxCol()+1;
4607 }
4608 return 0;
4609}
4610
4611SCROW ScDocument::GetNextDifferentChangedRow( SCTAB nTab, SCROW nStart) const
4612{
4613 if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4614 return 0;
4615
4616 const ScBitMaskCompressedArray<SCROW, CRFlags>* pRowFlagsArray = maTabs[nTab]->GetRowFlagsArray();
4617 if (!pRowFlagsArray)
4618 return 0;
4619
4620 if (!maTabs[nTab]->mpRowHeights || !maTabs[nTab]->mpHiddenRows)
4621 return 0;
4622
4623 size_t nIndex; // ignored
4624 SCROW nFlagsEndRow;
4625 SCROW nHiddenEndRow;
4626 SCROW nHeightEndRow;
4627 CRFlags nFlags;
4628 bool bHidden;
4629 sal_uInt16 nHeight;
4630 CRFlags nStartFlags = nFlags = pRowFlagsArray->GetValue( nStart, nIndex, nFlagsEndRow);
4631 bool bStartHidden = bHidden = maTabs[nTab]->RowHidden( nStart, nullptr, &nHiddenEndRow);
4632 sal_uInt16 nStartHeight = nHeight = maTabs[nTab]->GetRowHeight( nStart, nullptr, &nHeightEndRow, false);
4633 SCROW nRow;
4634 while ((nRow = std::min( nHiddenEndRow, std::min( nFlagsEndRow, nHeightEndRow)) + 1) <= MaxRow())
4635 {
4636 if (nFlagsEndRow < nRow)
4637 nFlags = pRowFlagsArray->GetValue( nRow, nIndex, nFlagsEndRow);
4638 if (nHiddenEndRow < nRow)
4639 bHidden = maTabs[nTab]->RowHidden( nRow, nullptr, &nHiddenEndRow);
4640 if (nHeightEndRow < nRow)
4641 nHeight = maTabs[nTab]->GetRowHeight( nRow, nullptr, &nHeightEndRow, false);
4642
4643 if (((nStartFlags & CRFlags::ManualBreak) != (nFlags & CRFlags::ManualBreak)) ||
4644 ((nStartFlags & CRFlags::ManualSize) != (nFlags & CRFlags::ManualSize)) ||
4645 (bStartHidden != bHidden) ||
4646 (nStartHeight != nHeight))
4647 return nRow;
4648 }
4649
4650 return MaxRow()+1;
4651}
4652
4653void ScDocument::GetColDefault( SCTAB nTab, SCCOL nCol, SCROW nLastRow, SCROW& nDefault)
4654{
4655 nDefault = 0;
4656 ScDocAttrIterator aDocAttrItr(*this, nTab, nCol, 0, nCol, nLastRow);
4657 SCCOL nColumn;
4658 SCROW nStartRow;
4659 SCROW nEndRow;
4660 const ScPatternAttr* pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
4661 if (nEndRow >= nLastRow)
4662 return;
4663
4664 ScDefaultAttrSet aSet;
4665 ScDefaultAttrSet::iterator aItr = aSet.end();
4666 while (pAttr)
4667 {
4668 ScDefaultAttr aAttr(pAttr);
4669 aItr = aSet.find(aAttr);
4670 if (aItr == aSet.end())
4671 {
4672 aAttr.nCount = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
4673 aAttr.nFirst = nStartRow;
4674 aSet.insert(aAttr);
4675 }
4676 else
4677 {
4678 aAttr.nCount = aItr->nCount + static_cast<SCSIZE>(nEndRow - nStartRow + 1);
4679 aAttr.nFirst = aItr->nFirst;
4680 aSet.erase(aItr);
4681 aSet.insert(aAttr);
4682 }
4683 pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
4684 }
4685 ScDefaultAttrSet::iterator aDefaultItr = aSet.begin();
4686 aItr = aDefaultItr;
4687 ++aItr;
4688 while (aItr != aSet.end())
4689 {
4690 // for entries with equal count, use the one with the lowest start row,
4691 // don't use the random order of pointer comparisons
4692 if ( aItr->nCount > aDefaultItr->nCount ||
4693 ( aItr->nCount == aDefaultItr->nCount && aItr->nFirst < aDefaultItr->nFirst ) )
4694 aDefaultItr = aItr;
4695 ++aItr;
4696 }
4697 nDefault = aDefaultItr->nFirst;
4698}
4699
4700void ScDocument::StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
4701{
4702 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4703 maTabs[nTab]->StripHidden( rX1, rY1, rX2, rY2 );
4704}
4705
4706void ScDocument::ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
4707{
4708 if ( ValidTab(nTab) && maTabs[nTab] )
4709 maTabs[nTab]->ExtendHidden( rX1, rY1, rX2, rY2 );
4710}
4711
4712// Attribute ----------------------------------------------------------
4713
4714const SfxPoolItem* ScDocument::GetAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich ) const
4715{
4716 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] &&
4717 nCol < maTabs[nTab]->GetAllocatedColumnsCount())
4718 {
4719 const SfxPoolItem* pTemp = maTabs[nTab]->GetAttr( nCol, nRow, nWhich );
4720 if (pTemp)
4721 return pTemp;
4722 else
4723 {
4724 OSL_FAIL( "Attribute Null" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "4724" ": "), "%s", "Attribute Null"); } } while (false)
;
4725 }
4726 }
4727 return &mxPoolHelper->GetDocPool()->GetDefaultItem( nWhich );
4728}
4729
4730const SfxPoolItem* ScDocument::GetAttr( const ScAddress& rPos, sal_uInt16 nWhich ) const
4731{
4732 return GetAttr(rPos.Col(), rPos.Row(), rPos.Tab(), nWhich);
4733}
4734
4735const ScPatternAttr* ScDocument::GetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4736{
4737 if (TableExists(nTab))
4738 return maTabs[nTab]->GetPattern( nCol, nRow );
4739 return nullptr;
4740}
4741
4742const ScPatternAttr* ScDocument::GetPattern( const ScAddress& rPos ) const
4743{
4744 if (TableExists(rPos.Tab()))
4745 return maTabs[rPos.Tab()]->GetPattern(rPos.Col(), rPos.Row());
4746
4747 return nullptr;
4748}
4749
4750const ScPatternAttr* ScDocument::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
4751{
4752 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4753 return maTabs[nTab]->GetMostUsedPattern( nCol, nStartRow, nEndRow );
4754 return nullptr;
4755}
4756
4757void ScDocument::ApplyAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem& rAttr )
4758{
4759 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4760 maTabs[nTab]->ApplyAttr( nCol, nRow, rAttr );
4761}
4762
4763void ScDocument::ApplyPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr )
4764{
4765 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4766 maTabs[nTab]->ApplyPattern( nCol, nRow, rAttr );
4767}
4768
4769void ScDocument::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow,
4770 SCCOL nEndCol, SCROW nEndRow,
4771 const ScMarkData& rMark,
4772 const ScPatternAttr& rAttr,
4773 ScEditDataArray* pDataArray,
4774 bool* const pIsChanged )
4775{
4776 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4777 for (const auto& rTab : rMark)
4778 {
4779 if (rTab >= nMax)
4780 break;
4781 if (maTabs[rTab])
4782 maTabs[rTab]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr, pDataArray, pIsChanged );
4783 }
4784}
4785
4786void ScDocument::ApplyPatternAreaTab( SCCOL nStartCol, SCROW nStartRow,
4787 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScPatternAttr& rAttr )
4788{
4789 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
4790 if (maTabs[nTab])
4791 maTabs[nTab]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
4792}
4793
4794void ScDocument::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
4795 const ScMarkData& rMark, const ScPatternAttr& rPattern, SvNumFormatType nNewType )
4796{
4797 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4798 for (const auto& rTab : rMark)
4799 {
4800 if (rTab >= nMax)
4801 break;
4802 if (maTabs[rTab])
4803 maTabs[rTab]->ApplyPatternIfNumberformatIncompatible( rRange, rPattern, nNewType );
4804 }
4805}
4806
4807void ScDocument::AddCondFormatData( const ScRangeList& rRange, SCTAB nTab, sal_uInt32 nIndex )
4808{
4809 if(o3tl::make_unsigned(nTab) >= maTabs.size())
4810 return;
4811
4812 if(!maTabs[nTab])
4813 return;
4814
4815 maTabs[nTab]->AddCondFormatData(rRange, nIndex);
4816}
4817
4818void ScDocument::RemoveCondFormatData( const ScRangeList& rRange, SCTAB nTab, sal_uInt32 nIndex )
4819{
4820 if(o3tl::make_unsigned(nTab) >= maTabs.size())
4821 return;
4822
4823 if(!maTabs[nTab])
4824 return;
4825
4826 maTabs[nTab]->RemoveCondFormatData(rRange, nIndex);
4827}
4828
4829void ScDocument::ApplyStyle( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScStyleSheet& rStyle)
4830{
4831 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
4832 if (maTabs[nTab])
4833 maTabs[nTab]->ApplyStyle( nCol, nRow, &rStyle );
4834}
4835
4836void ScDocument::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow,
4837 SCCOL nEndCol, SCROW nEndRow,
4838 const ScMarkData& rMark,
4839 const ScStyleSheet& rStyle)
4840{
4841 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4842 for (const auto& rTab : rMark)
4843 {
4844 if (rTab >= nMax)
4845 break;
4846 if (maTabs[rTab])
4847 maTabs[rTab]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
4848 }
4849}
4850
4851void ScDocument::ApplyStyleAreaTab( SCCOL nStartCol, SCROW nStartRow,
4852 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScStyleSheet& rStyle)
4853{
4854 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
4855 if (maTabs[nTab])
4856 maTabs[nTab]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
4857}
4858
4859void ScDocument::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
4860{
4861 // ApplySelectionStyle needs multi mark
4862 if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
4863 {
4864 ScRange aRange;
4865 rMark.GetMarkArea( aRange );
4866 ApplyStyleArea( aRange.aStart.Col(), aRange.aStart.Row(),
4867 aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rStyle );
4868 }
4869 else
4870 {
4871 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4872 for (const auto& rTab : rMark)
4873 {
4874 if (rTab >= nMax)
4875 break;
4876 if ( maTabs[rTab] )
4877 maTabs[rTab]->ApplySelectionStyle( rStyle, rMark );
4878 }
4879 }
4880}
4881
4882void ScDocument::ApplySelectionLineStyle( const ScMarkData& rMark,
4883 const SvxBorderLine* pLine, bool bColorOnly )
4884{
4885 if ( bColorOnly && !pLine )
4886 return;
4887
4888 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4889 for (const auto& rTab : rMark)
4890 {
4891 if (rTab >= nMax)
4892 break;
4893 if (maTabs[rTab])
4894 maTabs[rTab]->ApplySelectionLineStyle( rMark, pLine, bColorOnly );
4895 }
4896}
4897
4898const ScStyleSheet* ScDocument::GetStyle( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4899{
4900 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4901 return maTabs[nTab]->GetStyle(nCol, nRow);
4902 else
4903 return nullptr;
4904}
4905
4906const ScStyleSheet* ScDocument::GetSelectionStyle( const ScMarkData& rMark ) const
4907{
4908 bool bEqual = true;
4909 bool bFound;
4910
4911 const ScStyleSheet* pStyle = nullptr;
4912 const ScStyleSheet* pNewStyle;
4913
4914 if ( rMark.IsMultiMarked() )
4915 {
4916 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4917 for (const auto& rTab : rMark)
4918 {
4919 if (rTab >= nMax)
4920 break;
4921
4922 if (maTabs[rTab])
4923 {
4924 pNewStyle = maTabs[rTab]->GetSelectionStyle( rMark, bFound );
4925 if (bFound)
4926 {
4927 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
4928 bEqual = false; // different
4929 pStyle = pNewStyle;
4930 }
4931 }
4932 }
4933 }
4934 if ( rMark.IsMarked() )
4935 {
4936 ScRange aRange;
4937 rMark.GetMarkArea( aRange );
4938 for (SCTAB i=aRange.aStart.Tab(); i<=aRange.aEnd.Tab() && bEqual && i < static_cast<SCTAB>(maTabs.size()); i++)
4939 if (maTabs[i] && rMark.GetTableSelect(i))
4940 {
4941 pNewStyle = maTabs[i]->GetAreaStyle( bFound,
4942 aRange.aStart.Col(), aRange.aStart.Row(),
4943 aRange.aEnd.Col(), aRange.aEnd.Row() );
4944 if (bFound)
4945 {
4946 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
4947 bEqual = false; // different
4948 pStyle = pNewStyle;
4949 }
4950 }
4951 }
4952
4953 return bEqual ? pStyle : nullptr;
4954}
4955
4956void ScDocument::StyleSheetChanged( const SfxStyleSheetBase* pStyleSheet, bool bRemoved,
4957 OutputDevice* pDev,
4958 double nPPTX, double nPPTY,
4959 const Fraction& rZoomX, const Fraction& rZoomY )
4960{
4961 for (const auto& a : maTabs)
4962 {
4963 if (a)
4964 a->StyleSheetChanged
4965 ( pStyleSheet, bRemoved, pDev, nPPTX, nPPTY, rZoomX, rZoomY );
4966 }
4967
4968 if ( pStyleSheet && pStyleSheet->GetName() == ScResId(STR_STYLENAME_STANDARD_CELLreinterpret_cast<char const *>("STR_STYLENAME_STANDARD"
"\004" u8"Default Cell Style")
) )
4969 {
4970 // update attributes for all note objects
4971 ScDetectiveFunc::UpdateAllComments( *this );
4972 }
4973 else if ( pStyleSheet && pStyleSheet->GetName() == ScResId(STR_STYLENAME_STANDARD_PAGEreinterpret_cast<char const *>("STR_STYLENAME_STANDARD"
"\004" u8"Default Page Style")
) )
4974 {
4975 // update attributes for all note objects
4976 ScDetectiveFunc::UpdateAllComments( *this );
4977 }
4978}
4979
4980bool ScDocument::IsStyleSheetUsed( const ScStyleSheet& rStyle ) const
4981{
4982 if ( bStyleSheetUsageInvalid || rStyle.GetUsage() == ScStyleSheet::Usage::UNKNOWN )
4983 {
4984 SfxStyleSheetIterator aIter( mxPoolHelper->GetStylePool(),
4985 SfxStyleFamily::Para );
4986 for ( const SfxStyleSheetBase* pStyle = aIter.First(); pStyle;
4987 pStyle = aIter.Next() )
4988 {
4989 if (pStyle->isScStyleSheet())
4990 {
4991 const ScStyleSheet* pScStyle = static_cast<const ScStyleSheet*>( pStyle );
4992 pScStyle->SetUsage( ScStyleSheet::Usage::NOTUSED );
4993 }
4994 }
4995
4996 bool bIsUsed = false;
4997
4998 for (const auto& a : maTabs)
4999 {
5000 if (a && a->IsStyleSheetUsed( rStyle ) )
5001 bIsUsed = true;
5002 }
5003
5004 bStyleSheetUsageInvalid = false;
5005
5006 return bIsUsed;
5007 }
5008
5009 return rStyle.GetUsage() == ScStyleSheet::Usage::USED;
5010}
5011
5012bool ScDocument::ApplyFlagsTab( SCCOL nStartCol, SCROW nStartRow,
5013 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, ScMF nFlags )
5014{
5015 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
5016 if (maTabs[nTab])
5017 return maTabs[nTab]->ApplyFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
5018
5019 OSL_FAIL("ApplyFlags: wrong table")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "5019" ": "), "%s", "ApplyFlags: wrong table"); } } while
(false)
;
5020 return false;
5021}
5022
5023bool ScDocument::RemoveFlagsTab( SCCOL nStartCol, SCROW nStartRow,
5024 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, ScMF nFlags )
5025{
5026 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
5027 if (maTabs[nTab])
5028 return maTabs[nTab]->RemoveFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
5029
5030 OSL_FAIL("RemoveFlags: wrong table")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "5030" ": "), "%s", "RemoveFlags: wrong table"); } } while
(false)
;
5031 return false;
5032}
5033
5034const ScPatternAttr* ScDocument::SetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, std::unique_ptr<ScPatternAttr> pAttr )
5035{
5036 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
5037 if (maTabs[nTab])
5038 return maTabs[nTab]->SetPattern( nCol, nRow, std::move(pAttr) );
5039 return nullptr;
5040}
5041
5042void ScDocument::SetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr )
5043{
5044 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
5045 if (maTabs[nTab])
5046 maTabs[nTab]->SetPattern( nCol, nRow, rAttr );
5047}
5048
5049void ScDocument::SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr )
5050{
5051 SCTAB nTab = rPos.Tab();
5052 if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5053 maTabs[nTab]->SetPattern( rPos, rAttr );
5054}
5055
5056std::unique_ptr<ScPatternAttr> ScDocument::CreateSelectionPattern( const ScMarkData& rMark, bool bDeep )
5057{
5058 ScMergePatternState aState;
5059
5060 if ( rMark.IsMultiMarked() ) // multi selection
5061 {
5062 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5063 for (const auto& rTab : rMark)
5064 {
5065 if (rTab >= nMax)
5066 break;
5067 if (maTabs[rTab])
5068 maTabs[rTab]->MergeSelectionPattern( aState, rMark, bDeep );
5069 }
5070 }
5071 if ( rMark.IsMarked() ) // single selection
5072 {
5073 ScRange aRange;
5074 rMark.GetMarkArea(aRange);
5075 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5076 for (const auto& rTab : rMark)
5077 {
5078 if (rTab >= nMax)
5079 break;
5080 if (maTabs[rTab])
5081 maTabs[rTab]->MergePatternArea( aState,
5082 aRange.aStart.Col(), aRange.aStart.Row(),
5083 aRange.aEnd.Col(), aRange.aEnd.Row(), bDeep );
5084 }
5085 }
5086
5087 OSL_ENSURE( aState.pItemSet, "SelectionPattern Null" )do { if (true && (!(aState.pItemSet))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "5087" ": "), "%s", "SelectionPattern Null"); } } while (
false)
;
5088 if (aState.pItemSet)
5089 {
5090 std::unique_ptr<ScPatternAttr> pPattern(new ScPatternAttr( std::move(aState.pItemSet) ));
5091 if (aState.mbValidPatternId)
5092 pPattern->SetKey(aState.mnPatternId);
5093
5094 return pPattern;
5095 }
5096 else
5097 return std::unique_ptr<ScPatternAttr>(new ScPatternAttr( GetPool() )); // empty
5098}
5099
5100const ScPatternAttr* ScDocument::GetSelectionPattern( const ScMarkData& rMark )
5101{
5102 pSelectionAttr = CreateSelectionPattern( rMark );
5103 return pSelectionAttr.get();
5104}
5105
5106void ScDocument::GetSelectionFrame( const ScMarkData& rMark,
5107 SvxBoxItem& rLineOuter,
5108 SvxBoxInfoItem& rLineInner )
5109{
5110 rLineOuter.SetLine(nullptr, SvxBoxItemLine::TOP);
5111 rLineOuter.SetLine(nullptr, SvxBoxItemLine::BOTTOM);
5112 rLineOuter.SetLine(nullptr, SvxBoxItemLine::LEFT);
5113 rLineOuter.SetLine(nullptr, SvxBoxItemLine::RIGHT);
5114 rLineOuter.SetAllDistances(0);
5115
5116 rLineInner.SetLine(nullptr, SvxBoxInfoItemLine::HORI);
5117 rLineInner.SetLine(nullptr, SvxBoxInfoItemLine::VERT);
5118 rLineInner.SetTable(true);
5119 rLineInner.SetDist(true);
5120 rLineInner.SetMinDist(false);
5121
5122 ScLineFlags aFlags;
5123
5124 if( rMark.IsMultiMarked() )
5125 {
5126 ScRangeList aRangeList;
5127 rMark.FillRangeListWithMarks( &aRangeList, false );
5128 size_t nRangeCount = aRangeList.size();
5129 bool bMultipleRows = false, bMultipleCols = false;
5130 for( size_t nRangeIdx = 0; nRangeIdx < nRangeCount; ++nRangeIdx )
5131 {
5132 const ScRange & rRange = aRangeList[ nRangeIdx ];
5133 bMultipleRows = ( bMultipleRows || ( rRange.aStart.Row() != rRange.aEnd.Row() ) );
5134 bMultipleCols = ( bMultipleCols || ( rRange.aStart.Col() != rRange.aEnd.Col() ) );
5135 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5136 for (const auto& rTab : rMark)
5137 {
5138 if (rTab >= nMax)
5139 break;
5140
5141 if (maTabs[rTab])
5142 maTabs[rTab]->MergeBlockFrame( &rLineOuter, &rLineInner, aFlags,
5143 rRange.aStart.Col(), rRange.aStart.Row(),
5144 rRange.aEnd.Col(), rRange.aEnd.Row() );
5145 }
5146 }
5147 rLineInner.EnableHor( bMultipleRows );
5148 rLineInner.EnableVer( bMultipleCols );
5149 }
5150 else if( rMark.IsMarked() )
5151 {
5152 ScRange aRange;
5153 rMark.GetMarkArea(aRange);
5154 rLineInner.EnableHor( aRange.aStart.Row() != aRange.aEnd.Row() );
5155 rLineInner.EnableVer( aRange.aStart.Col() != aRange.aEnd.Col() );
5156 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5157 for (const auto& rTab : rMark)
5158 {
5159 if (rTab >= nMax)
5160 break;
5161
5162 if (maTabs[rTab])
5163 maTabs[rTab]->MergeBlockFrame( &rLineOuter, &rLineInner, aFlags,
5164 aRange.aStart.Col(), aRange.aStart.Row(),
5165 aRange.aEnd.Col(), aRange.aEnd.Row() );
5166 }
5167 }
5168
5169 // Evaluate don't care Status
5170
5171 rLineInner.SetValid( SvxBoxInfoItemValidFlags::LEFT, ( aFlags.nLeft != SC_LINE_DONTCARE2 ) );
5172 rLineInner.SetValid( SvxBoxInfoItemValidFlags::RIGHT, ( aFlags.nRight != SC_LINE_DONTCARE2 ) );
5173 rLineInner.SetValid( SvxBoxInfoItemValidFlags::TOP, ( aFlags.nTop != SC_LINE_DONTCARE2 ) );
5174 rLineInner.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, ( aFlags.nBottom != SC_LINE_DONTCARE2 ) );
5175 rLineInner.SetValid( SvxBoxInfoItemValidFlags::HORI, ( aFlags.nHori != SC_LINE_DONTCARE2 ) );
5176 rLineInner.SetValid( SvxBoxInfoItemValidFlags::VERT, ( aFlags.nVert != SC_LINE_DONTCARE2 ) );
5177}
5178
5179bool ScDocument::HasAttrib( SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
5180 SCCOL nCol2, SCROW nRow2, SCTAB nTab2, HasAttrFlags nMask ) const
5181{
5182 if ( nMask & HasAttrFlags::Rotate )
5183 {
5184 // Is attribute used in document?
5185 // (as in fillinfo)
5186
5187 ScDocumentPool* pPool = mxPoolHelper->GetDocPool();
5188
5189 bool bAnyItem = false;
5190 for (const SfxPoolItem* pItem : pPool->GetItemSurrogates(ATTR_ROTATE_VALUE))
5191 {
5192 // 90 or 270 degrees is former SvxOrientationItem - only look for other values
5193 // (see ScPatternAttr::GetCellOrientation)
5194 sal_Int32 nAngle = static_cast<const ScRotateValueItem*>(pItem)->GetValue();
5195 if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
5196 {
5197 bAnyItem = true;
5198 break;
5199 }
5200 }
5201 if (!bAnyItem)
5202 nMask &= ~HasAttrFlags::Rotate;
5203 }
5204
5205 if (nMask == HasAttrFlags::NONE)
5206 return false;
5207
5208 bool bFound = false;
5209 for (SCTAB i=nTab1; i<=nTab2 && !bFound && i < static_cast<SCTAB>(maTabs.size()); i++)
5210 if (maTabs[i])
5211 {
5212 if ( nMask & HasAttrFlags::RightOrCenter )
5213 {
5214 // On a RTL sheet, don't start to look for the default left value
5215 // (which is then logically right), instead always assume true.
5216 // That way, ScAttrArray::HasAttrib doesn't have to handle RTL sheets.
5217
5218 if ( IsLayoutRTL(i) )
5219 bFound = true;
5220 }
5221
5222 if ( !bFound )
5223 bFound = maTabs[i]->HasAttrib( nCol1, nRow1, nCol2, nRow2, nMask );
5224 }
5225
5226 return bFound;
5227}
5228
5229bool ScDocument::HasAttrib( const ScRange& rRange, HasAttrFlags nMask ) const
5230{
5231 return HasAttrib( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
5232 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(),
5233 nMask );
5234}
5235
5236void ScDocument::FindMaxRotCol( SCTAB nTab, RowInfo* pRowInfo, SCSIZE nArrCount,
5237 SCCOL nX1, SCCOL nX2 ) const
5238{
5239 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5240 maTabs[nTab]->FindMaxRotCol( pRowInfo, nArrCount, nX1, nX2 );
5241 else
5242 {
5243 OSL_FAIL("FindMaxRotCol: wrong table")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "5243" ": "), "%s", "FindMaxRotCol: wrong table"); } } while
(false)
;
5244 }
5245}
5246
5247void ScDocument::GetBorderLines( SCCOL nCol, SCROW nRow, SCTAB nTab,
5248 const SvxBorderLine** ppLeft, const SvxBorderLine** ppTop,
5249 const SvxBorderLine** ppRight, const SvxBorderLine** ppBottom ) const
5250{
5251 //TODO: consider page limits for printing !!!!!
5252
5253 const SvxBoxItem* pThisAttr = GetEffItem( nCol, nRow, nTab, ATTR_BORDER );
5254 OSL_ENSURE(pThisAttr,"where is the attribute?")do { if (true && (!(pThisAttr))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "5254" ": "), "%s", "where is the attribute?"); } } while
(false)
;
5255
5256 const SvxBorderLine* pLeftLine = pThisAttr->GetLeft();
5257 const SvxBorderLine* pTopLine = pThisAttr->GetTop();
5258 const SvxBorderLine* pRightLine = pThisAttr->GetRight();
5259 const SvxBorderLine* pBottomLine = pThisAttr->GetBottom();
5260
5261 if ( nCol > 0 )
5262 {
5263 const SvxBorderLine* pOther = GetEffItem( nCol-1, nRow, nTab, ATTR_BORDER )->GetRight();
5264 if ( ScHasPriority( pOther, pLeftLine ) )
5265 pLeftLine = pOther;
5266 }
5267 if ( nRow > 0 )
5268 {
5269 const SvxBorderLine* pOther = GetEffItem( nCol, nRow-1, nTab, ATTR_BORDER )->GetBottom();
5270 if ( ScHasPriority( pOther, pTopLine ) )
5271 pTopLine = pOther;
5272 }
5273 if ( nCol < MaxCol() )
5274 {
5275 const SvxBorderLine* pOther = GetEffItem( nCol+1, nRow, nTab, ATTR_BORDER )->GetLeft();
5276 if ( ScHasPriority( pOther, pRightLine ) )
5277 pRightLine = pOther;
5278 }
5279 if ( nRow < MaxRow() )
5280 {
5281 const SvxBorderLine* pOther = GetEffItem( nCol, nRow+1, nTab, ATTR_BORDER )->GetTop();
5282 if ( ScHasPriority( pOther, pBottomLine ) )
5283 pBottomLine = pOther;
5284 }
5285
5286 if (ppLeft)
5287 *ppLeft = pLeftLine;
5288 if (ppTop)
5289 *ppTop = pTopLine;
5290 if (ppRight)
5291 *ppRight = pRightLine;
5292 if (ppBottom)
5293 *ppBottom = pBottomLine;
5294}
5295
5296bool ScDocument::IsBlockEmpty( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
5297 SCCOL nEndCol, SCROW nEndRow, bool bIgnoreNotes ) const
5298{
5299 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
5300 if (maTabs[nTab])
5301 return maTabs[nTab]->IsBlockEmpty( nStartCol, nStartRow, nEndCol, nEndRow, bIgnoreNotes );
5302
5303 OSL_FAIL("wrong table number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "5303" ": "), "%s", "wrong table number"); } } while (false
)
;
5304 return false;
5305}
5306
5307void ScDocument::LockTable(SCTAB nTab)
5308{
5309 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5310 maTabs[nTab]->LockTable();
5311 else
5312 {
5313 OSL_FAIL("wrong table number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "5313" ": "), "%s", "wrong table number"); } } while (false
)
;
5314 }
5315}
5316
5317void ScDocument::UnlockTable(SCTAB nTab)
5318{
5319 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
5320 maTabs[nTab]->UnlockTable();
5321 else
5322 {
5323 OSL_FAIL("wrong table number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "5323" ": "), "%s", "wrong table number"); } } while (false
)
;
5324 }
5325}
5326
5327bool ScDocument::IsBlockEditable( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
5328 SCCOL nEndCol, SCROW nEndRow,
5329 bool* pOnlyNotBecauseOfMatrix /* = NULL */,
5330 bool bNoMatrixAtAll ) const
5331{
5332 // import into read-only document is possible
5333 if (!bImportingXML && !mbChangeReadOnlyEnabled && mpShell && mpShell->IsReadOnly())
5334 {
5335 if ( pOnlyNotBecauseOfMatrix )
5336 *pOnlyNotBecauseOfMatrix = false;
5337 return false;
5338 }
5339
5340 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
5341 if (maTabs[nTab])
5342 return maTabs[nTab]->IsBlockEditable( nStartCol, nStartRow, nEndCol,
5343 nEndRow, pOnlyNotBecauseOfMatrix, bNoMatrixAtAll );
5344
5345 OSL_FAIL("wrong table number")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "5345" ": "), "%s", "wrong table number"); } } while (false
)
;
5346 if ( pOnlyNotBecauseOfMatrix )
5347 *pOnlyNotBecauseOfMatrix = false;
5348 return false;
5349}
5350
5351bool ScDocument::IsSelectionEditable( const ScMarkData& rMark,
5352 bool* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
5353{
5354 // import into read-only document is possible
5355 if ( !bImportingXML && !mbChangeReadOnlyEnabled && mpShell && mpShell->IsReadOnly() )
5356 {
5357 if ( pOnlyNotBecauseOfMatrix )
5358 *pOnlyNotBecauseOfMatrix = false;
5359 return false;
5360 }
5361
5362 ScRange aRange;
5363 rMark.GetMarkArea(aRange);
5364
5365 bool bOk = true;
5366 bool bMatrix = ( pOnlyNotBecauseOfMatrix != nullptr );
5367 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5368 for (const auto& rTab : rMark)
5369 {
5370 if (rTab >= nMax)
5371 break;
5372
5373 if ( maTabs[rTab] )
5374 {
5375 if (rMark.IsMarked())
5376 {
5377 if ( !maTabs[rTab]->IsBlockEditable( aRange.aStart.Col(),
5378 aRange.aStart.Row(), aRange.aEnd.Col(),
5379 aRange.aEnd.Row(), pOnlyNotBecauseOfMatrix ) )
5380 {
5381 bOk = false;
5382 if ( pOnlyNotBecauseOfMatrix )
5383 bMatrix = *pOnlyNotBecauseOfMatrix;
5384 }
5385 }
5386 if (rMark.IsMultiMarked())
5387 {
5388 if ( !maTabs[rTab]->IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix ) )
5389 {
5390 bOk = false;
5391 if ( pOnlyNotBecauseOfMatrix )
5392 bMatrix = *pOnlyNotBecauseOfMatrix;
5393 }
5394 }
5395 }
5396
5397 if (!bOk && !bMatrix)
5398 break;
5399 }
5400
5401 if ( pOnlyNotBecauseOfMatrix )
5402 *pOnlyNotBecauseOfMatrix = ( !bOk && bMatrix );
5403
5404 return bOk;
5405}
5406
5407bool ScDocument::HasSelectedBlockMatrixFragment( SCCOL nStartCol, SCROW nStartRow,
5408 SCCOL nEndCol, SCROW nEndRow,
5409 const ScMarkData& rMark ) const
5410{
5411 bool bOk = true;
5412 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5413 for (const auto& rTab : rMark)
5414 {
5415 if (rTab >= nMax)
5416 break;
5417
5418 if (maTabs[rTab] && maTabs[rTab]->HasBlockMatrixFragment( nStartCol, nStartRow, nEndCol, nEndRow ))
5419 bOk = false;
5420
5421 if (!bOk)
5422 break;
5423 }
5424
5425 return !bOk;
5426}
5427
5428bool ScDocument::GetMatrixFormulaRange( const ScAddress& rCellPos, ScRange& rMatrix )
5429{
5430 // if rCell is part of a matrix formula, return its complete range
5431
5432 ScFormulaCell* pFCell = GetFormulaCell(rCellPos);
5433 if (!pFCell)
5434 // not a formula cell. Bail out.
5435 return false;
5436
5437 ScAddress aOrigin = rCellPos;
5438 if (!pFCell->GetMatrixOrigin(*this, aOrigin))
5439 // Failed to get the address of the matrix origin.
5440 return false;
5441
5442 if (aOrigin != rCellPos)
5443 {
5444 pFCell = GetFormulaCell(aOrigin);
5445 if (!pFCell)
5446 // The matrix origin cell is not a formula cell !? Something is up...
5447 return false;
5448 }
5449
5450 SCCOL nSizeX;
5451 SCROW nSizeY;
5452 pFCell->GetMatColsRows(nSizeX, nSizeY);
5453 if (nSizeX <= 0 || nSizeY <= 0)
5454 {
5455 // GetMatrixEdge computes also dimensions of the matrix
5456 // if not already done (may occur if document is loaded
5457 // from old file format).
5458 // Needs an "invalid" initialized address.
5459 aOrigin.SetInvalid();
5460 pFCell->GetMatrixEdge(*this, aOrigin);
5461 pFCell->GetMatColsRows(nSizeX, nSizeY);
5462 }
5463
5464 if (nSizeX <= 0 || nSizeY <= 0)
5465 // Matrix size is still invalid. Give up.
5466 return false;
5467
5468 ScAddress aEnd( aOrigin.Col() + nSizeX - 1,
5469 aOrigin.Row() + nSizeY - 1,
5470 aOrigin.Tab() );
5471
5472 rMatrix.aStart = aOrigin;
5473 rMatrix.aEnd = aEnd;
5474
5475 return true;
5476}
5477
5478void ScDocument::ExtendOverlapped( SCCOL& rStartCol, SCROW& rStartRow,
5479 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab ) const
5480{
5481 if ( ValidColRow(rStartCol,rStartRow) && ValidColRow(nEndCol,nEndRow) && ValidTab(nTab) )
5482 {
5483 if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5484 {
5485 SCCOL nCol;
5486 SCCOL nOldCol = rStartCol;
5487 SCROW nOldRow = rStartRow;
5488 for (nCol=nOldCol; nCol<=nEndCol; nCol++)
5489 while (GetAttr(nCol,rStartRow,nTab,ATTR_MERGE_FLAG)->IsVerOverlapped())
5490 --rStartRow;
5491
5492 //TODO: pass on ?
5493
5494 ScAttrArray* pAttrArray = maTabs[nTab]->aCol[nOldCol].pAttrArray.get();
5495 SCSIZE nIndex;
5496 if ( pAttrArray->Count() )
5497 pAttrArray->Search( nOldRow, nIndex );
5498 else
5499 nIndex = 0;
5500 SCROW nAttrPos = nOldRow;
5501 while (nAttrPos<=nEndRow)
5502 {
5503 OSL_ENSURE( nIndex < pAttrArray->Count(), "Wrong index in AttrArray" )do { if (true && (!(nIndex < pAttrArray->Count(
)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "5503" ": "), "%s", "Wrong index in AttrArray"); } } while
(false)
;
5504
5505 bool bHorOverlapped;
5506 if ( pAttrArray->Count() )
5507 bHorOverlapped = pAttrArray->mvData[nIndex].pPattern->GetItem(ATTR_MERGE_FLAG).IsHorOverlapped();
5508 else
5509 bHorOverlapped = GetDefPattern()->GetItem(ATTR_MERGE_FLAG).IsHorOverlapped();
5510 if ( bHorOverlapped )
5511 {
5512 SCROW nEndRowSeg = (pAttrArray->Count()) ? pAttrArray->mvData[nIndex].nEndRow : MaxRow();
5513 SCROW nLoopEndRow = std::min( nEndRow, nEndRowSeg );
5514 for (SCROW nAttrRow = nAttrPos; nAttrRow <= nLoopEndRow; nAttrRow++)
5515 {
5516 SCCOL nTempCol = nOldCol;
5517 do
5518 --nTempCol;
5519 while (GetAttr(nTempCol,nAttrRow,nTab,ATTR_MERGE_FLAG)->IsHorOverlapped());
5520 if (nTempCol < rStartCol)
5521 rStartCol = nTempCol;
5522 }
5523 }
5524 if ( pAttrArray->Count() )
5525 {
5526 nAttrPos = pAttrArray->mvData[nIndex].nEndRow + 1;
5527 ++nIndex;
5528 }
5529 else
5530 nAttrPos = MaxRow() + 1;
5531 }
5532 }
5533 }
5534 else
5535 {
5536 OSL_FAIL("ExtendOverlapped: invalid range")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "5536" ": "), "%s", "ExtendOverlapped: invalid range"); }
} while (false)
;
5537 }
5538}
5539
5540void ScDocument::ExtendMergeSel( SCCOL nStartCol, SCROW nStartRow,
5541 SCCOL& rEndCol, SCROW& rEndRow,
5542 const ScMarkData& rMark, bool bRefresh )
5543{
5544 // use all selected sheets from rMark
5545
5546 SCCOL nOldEndCol = rEndCol;
5547 SCROW nOldEndRow = rEndRow;
5548
5549 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5550 for (const auto& rTab : rMark)
5551 {
5552 if (rTab >= nMax)
5553 break;
5554
5555 if ( maTabs[rTab] )
5556 {
5557 SCCOL nThisEndCol = nOldEndCol;
5558 SCROW nThisEndRow = nOldEndRow;
5559 ExtendMerge( nStartCol, nStartRow, nThisEndCol, nThisEndRow, rTab, bRefresh );
5560 if ( nThisEndCol > rEndCol )
5561 rEndCol = nThisEndCol;
5562 if ( nThisEndRow > rEndRow )
5563 rEndRow = nThisEndRow;
5564 }
5565 }
5566}
5567
5568bool ScDocument::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
5569 SCCOL& rEndCol, SCROW& rEndRow,
5570 SCTAB nTab, bool bRefresh )
5571{
5572 bool bFound = false;
5573 if ( ValidColRow(nStartCol,nStartRow) && ValidColRow(rEndCol,rEndRow) && ValidTab(nTab) )
5574 {
5575 if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5576 bFound = maTabs[nTab]->ExtendMerge( nStartCol, nStartRow, rEndCol, rEndRow, bRefresh );
5577
5578 if (bRefresh)
5579 RefreshAutoFilter( nStartCol, nStartRow, rEndCol, rEndRow, nTab );
5580 }
5581 else
5582 {
5583 OSL_FAIL("ExtendMerge: invalid range")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "5583" ": "), "%s", "ExtendMerge: invalid range"); } } while
(false)
;
5584 }
5585
5586 return bFound;
5587}
5588
5589bool ScDocument::ExtendMerge( ScRange& rRange, bool bRefresh )
5590{
5591 bool bFound = false;
5592 SCTAB nStartTab = rRange.aStart.Tab();
5593 SCTAB nEndTab = rRange.aEnd.Tab();
5594 SCCOL nEndCol = rRange.aEnd.Col();
5595 SCROW nEndRow = rRange.aEnd.Row();
5596
5597 PutInOrder( nStartTab, nEndTab );
5598 for (SCTAB nTab = nStartTab; nTab <= nEndTab && nTab < static_cast<SCTAB>(maTabs.size()); nTab++ )
5599 {
5600 SCCOL nExtendCol = rRange.aEnd.Col();
5601 SCROW nExtendRow = rRange.aEnd.Row();
5602 if (ExtendMerge( rRange.aStart.Col(), rRange.aStart.Row(),
5603 nExtendCol, nExtendRow,
5604 nTab, bRefresh ) )
5605 {
5606 bFound = true;
5607 if (nExtendCol > nEndCol) nEndCol = nExtendCol;
5608 if (nExtendRow > nEndRow) nEndRow = nExtendRow;
5609 }
5610 }
5611
5612 rRange.aEnd.SetCol(nEndCol);
5613 rRange.aEnd.SetRow(nEndRow);
5614
5615 return bFound;
5616}
5617
5618void ScDocument::ExtendTotalMerge( ScRange& rRange ) const
5619{
5620 // Extend range to merged cells without including any new non-overlapped cells
5621 ScRange aExt = rRange;
5622 // ExtendMerge() is non-const, but called without refresh.
5623 if (!const_cast<ScDocument*>(this)->ExtendMerge( aExt ))
5624 return;
5625
5626 if ( aExt.aEnd.Row() > rRange.aEnd.Row() )
5627 {
5628 ScRange aTest = aExt;
5629 aTest.aStart.SetRow( rRange.aEnd.Row() + 1 );
5630 if ( HasAttrib( aTest, HasAttrFlags::NotOverlapped ) )
5631 aExt.aEnd.SetRow(rRange.aEnd.Row());
5632 }
5633 if ( aExt.aEnd.Col() > rRange.aEnd.Col() )
5634 {
5635 ScRange aTest = aExt;
5636 aTest.aStart.SetCol( rRange.aEnd.Col() + 1 );
5637 if ( HasAttrib( aTest, HasAttrFlags::NotOverlapped ) )
5638 aExt.aEnd.SetCol(rRange.aEnd.Col());
5639 }
5640
5641 rRange = aExt;
5642}
5643
5644void ScDocument::ExtendOverlapped( ScRange& rRange ) const
5645{
5646 SCTAB nStartTab = rRange.aStart.Tab();
5647 SCTAB nEndTab = rRange.aEnd.Tab();
5648 SCCOL nStartCol = rRange.aStart.Col();
5649 SCROW nStartRow = rRange.aStart.Row();
5650
5651 PutInOrder( nStartTab, nEndTab );
5652 for (SCTAB nTab = nStartTab; nTab <= nEndTab && nTab < static_cast<SCTAB>(maTabs.size()); nTab++ )
5653 {
5654 SCCOL nExtendCol = rRange.aStart.Col();
5655 SCROW nExtendRow = rRange.aStart.Row();
5656 ExtendOverlapped( nExtendCol, nExtendRow,
5657 rRange.aEnd.Col(), rRange.aEnd.Row(), nTab );
5658 if (nExtendCol < nStartCol)
5659 {
5660 nStartCol = nExtendCol;
5661 }
5662 if (nExtendRow < nStartRow)
5663 {
5664 nStartRow = nExtendRow;
5665 }
5666 }
5667
5668 rRange.aStart.SetCol(nStartCol);
5669 rRange.aStart.SetRow(nStartRow);
5670}
5671
5672bool ScDocument::RefreshAutoFilter( SCCOL nStartCol, SCROW nStartRow,
5673 SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
5674{
5675 SCTAB nDBTab;
5676 SCCOL nDBStartCol;
5677 SCROW nDBStartRow;
5678 SCCOL nDBEndCol;
5679 SCROW nDBEndRow;
5680
5681 // Delete Autofilter
5682
5683 bool bChange = RemoveFlagsTab( nStartCol,nStartRow, nEndCol,nEndRow, nTab, ScMF::Auto );
5684
5685 // Set Autofilter
5686
5687 const ScDBData* pData = nullptr;
5688 ScDBCollection::NamedDBs& rDBs = pDBCollection->getNamedDBs();
5689 for (const auto& rxDB : rDBs)
5690 {
5691 if (rxDB->HasAutoFilter())
5692 {
5693 rxDB->GetArea(nDBTab, nDBStartCol,nDBStartRow, nDBEndCol,nDBEndRow);
5694 if ( nDBTab==nTab && nDBStartRow<=nEndRow && nDBEndRow>=nStartRow &&
5695 nDBStartCol<=nEndCol && nDBEndCol>=nStartCol )
5696 {
5697 if (ApplyFlagsTab( nDBStartCol,nDBStartRow, nDBEndCol,nDBStartRow,
5698 nDBTab, ScMF::Auto ))
5699 bChange = true;
5700 }
5701 }
5702 }
5703 if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5704 pData = maTabs[nTab]->GetAnonymousDBData();
5705 else
5706 pData=nullptr;
5707 if (pData && pData->HasAutoFilter())
5708 {
5709 pData->GetArea( nDBTab, nDBStartCol,nDBStartRow, nDBEndCol,nDBEndRow );
5710 if ( nDBTab==nTab && nDBStartRow<=nEndRow && nDBEndRow>=nStartRow &&
5711 nDBStartCol<=nEndCol && nDBEndCol>=nStartCol )
5712 {
5713 if (ApplyFlagsTab( nDBStartCol,nDBStartRow, nDBEndCol,nDBStartRow,
5714 nDBTab, ScMF::Auto ))
5715 bChange = true;
5716 }
5717 }
5718 return bChange;
5719}
5720
5721void ScDocument::SkipOverlapped( SCCOL& rCol, SCROW& rRow, SCTAB nTab ) const
5722{
5723 while (IsHorOverlapped(rCol, rRow, nTab))
5724 --rCol;
5725 while (IsVerOverlapped(rCol, rRow, nTab))
5726 --rRow;
5727}
5728
5729bool ScDocument::IsHorOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
5730{
5731 const ScMergeFlagAttr* pAttr = GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
5732 if (pAttr)
5733 return pAttr->IsHorOverlapped();
5734 else
5735 {
5736 OSL_FAIL("Overlapped: Attr==0")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "5736" ": "), "%s", "Overlapped: Attr==0"); } } while (false
)
;
5737 return false;
5738 }
5739}
5740
5741bool ScDocument::IsVerOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
5742{
5743 const ScMergeFlagAttr* pAttr = GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
5744 if (pAttr)
5745 return pAttr->IsVerOverlapped();
5746 else
5747 {
5748 OSL_FAIL("Overlapped: Attr==0")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "5748" ": "), "%s", "Overlapped: Attr==0"); } } while (false
)
;
5749 return false;
5750 }
5751}
5752
5753void ScDocument::ApplySelectionFrame( const ScMarkData& rMark,
5754 const SvxBoxItem& rLineOuter,
5755 const SvxBoxInfoItem* pLineInner )
5756{
5757 ScRangeList aRangeList;
5758 rMark.FillRangeListWithMarks( &aRangeList, false );
5759 size_t nRangeCount = aRangeList.size();
5760 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5761 for (const auto& rTab : rMark)
5762 {
5763 if (rTab >= nMax)
5764 break;
5765
5766 if (maTabs[rTab])
5767 {
5768 for ( size_t j=0; j < nRangeCount; j++ )
5769 {
5770 const ScRange & rRange = aRangeList[ j ];
5771 maTabs[rTab]->ApplyBlockFrame( rLineOuter, pLineInner,
5772 rRange.aStart.Col(), rRange.aStart.Row(),
5773 rRange.aEnd.Col(), rRange.aEnd.Row() );
5774 }
5775 }
5776 }
5777 if (!rLineOuter.IsRemoveAdjacentCellBorder())
5778 return;
5779
5780 SvxBoxItem aTmp0(rLineOuter);
5781 aTmp0.SetLine( nullptr, SvxBoxItemLine::TOP );
5782 aTmp0.SetLine( nullptr, SvxBoxItemLine::BOTTOM );
5783 aTmp0.SetLine( nullptr, SvxBoxItemLine::LEFT );
5784 aTmp0.SetLine( nullptr, SvxBoxItemLine::RIGHT );
5785 SvxBoxItem aLeft( aTmp0 );
5786 SvxBoxItem aRight( aTmp0 );
5787 SvxBoxItem aTop( aTmp0 );
5788 SvxBoxItem aBottom( aTmp0 );
5789
5790 SvxBoxInfoItem aTmp1( *pLineInner );
5791 aTmp1.SetTable( false );
5792 aTmp1.SetLine( nullptr, SvxBoxInfoItemLine::HORI );
5793 aTmp1.SetLine( nullptr, SvxBoxInfoItemLine::VERT );
5794 aTmp1.SetValid( SvxBoxInfoItemValidFlags::ALL, false );
5795 aTmp1.SetValid( SvxBoxInfoItemValidFlags::DISTANCE );
5796 SvxBoxInfoItem aLeftInfo( aTmp1 );
5797 SvxBoxInfoItem aRightInfo( aTmp1 );
5798 SvxBoxInfoItem aTopInfo( aTmp1 );
5799 SvxBoxInfoItem aBottomInfo( aTmp1 );
5800
5801 if (pLineInner->IsValid( SvxBoxInfoItemValidFlags::TOP ) && !rLineOuter.GetTop())
5802 aTopInfo.SetValid( SvxBoxInfoItemValidFlags::BOTTOM );
5803
5804 if (pLineInner->IsValid( SvxBoxInfoItemValidFlags::BOTTOM ) && !rLineOuter.GetBottom())
5805 aBottomInfo.SetValid( SvxBoxInfoItemValidFlags::TOP );
5806
5807 if (pLineInner->IsValid( SvxBoxInfoItemValidFlags::LEFT ) && !rLineOuter.GetLeft())
5808 aLeftInfo.SetValid( SvxBoxInfoItemValidFlags::RIGHT );
5809
5810 if (pLineInner->IsValid( SvxBoxInfoItemValidFlags::RIGHT ) && !rLineOuter.GetRight())
5811 aRightInfo.SetValid( SvxBoxInfoItemValidFlags::LEFT );
5812
5813 const ScRangeList& rRangeListTopEnvelope = rMark.GetTopEnvelope();
5814 const ScRangeList& rRangeListBottomEnvelope = rMark.GetBottomEnvelope();
5815 const ScRangeList& rRangeListLeftEnvelope = rMark.GetLeftEnvelope();
5816 const ScRangeList& rRangeListRightEnvelope = rMark.GetRightEnvelope();
5817
5818 for (const auto& rTab : rMark)
5819 {
5820 if (rTab >= nMax)
5821 break;
5822
5823 if ( maTabs[rTab] )
5824 {
5825 size_t nEnvelopeRangeCount = rRangeListTopEnvelope.size();
5826 for ( size_t j=0; j < nEnvelopeRangeCount; j++ )
5827 {
5828 const ScRange & rRange = rRangeListTopEnvelope[ j ];
5829 maTabs[rTab]->ApplyBlockFrame( aTop, &aTopInfo,
5830 rRange.aStart.Col(), rRange.aStart.Row(),
5831 rRange.aEnd.Col(), rRange.aEnd.Row() );
5832 }
5833 nEnvelopeRangeCount = rRangeListBottomEnvelope.size();
5834 for ( size_t j=0; j < nEnvelopeRangeCount; j++ )
5835 {
5836 const ScRange & rRange = rRangeListBottomEnvelope[ j ];
5837 maTabs[rTab]->ApplyBlockFrame( aBottom, &aBottomInfo,
5838 rRange.aStart.Col(), rRange.aStart.Row(),
5839 rRange.aEnd.Col(), rRange.aEnd.Row() );
5840 }
5841 nEnvelopeRangeCount = rRangeListLeftEnvelope.size();
5842 for ( size_t j=0; j < nEnvelopeRangeCount; j++ )
5843 {
5844 const ScRange & rRange = rRangeListLeftEnvelope[ j ];
5845 maTabs[rTab]->ApplyBlockFrame( aLeft, &aLeftInfo,
5846 rRange.aStart.Col(), rRange.aStart.Row(),
5847 rRange.aEnd.Col(), rRange.aEnd.Row() );
5848 }
5849 nEnvelopeRangeCount = rRangeListRightEnvelope.size();
5850 for ( size_t j=0; j < nEnvelopeRangeCount; j++ )
5851 {
5852 const ScRange & rRange = rRangeListRightEnvelope[ j ];
5853 maTabs[rTab]->ApplyBlockFrame( aRight, &aRightInfo,
5854 rRange.aStart.Col(), rRange.aStart.Row(),
5855 rRange.aEnd.Col(), rRange.aEnd.Row() );
5856 }
5857 }
5858 }
5859}
5860
5861void ScDocument::ApplyFrameAreaTab(const ScRange& rRange,
5862 const SvxBoxItem& rLineOuter,
5863 const SvxBoxInfoItem& rLineInner)
5864{
5865 SCTAB nStartTab = rRange.aStart.Tab();
5866 SCTAB nEndTab = rRange.aStart.Tab();
5867 for (SCTAB nTab=nStartTab; nTab<=nEndTab && nTab < static_cast<SCTAB>(maTabs.size()); nTab++)
5868 if (maTabs[nTab])
5869 maTabs[nTab]->ApplyBlockFrame(rLineOuter, &rLineInner,
5870 rRange.aStart.Col(), rRange.aStart.Row(),
5871 rRange.aEnd.Col(), rRange.aEnd.Row());
5872}
5873
5874void ScDocument::ApplySelectionPattern( const ScPatternAttr& rAttr, const ScMarkData& rMark, ScEditDataArray* pDataArray, bool* const pIsChanged )
5875{
5876 const SfxItemSet* pSet = &rAttr.GetItemSet();
5877 bool bSet = false;
5878 sal_uInt16 i;
5879 for (i=ATTR_PATTERN_START; i<=ATTR_PATTERN_END && !bSet; i++)
5880 if (pSet->GetItemState(i) == SfxItemState::SET)
5881 bSet = true;
5882
5883 if (!bSet)
5884 return;
5885
5886 // ApplySelectionCache needs multi mark
5887 if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
5888 {
5889 ScRange aRange;
5890 rMark.GetMarkArea( aRange );
5891 ApplyPatternArea( aRange.aStart.Col(), aRange.aStart.Row(),
5892 aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rAttr, pDataArray, pIsChanged );
5893 }
5894 else
5895 {
5896 SfxItemPoolCache aCache( mxPoolHelper->GetDocPool(), pSet );
5897 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5898 for (const auto& rTab : rMark)
5899 {
5900 if (rTab >= nMax)
5901 break;
5902 if (maTabs[rTab])
5903 maTabs[rTab]->ApplySelectionCache( &aCache, rMark, pDataArray, pIsChanged );
5904 }
5905 }
5906}
5907
5908void ScDocument::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
5909{
5910 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5911 for (const auto& rTab : rMark)
5912 {
5913 if (rTab >= nMax)
5914 break;
5915 if (maTabs[rTab])
5916 maTabs[rTab]->ChangeSelectionIndent( bIncrement, rMark );
5917 }
5918}
5919
5920void ScDocument::ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark )
5921{
5922 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5923 for (const auto& rTab : rMark)
5924 {
5925 if (rTab >= nMax)
5926 break;
5927 if (maTabs[rTab])
5928 maTabs[rTab]->ClearSelectionItems( pWhich, rMark );
5929 }
5930}
5931
5932void ScDocument::DeleteSelection( InsertDeleteFlags nDelFlag, const ScMarkData& rMark, bool bBroadcast )
5933{
5934 sc::AutoCalcSwitch aACSwitch(*this, false);
5935
5936 std::vector<ScAddress> aGroupPos;
5937 // Destroy and reconstruct listeners only if content is affected.
5938 bool bDelContent = ((nDelFlag & ~InsertDeleteFlags::CONTENTS) != nDelFlag);
5939 if (bDelContent)
5940 {
5941 // Record the positions of top and/or bottom formula groups that
5942 // intersect the area borders.
5943 sc::EndListeningContext aCxt(*this);
5944 ScRangeList aRangeList;
5945 rMark.FillRangeListWithMarks( &aRangeList, false);
5946 for (size_t i = 0; i < aRangeList.size(); ++i)
5947 {
5948 const ScRange & rRange = aRangeList[i];
5949 EndListeningIntersectedGroups( aCxt, rRange, &aGroupPos);
5950 }
5951 aCxt.purgeEmptyBroadcasters();
5952 }
5953
5954 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
5955 for (const auto& rTab : rMark)
5956 {
5957 if (rTab >= nMax)
5958 break;
5959 if (maTabs[rTab])
5960 maTabs[rTab]->DeleteSelection(nDelFlag, rMark, bBroadcast);
5961 }
5962
5963 if (!bDelContent)
5964 return;
5965
5966 // Re-start listeners on those top bottom groups that have been split.
5967 SetNeedsListeningGroups(aGroupPos);
5968 StartNeededListeners();
5969
5970 // If formula groups were split their listeners were destroyed and may
5971 // need to be notified now that they're restored,
5972 // ScTable::DeleteSelection() couldn't do that.
5973 if (aGroupPos.empty())
5974 return;
5975
5976 ScRangeList aRangeList;
5977 rMark.FillRangeListWithMarks( &aRangeList, false);
5978 for (size_t i = 0; i < aRangeList.size(); ++i)
5979 {
5980 SetDirty( aRangeList[i], true);
5981 }
5982 //Notify listeners on top and bottom of the group that has been split
5983 for (size_t i = 0; i < aGroupPos.size(); ++i) {
5984 ScFormulaCell *pFormulaCell = GetFormulaCell(aGroupPos[i]);
5985 if (pFormulaCell)
5986 pFormulaCell->SetDirty(true);
5987 }
5988}
5989
5990void ScDocument::DeleteSelectionTab(
5991 SCTAB nTab, InsertDeleteFlags nDelFlag, const ScMarkData& rMark )
5992{
5993 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
5994 {
5995 sc::AutoCalcSwitch aACSwitch(*this, false);
5996
5997 std::vector<ScAddress> aGroupPos;
5998 // Destroy and reconstruct listeners only if content is affected.
5999 bool bDelContent = ((nDelFlag & ~InsertDeleteFlags::CONTENTS) != nDelFlag);
6000 if (bDelContent)
6001 {
6002 // Record the positions of top and/or bottom formula groups that
6003 // intersect the area borders.
6004 sc::EndListeningContext aCxt(*this);
6005 ScRangeList aRangeList;
6006 rMark.FillRangeListWithMarks( &aRangeList, false);
6007 for (size_t i = 0; i < aRangeList.size(); ++i)
6008 {
6009 const ScRange & rRange = aRangeList[i];
6010 if (rRange.aStart.Tab() <= nTab && nTab <= rRange.aEnd.Tab())
6011 {
6012 ScRange aRange( rRange);
6013 aRange.aStart.SetTab( nTab);
6014 aRange.aEnd.SetTab( nTab);
6015 EndListeningIntersectedGroups( aCxt, aRange, &aGroupPos);
6016 }
6017 }
6018 aCxt.purgeEmptyBroadcasters();
6019 }
6020
6021 maTabs[nTab]->DeleteSelection(nDelFlag, rMark);
6022
6023 if (bDelContent)
6024 {
6025 // Re-start listeners on those top bottom groups that have been split.
6026 SetNeedsListeningGroups(aGroupPos);
6027 StartNeededListeners();
6028
6029 // If formula groups were split their listeners were destroyed and may
6030 // need to be notified now that they're restored,
6031 // ScTable::DeleteSelection() couldn't do that.
6032 if (!aGroupPos.empty())
6033 {
6034 ScRangeList aRangeList;
6035 rMark.FillRangeListWithMarks( &aRangeList, false);
6036 for (size_t i = 0; i < aRangeList.size(); ++i)
6037 {
6038 const ScRange & rRange = aRangeList[i];
6039 if (rRange.aStart.Tab() <= nTab && nTab <= rRange.aEnd.Tab())
6040 {
6041 ScRange aRange( rRange);
6042 aRange.aStart.SetTab( nTab);
6043 aRange.aEnd.SetTab( nTab);
6044 SetDirty( aRange, true);
6045 }
6046 }
6047 }
6048 }
6049 }
6050 else
6051 {
6052 OSL_FAIL("wrong table")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "6052" ": "), "%s", "wrong table"); } } while (false)
;
6053 }
6054}
6055
6056ScPatternAttr* ScDocument::GetDefPattern() const
6057{
6058 return const_cast<ScPatternAttr*>(&mxPoolHelper->GetDocPool()->GetDefaultItem(ATTR_PATTERN));
6059}
6060
6061ScDocumentPool* ScDocument::GetPool()
6062{
6063 return mxPoolHelper->GetDocPool();
6064}
6065
6066ScStyleSheetPool* ScDocument::GetStyleSheetPool() const
6067{
6068 return mxPoolHelper->GetStylePool();
6069}
6070
6071SCSIZE ScDocument::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
6072 SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, ScDirection eDir )
6073{
6074 PutInOrder(nStartCol, nEndCol);
6075 PutInOrder(nStartRow, nEndRow);
6076 PutInOrder(nStartTab, nEndTab);
6077 if (ValidTab(nStartTab) && nStartTab < static_cast<SCTAB>(maTabs.size()))
6078 {
6079 if (maTabs[nStartTab])
6080 return maTabs[nStartTab]->GetEmptyLinesInBlock(nStartCol, nStartRow, nEndCol, nEndRow, eDir);
6081 else
6082 return 0;
6083 }
6084 else
6085 return 0;
6086}
6087
6088void ScDocument::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, ScMoveDirection eDirection ) const
6089{
6090 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6091 maTabs[nTab]->FindAreaPos( rCol, rRow, eDirection );
6092}
6093
6094void ScDocument::GetNextPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCCOL nMovX, SCROW nMovY,
6095 bool bMarked, bool bUnprotected, const ScMarkData& rMark, SCCOL nTabStartCol ) const
6096{
6097 OSL_ENSURE( !nMovX || !nMovY, "GetNextPos: only X or Y" )do { if (true && (!(!nMovX || !nMovY))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "6097" ": "), "%s", "GetNextPos: only X or Y"); } } while
(false)
;
6098
6099 ScMarkData aCopyMark = rMark;
6100 aCopyMark.SetMarking(false);
6101 aCopyMark.MarkToMulti();
6102
6103 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6104 maTabs[nTab]->GetNextPos( rCol, rRow, nMovX, nMovY, bMarked, bUnprotected, aCopyMark, nTabStartCol );
6105}
6106
6107// Data operations
6108
6109void ScDocument::UpdStlShtPtrsFrmNms()
6110{
6111 ScDocumentPool* pPool = mxPoolHelper->GetDocPool();
6112
6113 for (const SfxPoolItem* pItem : pPool->GetItemSurrogates(ATTR_PATTERN))
6114 {
6115 auto pPattern = const_cast<ScPatternAttr*>(dynamic_cast<const ScPatternAttr*>(pItem));
6116 if (pPattern)
6117 pPattern->UpdateStyleSheet(*this);
6118 }
6119 const_cast<ScPatternAttr&>(pPool->GetDefaultItem(ATTR_PATTERN)).UpdateStyleSheet(*this);
6120}
6121
6122void ScDocument::StylesToNames()
6123{
6124 ScDocumentPool* pPool = mxPoolHelper->GetDocPool();
6125
6126 for (const SfxPoolItem* pItem : pPool->GetItemSurrogates(ATTR_PATTERN))
6127 {
6128 auto pPattern = const_cast<ScPatternAttr*>(dynamic_cast<const ScPatternAttr*>(pItem));
6129 if (pPattern)
6130 pPattern->StyleToName();
6131 }
6132 const_cast<ScPatternAttr&>(pPool->GetDefaultItem(ATTR_PATTERN)).StyleToName();
6133}
6134
6135sal_uLong ScDocument::GetCellCount() const
6136{
6137 sal_uLong nCellCount = 0;
6138
6139 for (const auto& a : maTabs)
6140 {
6141 if (a)
6142 nCellCount += a->GetCellCount();
6143 }
6144
6145 return nCellCount;
6146}
6147
6148sal_uLong ScDocument::GetFormulaGroupCount() const
6149{
6150 sal_uLong nFormulaGroupCount = 0;
6151
6152 ScFormulaGroupIterator aIter( *const_cast<ScDocument*>(this) );
6153 for ( sc::FormulaGroupEntry* ptr = aIter.first(); ptr; ptr = aIter.next())
6154 {
6155 nFormulaGroupCount++;
6156 }
6157
6158 return nFormulaGroupCount;
6159}
6160
6161sal_uLong ScDocument::GetCodeCount() const
6162{
6163 sal_uLong nCodeCount = 0;
6164
6165 for (const auto& a : maTabs)
6166 {
6167 if (a)
6168 nCodeCount += a->GetCodeCount();
6169 }
6170
6171 return nCodeCount;
6172}
6173
6174void ScDocument::PageStyleModified( SCTAB nTab, const OUString& rNewName )
6175{
6176 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
6177 maTabs[nTab]->PageStyleModified( rNewName );
6178}
6179
6180void ScDocument::SetPageStyle( SCTAB nTab, const OUString& rName )
6181{
6182 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
6183 maTabs[nTab]->SetPageStyle( rName );
6184}
6185
6186OUString ScDocument::GetPageStyle( SCTAB nTab ) const
6187{
6188 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
6189 return maTabs[nTab]->GetPageStyle();
6190
6191 return OUString();
6192}
6193
6194void ScDocument::SetPageSize( SCTAB nTab, const Size& rSize )
6195{
6196 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
6197 maTabs[nTab]->SetPageSize( rSize );
6198}
6199
6200Size ScDocument::GetPageSize( SCTAB nTab ) const
6201{
6202 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
6203 return maTabs[nTab]->GetPageSize();
6204
6205 OSL_FAIL("invalid tab")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "6205" ": "), "%s", "invalid tab"); } } while (false)
;
6206 return Size();
6207}
6208
6209void ScDocument::SetRepeatArea( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow )
6210{
6211 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
6212 maTabs[nTab]->SetRepeatArea( nStartCol, nEndCol, nStartRow, nEndRow );
6213}
6214
6215void ScDocument::InvalidatePageBreaks(SCTAB nTab)
6216{
6217 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6218 maTabs[nTab]->InvalidatePageBreaks();
6219}
6220
6221void ScDocument::UpdatePageBreaks( SCTAB nTab, const ScRange* pUserArea )
6222{
6223 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
6224 maTabs[nTab]->UpdatePageBreaks( pUserArea );
6225}
6226
6227void ScDocument::RemoveManualBreaks( SCTAB nTab )
6228{
6229 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
6230 maTabs[nTab]->RemoveManualBreaks();
6231}
6232
6233bool ScDocument::HasManualBreaks( SCTAB nTab ) const
6234{
6235 if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
6236 return maTabs[nTab]->HasManualBreaks();
6237
6238 OSL_FAIL("invalid tab")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "6238" ": "), "%s", "invalid tab"); } } while (false)
;
6239 return false;
6240}
6241
6242void ScDocument::GetDocStat( ScDocStat& rDocStat )
6243{
6244 rDocStat.nTableCount = GetTableCount();
6245 rDocStat.aDocName = aDocName;
6246 rDocStat.nFormulaCount = GetFormulaGroupCount();
6247 rDocStat.nCellCount = GetCellCount();
6248}
6249
6250bool ScDocument::HasPrintRange()
6251{
6252 bool bResult = false;
6253
6254 for (const auto& a : maTabs)
6255 {
6256 if (!a)
6257 continue;
6258 bResult = a->IsPrintEntireSheet() || (a->GetPrintRangeCount() > 0);
6259 if (bResult)
6260 break;
6261 }
6262
6263 return bResult;
6264}
6265
6266bool ScDocument::IsPrintEntireSheet( SCTAB nTab ) const
6267{
6268 return (ValidTab(nTab) ) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsPrintEntireSheet();
6269}
6270
6271sal_uInt16 ScDocument::GetPrintRangeCount( SCTAB nTab )
6272{
6273 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6274 return maTabs[nTab]->GetPrintRangeCount();
6275
6276 return 0;
6277}
6278
6279const ScRange* ScDocument::GetPrintRange( SCTAB nTab, sal_uInt16 nPos )
6280{
6281 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6282 return maTabs[nTab]->GetPrintRange(nPos);
6283
6284 return nullptr;
6285}
6286
6287const ScRange* ScDocument::GetRepeatColRange( SCTAB nTab )
6288{
6289 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6290 return maTabs[nTab]->GetRepeatColRange();
6291
6292 return nullptr;
6293}
6294
6295const ScRange* ScDocument::GetRepeatRowRange( SCTAB nTab )
6296{
6297 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6298 return maTabs[nTab]->GetRepeatRowRange();
6299
6300 return nullptr;
6301}
6302
6303void ScDocument::ClearPrintRanges( SCTAB nTab )
6304{
6305 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6306 maTabs[nTab]->ClearPrintRanges();
6307}
6308
6309void ScDocument::AddPrintRange( SCTAB nTab, const ScRange& rNew )
6310{
6311 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6312 maTabs[nTab]->AddPrintRange( rNew );
6313}
6314
6315void ScDocument::SetPrintEntireSheet( SCTAB nTab )
6316{
6317 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6318 maTabs[nTab]->SetPrintEntireSheet();
6319}
6320
6321void ScDocument::SetRepeatColRange( SCTAB nTab, std::unique_ptr<ScRange> pNew )
6322{
6323 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6324 maTabs[nTab]->SetRepeatColRange( std::move(pNew) );
6325}
6326
6327void ScDocument::SetRepeatRowRange( SCTAB nTab, std::unique_ptr<ScRange> pNew )
6328{
6329 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6330 maTabs[nTab]->SetRepeatRowRange( std::move(pNew) );
6331}
6332
6333std::unique_ptr<ScPrintRangeSaver> ScDocument::CreatePrintRangeSaver() const
6334{
6335 const SCTAB nCount = static_cast<SCTAB>(maTabs.size());
6336 std::unique_ptr<ScPrintRangeSaver> pNew(new ScPrintRangeSaver( nCount ));
6337 for (SCTAB i=0; i<nCount; i++)
6338 if (maTabs[i])
6339 maTabs[i]->FillPrintSaver( pNew->GetTabData(i) );
6340 return pNew;
6341}
6342
6343void ScDocument::RestorePrintRanges( const ScPrintRangeSaver& rSaver )
6344{
6345 const SCTAB nCount = rSaver.GetTabCount();
6346 const SCTAB maxIndex = std::min(nCount, static_cast<SCTAB>(maTabs.size()));
6347 for (SCTAB i=0; i<maxIndex; i++)
6348 if (maTabs[i])
6349 maTabs[i]->RestorePrintRanges( rSaver.GetTabData(i) );
6350}
6351
6352bool ScDocument::NeedPageResetAfterTab( SCTAB nTab ) const
6353{
6354 // The page number count restarts at a sheet, if another template is set at
6355 // the preceding one (only compare names) and if a pagenumber is specified (not 0)
6356
6357 if ( nTab + 1 < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab+1] )
6358 {
6359 const OUString & rNew = maTabs[nTab+1]->GetPageStyle();
6360 if ( rNew != maTabs[nTab]->GetPageStyle() )
6361 {
6362 SfxStyleSheetBase* pStyle = mxPoolHelper->GetStylePool()->Find( rNew, SfxStyleFamily::Page );
6363 if ( pStyle )
6364 {
6365 const SfxItemSet& rSet = pStyle->GetItemSet();
6366 sal_uInt16 nFirst = rSet.Get(ATTR_PAGE_FIRSTPAGENO).GetValue();
6367 if ( nFirst != 0 )
6368 return true; // Specify page number in new template
6369 }
6370 }
6371 }
6372
6373 return false; // otherwise not
6374}
6375
6376SfxUndoManager* ScDocument::GetUndoManager()
6377{
6378 if (!mpUndoManager)
6379 {
6380 // to support enhanced text edit for draw objects, use an SdrUndoManager
6381 ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE);
6382
6383 SdrUndoManager* pUndoManager = new SdrUndoManager;
6384 pUndoManager->SetDocShell(GetDocumentShell());
6385 mpUndoManager = pUndoManager;
6386 }
6387
6388 return mpUndoManager;
6389}
6390
6391ScRowBreakIterator* ScDocument::GetRowBreakIterator(SCTAB nTab) const
6392{
6393 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6394 return new ScRowBreakIterator(maTabs[nTab]->maRowPageBreaks);
6395 return nullptr;
6396}
6397
6398void ScDocument::AddSubTotalCell(ScFormulaCell* pCell)
6399{
6400 maSubTotalCells.insert(pCell);
6401}
6402
6403void ScDocument::RemoveSubTotalCell(ScFormulaCell* pCell)
6404{
6405 maSubTotalCells.erase(pCell);
6406}
6407
6408namespace {
6409
6410bool lcl_hasDirtyRange(const ScDocument& rDoc, ScFormulaCell* pCell, const ScRange& rDirtyRange)
6411{
6412 ScDetectiveRefIter aRefIter(rDoc, pCell);
6413 ScRange aRange;
6414 while (aRefIter.GetNextRef(aRange))
6415 {
6416 if (aRange.Intersects(rDirtyRange))
6417 return true;
6418 }
6419 return false;
6420}
6421
6422}
6423
6424void ScDocument::SetSubTotalCellsDirty(const ScRange& rDirtyRange)
6425{
6426 // to update the list by skipping cells that no longer contain subtotal function.
6427 set<ScFormulaCell*> aNewSet;
6428
6429 bool bOldRecalc = GetAutoCalc();
6430 SetAutoCalc(false);
6431 for (ScFormulaCell* pCell : maSubTotalCells)
6432 {
6433 if (pCell->IsSubTotal())
6434 {
6435 aNewSet.insert(pCell);
6436 if (lcl_hasDirtyRange(*this, pCell, rDirtyRange))
6437 pCell->SetDirty();
6438 }
6439 }
6440
6441 SetAutoCalc(bOldRecalc);
6442 maSubTotalCells.swap(aNewSet); // update the list.
6443}
6444
6445sal_uInt16 ScDocument::GetTextWidth( const ScAddress& rPos ) const
6446{
6447 SCTAB nTab = rPos.Tab();
6448 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6449 return maTabs[nTab]->GetTextWidth(rPos.Col(), rPos.Row());
6450
6451 return 0;
6452}
6453
6454SvtScriptType ScDocument::GetScriptType( const ScAddress& rPos ) const
6455{
6456 SCTAB nTab = rPos.Tab();
6457 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6458 return maTabs[nTab]->GetScriptType(rPos.Col(), rPos.Row());
6459
6460 return SvtScriptType::NONE;
6461}
6462
6463void ScDocument::SetScriptType( const ScAddress& rPos, SvtScriptType nType )
6464{
6465 SCTAB nTab = rPos.Tab();
6466 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
6467 maTabs[nTab]->SetScriptType(rPos.Col(), rPos.Row(), nType);
6468}
6469
6470void ScDocument::EnableUndo( bool bVal )
6471{
6472 // The undo manager increases lock count every time undo is disabled.
6473 // Because of this, we shouldn't disable undo unless it's currently
6474 // enabled, or else re-enabling it may not actually re-enable undo unless
6475 // the lock count becomes zero.
6476
6477 if (bVal != GetUndoManager()->IsUndoEnabled())
6478 {
6479 GetUndoManager()->EnableUndo(bVal);
6480 if( mpDrawLayer ) mpDrawLayer->EnableUndo(bVal);
6481 }
6482
6483 mbUndoEnabled = bVal;
6484}
6485
6486void ScDocument::EnableUserInteraction( bool bVal )
6487{
6488 mbUserInteractionEnabled = bVal;
6489}
6490
6491bool ScDocument::IsInVBAMode() const
6492{
6493 if (!mpShell)
6494 return false;
6495
6496 try
6497 {
6498 uno::Reference<script::vba::XVBACompatibility> xVBA(
6499 mpShell->GetBasicContainer(), uno::UNO_QUERY);
6500
6501 return xVBA.is() && xVBA->getVBACompatibilityMode();
6502 }
6503 catch (const lang::NotInitializedException&) {}
6504
6505 return false;
6506}
6507
6508ScPostIt* ScDocument::GetNote(const ScAddress& rPos)
6509{
6510 return GetNote(rPos.Col(), rPos.Row(), rPos.Tab());
6511}
6512
6513ScPostIt* ScDocument::GetNote(SCCOL nCol, SCROW nRow, SCTAB nTab)
6514{
6515 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) &&
6516 nCol < maTabs[nTab]->GetAllocatedColumnsCount())
6517 return maTabs[nTab]->aCol[nCol].GetCellNote(nRow);
6518 else
6519 return nullptr;
6520
6521}
6522
6523void ScDocument::SetNote(const ScAddress& rPos, std::unique_ptr<ScPostIt> pNote)
6524{
6525 return SetNote(rPos.Col(), rPos.Row(), rPos.Tab(), std::move(pNote));
6526}
6527
6528void ScDocument::SetNote(SCCOL nCol, SCROW nRow, SCTAB nTab, std::unique_ptr<ScPostIt> pNote)
6529{
6530 return maTabs[nTab]->CreateColumnIfNotExists(nCol).SetCellNote(nRow, std::move(pNote));
6531}
6532
6533bool ScDocument::HasNote(const ScAddress& rPos) const
6534{
6535 return HasNote(rPos.Col(), rPos.Row(), rPos.Tab());
6536}
6537
6538bool ScDocument::HasNote(SCCOL nCol, SCROW nRow, SCTAB nTab) const
6539{
6540 if (!ValidColRow(nCol, nRow))
6541 return false;
6542
6543 const ScTable* pTab = FetchTable(nTab);
6544 if (!pTab)
6545 return false;
6546
6547 if (nCol >= pTab->GetAllocatedColumnsCount())
6548 return false;
6549
6550 const ScPostIt* pNote = pTab->aCol[nCol].GetCellNote(nRow);
6551 return pNote != nullptr;
6552}
6553
6554bool ScDocument::HasColNotes(SCCOL nCol, SCTAB nTab) const
6555{
6556 if (!ValidCol(nCol))
6557 return false;
6558
6559 const ScTable* pTab = FetchTable(nTab);
6560 if (!pTab)
6561 return false;
6562
6563 return pTab->aCol[nCol].HasCellNotes();
6564}
6565
6566bool ScDocument::HasTabNotes(SCTAB nTab) const
6567{
6568 const ScTable* pTab = FetchTable(nTab);
6569
6570 if ( !pTab )
6571 return false;
6572
6573 for (SCCOL nCol=0, nColSize = pTab->aCol.size(); nCol < nColSize; ++nCol)
6574 if ( HasColNotes(nCol, nTab) )
6575 return true;
6576
6577 return false;
6578}
6579
6580bool ScDocument::HasNotes() const
6581{
6582 for (SCTAB i = 0; i <= MAXTAB; ++i)
6583 {
6584 if (HasTabNotes(i))
6585 return true;
6586 }
6587 return false;
6588}
6589
6590std::unique_ptr<ScPostIt> ScDocument::ReleaseNote(const ScAddress& rPos)
6591{
6592 ScTable* pTab = FetchTable(rPos.Tab());
6593 if (!pTab)
6594 return nullptr;
6595
6596 return pTab->ReleaseNote(rPos.Col(), rPos.Row());
6597}
6598
6599ScPostIt* ScDocument::GetOrCreateNote(const ScAddress& rPos)
6600{
6601 if (HasNote(rPos))
6602 return GetNote(rPos);
6603 else
6604 return CreateNote(rPos);
6605}
6606ScPostIt* ScDocument::CreateNote(const ScAddress& rPos)
6607{
6608 ScPostIt* pPostIt = new ScPostIt(*this, rPos);
6609 SetNote(rPos, std::unique_ptr<ScPostIt>(pPostIt));
6610 return pPostIt;
6611}
6612
6613size_t ScDocument::GetNoteCount( SCTAB nTab, SCCOL nCol ) const
6614{
6615 const ScTable* pTab = FetchTable(nTab);
6616 if (!pTab)
6617 return 0;
6618
6619 return pTab->GetNoteCount(nCol);
6620}
6621
6622void ScDocument::CreateAllNoteCaptions()
6623{
6624 for (const auto& a : maTabs)
6625 {
6626 if (a)
6627 a->CreateAllNoteCaptions();
6628 }
6629}
6630
6631void ScDocument::ForgetNoteCaptions( const ScRangeList& rRanges, bool bPreserveData )
6632{
6633 for (size_t i = 0, n = rRanges.size(); i < n; ++i)
6634 {
6635 const ScRange & rRange = rRanges[i];
6636 const ScAddress& s = rRange.aStart;
6637 const ScAddress& e = rRange.aEnd;
6638 for (SCTAB nTab = s.Tab(); nTab <= e.Tab(); ++nTab)
6639 {
6640 ScTable* pTab = FetchTable(nTab);
6641 if (!pTab)
6642 continue;
6643
6644 pTab->ForgetNoteCaptions(s.Col(), s.Row(), e.Col(), e.Row(), bPreserveData);
6645 }
6646 }
6647}
6648
6649CommentCaptionState ScDocument::GetAllNoteCaptionsState( const ScRangeList& rRanges )
6650{
6651 CommentCaptionState aTmpState = CommentCaptionState::ALLHIDDEN;
6652 CommentCaptionState aState = CommentCaptionState::ALLHIDDEN;
6653 bool bFirstControl = true;
6654 std::vector<sc::NoteEntry> aNotes;
6655
6656 for (size_t i = 0, n = rRanges.size(); i < n; ++i)
6657 {
6658 const ScRange & rRange = rRanges[i];
6659
6660 for( SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab )
6661 {
6662 aState = maTabs[nTab]->GetAllNoteCaptionsState( rRange, aNotes );
6663
6664 if (aState == CommentCaptionState::MIXED)
6665 return aState;
6666
6667 if (bFirstControl) // it is possible that a range is ALLSHOWN, another range is ALLHIDDEN,
6668 { // we have to detect that situation as mixed.
6669 aTmpState = aState;
6670 bFirstControl = false;
6671 }
6672 else if(aTmpState != aState)
6673 {
6674 aState = CommentCaptionState::MIXED;
6675 return aState;
6676 }
6677 }
6678 }
6679 return aState;
6680}
6681
6682ScAddress ScDocument::GetNotePosition( size_t nIndex ) const
6683{
6684 for (size_t nTab = 0; nTab < maTabs.size(); ++nTab)
6685 {
6686 for (SCCOL nCol : GetColumnsRange(nTab, 0, MaxCol()))
6687 {
6688 size_t nColNoteCount = GetNoteCount(nTab, nCol);
6689 if (!nColNoteCount)
6690 continue;
6691
6692 if (nIndex >= nColNoteCount)
6693 {
6694 nIndex -= nColNoteCount;
6695 continue;
6696 }
6697
6698 SCROW nRow = GetNotePosition(nTab, nCol, nIndex);
6699 if (nRow >= 0)
6700 return ScAddress(nCol, nRow, nTab);
6701
6702 OSL_FAIL("note not found")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "6702" ": "), "%s", "note not found"); } } while (false)
;
6703 return ScAddress::INITIALIZE_INVALID;
6704 }
6705 }
6706
6707 OSL_FAIL("note not found")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "6707" ": "), "%s", "note not found"); } } while (false)
;
6708 return ScAddress::INITIALIZE_INVALID;
6709}
6710
6711ScAddress ScDocument::GetNotePosition( size_t nIndex, SCTAB nTab ) const
6712{
6713 for (SCCOL nCol : GetColumnsRange(nTab, 0, MaxCol()))
6714 {
6715 size_t nColNoteCount = GetNoteCount(nTab, nCol);
6716 if (!nColNoteCount)
6717 continue;
6718
6719 if (nIndex >= nColNoteCount)
6720 {
6721 nIndex -= nColNoteCount;
6722 continue;
6723 }
6724
6725 SCROW nRow = GetNotePosition(nTab, nCol, nIndex);
6726 if (nRow >= 0)
6727 return ScAddress(nCol, nRow, nTab);
6728
6729 OSL_FAIL("note not found")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "6729" ": "), "%s", "note not found"); } } while (false)
;
6730 return ScAddress::INITIALIZE_INVALID;
6731 }
6732
6733 OSL_FAIL("note not found")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
":" "6733" ": "), "%s", "note not found"); } } while (false)
;
6734 return ScAddress::INITIALIZE_INVALID;
6735}
6736
6737SCROW ScDocument::GetNotePosition( SCTAB nTab, SCCOL nCol, size_t nIndex ) const
6738{
6739 const ScTable* pTab = FetchTable(nTab);
6740 if (!pTab)
6741 return -1;
6742
6743 return pTab->GetNotePosition(nCol, nIndex);
6744}
6745
6746void ScDocument::GetAllNoteEntries( std::vector<sc::NoteEntry>& rNotes ) const
6747{
6748 for (const auto & pTab : maTabs)
6749 {
6750 if (!pTab)
6751 continue;
6752
6753 pTab->GetAllNoteEntries(rNotes);
6754 }
6755}
6756
6757void ScDocument::GetAllNoteEntries( SCTAB nTab, std::vector<sc::NoteEntry>& rNotes ) const
6758{
6759 const ScTable* pTab = FetchTable(nTab);
6760 if (!pTab)
6761 return;
6762
6763 return pTab->GetAllNoteEntries( rNotes );
6764}
6765
6766void ScDocument::GetNotesInRange( const ScRangeList& rRangeList, std::vector<sc::NoteEntry>& rNotes ) const
6767{
6768 for( size_t i = 0; i < rRangeList.size(); ++i)
6769 {
6770 const ScRange & rRange = rRangeList[i];
6771 for( SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab )
6772 {
6773 maTabs[nTab]->GetNotesInRange( rRange, rNotes );
6774 }
6775 }
6776}
6777
6778void ScDocument::GetUnprotectedCells( ScRangeList& rRangeList, SCTAB nTab ) const
6779{
6780 maTabs[nTab]->GetUnprotectedCells( rRangeList );
6781}
6782
6783bool ScDocument::ContainsNotesInRange( const ScRangeList& rRangeList ) const
6784{
6785 for( size_t i = 0; i < rRangeList.size(); ++i)
6786 {
6787 const ScRange & rRange = rRangeList[i];
6788 for( SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab )
6789 {
6790 bool bContainsNote = maTabs[nTab]->ContainsNotesInRange( rRange );
6791 if(bContainsNote)
6792 return true;
6793 }
6794 }
6795
6796 return false;
6797}
6798
6799void ScDocument::SetAutoNameCache( std::unique_ptr<ScAutoNameCache> pCache )
6800{
6801 pAutoNameCache = std::move(pCache);
6802}
6803
6804thread_local ScDocumentThreadSpecific ScDocument::maThreadSpecific;
6805
6806ScRecursionHelper& ScDocument::GetRecursionHelper()
6807{
6808 if (!IsThreadedGroupCalcInProgress())
6809 {
6810 if (!maNonThreaded.xRecursionHelper)
6811 maNonThreaded.xRecursionHelper = std::make_unique<ScRecursionHelper>();
6812 return *maNonThreaded.xRecursionHelper;
6813 }
6814 else
6815 {
6816 if (!maThreadSpecific.xRecursionHelper)
6817 maThreadSpecific.xRecursionHelper = std::make_unique<ScRecursionHelper>();
6818 return *maThreadSpecific.xRecursionHelper;
6819 }
6820}
6821
6822void ScDocumentThreadSpecific::SetupFromNonThreadedData(const ScDocumentThreadSpecific& /*rNonThreadedData*/)
6823{
6824 // What about the recursion helper?
6825 // Copy the lookup cache?
6826}
6827
6828void ScDocumentThreadSpecific::MergeBackIntoNonThreadedData(ScDocumentThreadSpecific& /*rNonThreadedData*/)
6829{
6830 // What about recursion helper and lookup cache?
6831}
6832
6833ScDocumentThreadSpecific::ScDocumentThreadSpecific()
6834 : pContext(nullptr)
6835{}
6836
6837ScDocumentThreadSpecific::~ScDocumentThreadSpecific() {}
6838
6839void ScDocument::SetupFromNonThreadedContext(ScInterpreterContext& /*threadedContext*/, int /*threadNumber*/)
6840{
6841 // lookup cache is now only in pooled ScInterpreterContext's
6842}
6843
6844void ScDocument::MergeBackIntoNonThreadedContext(ScInterpreterContext& threadedContext, int /*threadNumber*/)
6845{
6846 // Move data from a context used by a calculation thread to the main thread's context.
6847 // Called from the main thread after the calculation thread has already finished.
6848 assert(!IsThreadedGroupCalcInProgress())(static_cast <bool> (!IsThreadedGroupCalcInProgress()) ?
void (0) : __assert_fail ("!IsThreadedGroupCalcInProgress()"
, "/home/maarten/src/libreoffice/core/sc/source/core/data/document.cxx"
, 6848, __extension__ __PRETTY_FUNCTION__))
;
6849 maInterpreterContext.maDelayedSetNumberFormat.insert(
6850 maInterpreterContext.maDelayedSetNumberFormat.end(),
6851 std::make_move_iterator(threadedContext.maDelayedSetNumberFormat.begin()),
6852 std::make_move_iterator(threadedContext.maDelayedSetNumberFormat.end()));
6853 // lookup cache is now only in pooled ScInterpreterContext's
6854}
6855
6856/* vim:set shiftwidth=4 softtabstop=4 expandtab: */