LibreOffice Module sc (master)  1
document.cxx
Go to the documentation of this file.
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>
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 
89 #include <formula/vectortoken.hxx>
90 
91 #include <limits>
92 #include <memory>
93 #include <utility>
94 
95 #include <comphelper/lok.hxx>
96 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
97 
98 #include <vcl/uitest/logger.hxx>
100 
101 #include <mtvelements.hxx>
102 #include <sfx2/lokhelper.hxx>
103 
104 using ::editeng::SvxBorderLine;
105 using namespace ::com::sun::star;
106 
107 namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
108 using ::com::sun::star::uno::Sequence;
109 using ::com::sun::star::sheet::TablePageBreakData;
110 using ::std::set;
111 
112 namespace {
113 
114 std::pair<SCTAB,SCTAB> getMarkedTableRange(const std::vector<ScTableUniquePtr>& rTables, const ScMarkData& rMark)
115 {
116  SCTAB nTabStart = MAXTAB;
117  SCTAB nTabEnd = 0;
118  SCTAB nMax = static_cast<SCTAB>(rTables.size());
119  for (const auto& rTab : rMark)
120  {
121  if (rTab >= nMax)
122  break;
123 
124  if (!rTables[rTab])
125  continue;
126 
127  if (rTab < nTabStart)
128  nTabStart = rTab;
129  nTabEnd = rTab;
130  }
131 
132  return std::pair<SCTAB,SCTAB>(nTabStart,nTabEnd);
133 }
134 
135 void collectUIInformation(const std::map<OUString, OUString>& aParameters, const OUString& rAction)
136 {
137  EventDescription aDescription;
138  aDescription.aID = "grid_window";
139  aDescription.aAction = rAction;
140  aDescription.aParameters = aParameters;
141  aDescription.aParent = "MainWindow";
142  aDescription.aKeyWord = "ScGridWinUIObject";
143 
144  UITestLogger::getInstance().logEvent(aDescription);
145 }
146 
147 struct ScDefaultAttr
148 {
149  const ScPatternAttr* pAttr;
150  SCROW nFirst;
151  SCSIZE nCount;
152  explicit ScDefaultAttr(const ScPatternAttr* pPatAttr) : pAttr(pPatAttr), nFirst(0), nCount(0) {}
153 };
154 
155 struct ScLessDefaultAttr
156 {
157  bool operator() (const ScDefaultAttr& rValue1, const ScDefaultAttr& rValue2) const
158  {
159  return rValue1.pAttr < rValue2.pAttr;
160  }
161 };
162 
163 }
164 
165 typedef std::set<ScDefaultAttr, ScLessDefaultAttr> ScDefaultAttrSet;
166 
167 void ScDocument::MakeTable( SCTAB nTab,bool _bNeedsNameCheck )
168 {
169  if ( !(ValidTab(nTab) && ( nTab >= static_cast<SCTAB>(maTabs.size()) ||!maTabs[nTab])) )
170  return;
171 
172  // Get Custom prefix
173  const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
174  OUString aString = rOpt.GetInitTabPrefix() + OUString::number(nTab+1);
175  if ( _bNeedsNameCheck )
176  CreateValidTabName( aString ); // no doubles
177  if (nTab < static_cast<SCTAB>(maTabs.size()))
178  {
179  maTabs[nTab].reset( new ScTable(this, nTab, aString) );
180  }
181  else
182  {
183  while(nTab > static_cast<SCTAB>(maTabs.size()))
184  maTabs.push_back(nullptr);
185  maTabs.emplace_back( new ScTable(this, nTab, aString) );
186  }
187  maTabs[nTab]->SetLoadingMedium(bLoadingMedium);
188 }
189 
190 bool ScDocument::HasTable( SCTAB nTab ) const
191 {
192  if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
193  if (maTabs[nTab])
194  return true;
195 
196  return false;
197 }
198 
199 bool ScDocument::GetHashCode( SCTAB nTab, sal_Int64& rHashCode ) const
200 {
201  if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
202  {
203  if (maTabs[nTab])
204  {
205  rHashCode = maTabs[nTab]->GetHashCode();
206  return true;
207  }
208  }
209  return false;
210 }
211 
212 bool ScDocument::GetName( SCTAB nTab, OUString& rName ) const
213 {
214  if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
215  {
216  if (maTabs[nTab])
217  {
218  rName = maTabs[nTab]->GetName();
219  return true;
220  }
221  }
222  rName.clear();
223  return false;
224 }
225 
226 OUString ScDocument::GetCopyTabName( SCTAB nTab ) const
227 {
228  if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabNames.size()))
229  return maTabNames[nTab];
230  return OUString();
231 }
232 
233 bool ScDocument::SetCodeName( SCTAB nTab, const OUString& rName )
234 {
235  if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
236  {
237  if (maTabs[nTab])
238  {
239  maTabs[nTab]->SetCodeName( rName );
240  return true;
241  }
242  }
243  SAL_WARN("sc", "can't set code name " << rName );
244  return false;
245 }
246 
247 bool ScDocument::GetCodeName( SCTAB nTab, OUString& rName ) const
248 {
249  if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
250  if (maTabs[nTab])
251  {
252  rName = maTabs[nTab]->GetCodeName();
253  return true;
254  }
255  rName.clear();
256  return false;
257 }
258 
259 bool ScDocument::GetTable( const OUString& rName, SCTAB& rTab ) const
260 {
261  OUString aUpperName;
262  static OUString aCacheName, aCacheUpperName;
263 
265  if (aCacheName != rName)
266  {
267  aCacheName = rName;
268  // surprisingly slow ...
269  aCacheUpperName = ScGlobal::getCharClassPtr()->uppercase(rName);
270  }
271  aUpperName = aCacheUpperName;
272 
273  for (SCTAB i=0; i< static_cast<SCTAB>(maTabs.size()); i++)
274  if (maTabs[i])
275  {
276  if (aUpperName == maTabs[i]->GetUpperName())
277  {
278  rTab = i;
279  return true;
280  }
281  }
282  rTab = 0;
283  return false;
284 }
285 
286 std::vector<OUString> ScDocument::GetAllTableNames() const
287 {
288  std::vector<OUString> aNames;
289  aNames.reserve(maTabs.size());
290  for (const auto& a : maTabs)
291  {
292  // Positions need to be preserved for ScCompiler and address convention
293  // context, so still push an empty string for NULL tabs.
294  OUString aName;
295  if (a)
296  {
297  const ScTable& rTab = *a;
298  aName = rTab.GetName();
299  }
300  aNames.push_back(aName);
301  }
302 
303  return aNames;
304 }
305 
307 {
308  if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
309  return maTabs[nTab]->GetAnonymousDBData();
310  return nullptr;
311 }
312 
314 {
315  return static_cast<SCTAB>(maTabs.size());
316 }
317 
318 void ScDocument::SetAnonymousDBData(SCTAB nTab, std::unique_ptr<ScDBData> pDBData)
319 {
320  if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
321  maTabs[nTab]->SetAnonymousDBData(std::move(pDBData));
322 }
323 
324 void ScDocument::SetAnonymousDBData( std::unique_ptr<ScDBData> pDBData )
325 {
326  mpAnonymousDBData = std::move(pDBData);
327 }
328 
330 {
331  return mpAnonymousDBData.get();
332 }
333 
334 bool ScDocument::ValidTabName( const OUString& rName )
335 {
336  if (rName.isEmpty())
337  return false;
338  sal_Int32 nLen = rName.getLength();
339 
340 #if 1
341  // Restrict sheet names to what Excel accepts.
342  /* TODO: We may want to remove this restriction for full ODFF compliance.
343  * Merely loading and calculating ODF documents using these characters in
344  * sheet names is not affected by this, but all sheet name editing and
345  * copying functionality is, maybe falling back to "Sheet4" or similar. */
346  for (sal_Int32 i = 0; i < nLen; ++i)
347  {
348  const sal_Unicode c = rName[i];
349  switch (c)
350  {
351  case ':':
352  case '\\':
353  case '/':
354  case '?':
355  case '*':
356  case '[':
357  case ']':
358  // these characters are not allowed to match XL's convention.
359  return false;
360  case '\'':
361  if (i == 0 || i == nLen - 1)
362  // single quote is not allowed at the first or last
363  // character position.
364  return false;
365  break;
366  }
367  }
368 #endif
369 
370  return true;
371 }
372 
373 bool ScDocument::ValidNewTabName( const OUString& rName ) const
374 {
375  bool bValid = ValidTabName(rName);
376  if (!bValid)
377  return false;
378  OUString aUpperName = ScGlobal::getCharClassPtr()->uppercase(rName);
379  for (const auto& a : maTabs)
380  {
381  if (!a)
382  continue;
383  const OUString& rOldName = a->GetUpperName();
384  bValid = rOldName != aUpperName;
385  if (!bValid)
386  break;
387  }
388  return bValid;
389 }
390 
391 void ScDocument::CreateValidTabName(OUString& rName) const
392 {
393  if ( !ValidTabName(rName) )
394  {
395  // Find new one
396 
397  // Get Custom prefix
398  const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
399  const OUString& aStrTable = rOpt.GetInitTabPrefix();
400 
401  bool bOk = false;
402 
403  // First test if the prefix is valid, if so only avoid doubles
404  bool bPrefix = ValidTabName( aStrTable );
405  OSL_ENSURE(bPrefix, "Invalid Table Name");
406  SCTAB nDummy;
407 
408  for ( SCTAB i = static_cast<SCTAB>(maTabs.size())+1; !bOk ; i++ )
409  {
410  rName = aStrTable + OUString::number(static_cast<sal_Int32>(i));
411  if (bPrefix)
412  bOk = ValidNewTabName( rName );
413  else
414  bOk = !GetTable( rName, nDummy );
415  }
416  }
417  else
418  {
419  // testing the supplied Name
420 
421  if ( !ValidNewTabName(rName) )
422  {
423  SCTAB i = 1;
424  OUStringBuffer aName;
425  do
426  {
427  i++;
428  aName = rName;
429  aName.append('_');
430  aName.append(static_cast<sal_Int32>(i));
431  }
432  while (!ValidNewTabName(aName.toString()) && (i < MAXTAB+1));
433  rName = aName.makeStringAndClear();
434  }
435  }
436 }
437 
438 void ScDocument::CreateValidTabNames(std::vector<OUString>& aNames, SCTAB nCount) const
439 {
440  aNames.clear();//ensure that the vector is empty
441 
442  // Get Custom prefix
443  const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
444  const OUString& aStrTable = rOpt.GetInitTabPrefix();
445 
446  OUStringBuffer rName;
447 
448  // First test if the prefix is valid, if so only avoid doubles
449  bool bPrefix = ValidTabName( aStrTable );
450  OSL_ENSURE(bPrefix, "Invalid Table Name");
451  SCTAB nDummy;
452  SCTAB i = static_cast<SCTAB>(maTabs.size())+1;
453 
454  for (SCTAB j = 0; j < nCount; ++j)
455  {
456  bool bOk = false;
457  while(!bOk)
458  {
459  rName = aStrTable;
460  rName.append(static_cast<sal_Int32>(i));
461  if (bPrefix)
462  bOk = ValidNewTabName( rName.toString() );
463  else
464  bOk = !GetTable( rName.toString(), nDummy );
465  i++;
466  }
467  aNames.push_back(rName.makeStringAndClear());
468  }
469 }
470 
471 void ScDocument::AppendTabOnLoad(const OUString& rName)
472 {
473  SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
474  if (!ValidTab(nTabCount))
475  // max table count reached. No more tables.
476  return;
477 
478  OUString aName = rName;
479  CreateValidTabName(aName);
480  maTabs.emplace_back( new ScTable(this, nTabCount, aName) );
481 }
482 
483 void ScDocument::SetTabNameOnLoad(SCTAB nTab, const OUString& rName)
484 {
485  if (!ValidTab(nTab) || static_cast<SCTAB>(maTabs.size()) <= nTab)
486  return;
487 
488  if (!ValidTabName(rName))
489  return;
490 
491  maTabs[nTab]->SetName(rName);
492 }
493 
495 {
496  for (const auto& a : maTabs)
497  {
498  if (a)
499  a->SetStreamValid(false);
500  }
501 }
502 
504  SCTAB nPos, const OUString& rName, bool bExternalDocument, bool bUndoDeleteTab )
505 {
506  SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
507  bool bValid = ValidTab(nTabCount);
508  if ( !bExternalDocument ) // else test rName == "'Doc'!Tab" first
509  bValid = (bValid && ValidNewTabName(rName));
510  if (bValid)
511  {
512  if (nPos == SC_TAB_APPEND || nPos >= nTabCount)
513  {
514  nPos = maTabs.size();
515  maTabs.emplace_back( new ScTable(this, nTabCount, rName) );
516  if ( bExternalDocument )
517  maTabs[nTabCount]->SetVisible( false );
518  }
519  else
520  {
521  if (ValidTab(nPos) && (nPos < nTabCount))
522  {
523  sc::RefUpdateInsertTabContext aCxt( *this, nPos, 1);
524 
525  ScRange aRange( 0,0,nPos, MaxCol(),MaxRow(),MAXTAB );
526  xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
527  xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
528  if (pRangeName)
529  pRangeName->UpdateInsertTab(aCxt);
530  pDBCollection->UpdateReference(
531  URM_INSDEL, 0,0,nPos, MaxCol(),MaxRow(),MAXTAB, 0,0,1 );
532  if (pDPCollection)
533  pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
534  if (pDetOpList)
535  pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,1 );
536  UpdateChartRef( URM_INSDEL, 0,0,nPos, MaxCol(),MaxRow(),MAXTAB, 0,0,1 );
537  UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,1 );
538  if ( pUnoBroadcaster )
539  pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,1 ) );
540 
541  for (const auto& a : maTabs)
542  {
543  if (a)
544  a->UpdateInsertTab(aCxt);
545  }
546  maTabs.emplace(maTabs.begin() + nPos, new ScTable(this, nPos, rName));
547 
548  // UpdateBroadcastAreas must be called between UpdateInsertTab,
549  // which ends listening, and StartAllListeners, to not modify
550  // areas that are to be inserted by starting listeners.
551  UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,1);
552  for (const auto& a : maTabs)
553  {
554  if (a)
555  a->UpdateCompile();
556  }
557 
559 
560  if (pValidationList)
561  {
563  pValidationList->UpdateInsertTab(aCxt);
564  }
565 
566  bValid = true;
567  }
568  else
569  bValid = false;
570  }
571  }
572 
573  if (bValid)
574  {
576  aCxt.mbClearTabDeletedFlag = bUndoDeleteTab;
577  aCxt.mnTabDeletedStart = nPos;
578  aCxt.mnTabDeletedEnd = nPos;
579  SetAllFormulasDirty(aCxt);
580 
582  {
583  ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>(this->GetDocumentShell()->GetModel());
585  }
586  }
587 
588  return bValid;
589 }
590 
591 bool ScDocument::InsertTabs( SCTAB nPos, const std::vector<OUString>& rNames,
592  bool bNamesValid )
593 {
594  SCTAB nNewSheets = static_cast<SCTAB>(rNames.size());
595  SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
596  bool bValid = bNamesValid || ValidTab(nTabCount+nNewSheets);
597 
598  if (bValid)
599  {
600  if (nPos == SC_TAB_APPEND || nPos >= nTabCount)
601  {
602  for ( SCTAB i = 0; i < nNewSheets; ++i )
603  {
604  maTabs.emplace_back( new ScTable(this, nTabCount + i, rNames.at(i)) );
605  }
606  }
607  else
608  {
609  if (ValidTab(nPos) && (nPos < nTabCount))
610  {
611  sc::RefUpdateInsertTabContext aCxt( *this, nPos, nNewSheets);
612  ScRange aRange( 0,0,nPos, MaxCol(),MaxRow(),MAXTAB );
613  xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,nNewSheets );
614  xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,nNewSheets );
615  if (pRangeName)
616  pRangeName->UpdateInsertTab(aCxt);
617  pDBCollection->UpdateReference(
618  URM_INSDEL, 0,0,nPos, MaxCol(),MaxRow(),MAXTAB, 0,0,nNewSheets );
619  if (pDPCollection)
620  pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,nNewSheets );
621  if (pDetOpList)
622  pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,nNewSheets );
623  UpdateChartRef( URM_INSDEL, 0,0,nPos, MaxCol(),MaxRow(),MAXTAB, 0,0,nNewSheets );
624  UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0, nNewSheets );
625  if ( pUnoBroadcaster )
626  pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,nNewSheets ) );
627 
628  for (const auto& a : maTabs)
629  {
630  if (a)
631  a->UpdateInsertTab(aCxt);
632  }
633  for (SCTAB i = 0; i < nNewSheets; ++i)
634  {
635  maTabs.emplace(maTabs.begin() + nPos + i, new ScTable(this, nPos + i, rNames.at(i)) );
636  }
637 
638  // UpdateBroadcastAreas must be called between UpdateInsertTab,
639  // which ends listening, and StartAllListeners, to not modify
640  // areas that are to be inserted by starting listeners.
641  UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,nNewSheets);
642  for (const auto& a : maTabs)
643  {
644  if (a)
645  a->UpdateCompile();
646  }
647 
649 
650  if (pValidationList)
651  {
653  pValidationList->UpdateInsertTab(aCxt);
654  }
655 
656  bValid = true;
657  }
658  else
659  bValid = false;
660  }
661  }
662 
663  if (bValid)
664  {
666  SetAllFormulasDirty(aCxt);
667  }
668 
669  return bValid;
670 }
671 
673 {
674  bool bValid = false;
675  if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
676  {
677  if (maTabs[nTab])
678  {
679  SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
680  if (nTabCount > 1)
681  {
682  sc::AutoCalcSwitch aACSwitch(*this, false);
683  sc::RefUpdateDeleteTabContext aCxt( *this, nTab, 1);
684 
685  ScRange aRange( 0, 0, nTab, MaxCol(), MaxRow(), nTab );
686  DelBroadcastAreasInRange( aRange );
687 
688  // #i8180# remove database ranges etc. that are on the deleted tab
689  // (restored in undo with ScRefUndoData)
690 
691  xColNameRanges->DeleteOnTab( nTab );
692  xRowNameRanges->DeleteOnTab( nTab );
693  pDBCollection->DeleteOnTab( nTab );
694  if (pDPCollection)
695  pDPCollection->DeleteOnTab( nTab );
696  if (pDetOpList)
697  pDetOpList->DeleteOnTab( nTab );
698  DeleteAreaLinksOnTab( nTab );
699 
700  // normal reference update
701 
702  aRange.aEnd.SetTab( static_cast<SCTAB>(maTabs.size())-1 );
703  xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
704  xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
705  if (pRangeName)
706  pRangeName->UpdateDeleteTab(aCxt);
707  pDBCollection->UpdateReference(
708  URM_INSDEL, 0,0,nTab, MaxCol(),MaxRow(),MAXTAB, 0,0,-1 );
709  if (pDPCollection)
710  pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
711  if (pDetOpList)
712  pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1 );
713  UpdateChartRef( URM_INSDEL, 0,0,nTab, MaxCol(),MaxRow(),MAXTAB, 0,0,-1 );
714  UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1 );
715  if (pValidationList)
716  {
718  pValidationList->UpdateDeleteTab(aCxt);
719  }
720  if ( pUnoBroadcaster )
721  pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1 ) );
722 
723  for (auto & pTab : maTabs)
724  if (pTab)
725  pTab->UpdateDeleteTab(aCxt);
726 
727  maTabs.erase(maTabs.begin() + nTab);
728  // UpdateBroadcastAreas must be called between UpdateDeleteTab,
729  // which ends listening, and StartAllListeners, to not modify
730  // areas that are to be inserted by starting listeners.
731  UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1);
732  for (const auto& a : maTabs)
733  {
734  if (a)
735  a->UpdateCompile();
736  }
737  // Excel-Filter deletes some Tables while loading, Listeners will
738  // only be triggered after the loading is done.
739  if ( !bInsertingFromOtherDoc )
740  {
742 
743  sc::SetFormulaDirtyContext aFormulaDirtyCxt;
744  SetAllFormulasDirty(aFormulaDirtyCxt);
745  }
746 
748  {
749  ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>(this->GetDocumentShell()->GetModel());
751  }
752 
753  bValid = true;
754  }
755  }
756  }
757  return bValid;
758 }
759 
760 bool ScDocument::DeleteTabs( SCTAB nTab, SCTAB nSheets )
761 {
762  bool bValid = false;
763  if (ValidTab(nTab) && (nTab + nSheets) <= static_cast<SCTAB>(maTabs.size()))
764  {
765  if (maTabs[nTab])
766  {
767  SCTAB nTabCount = static_cast<SCTAB>(maTabs.size());
768  if (nTabCount > nSheets)
769  {
770  sc::AutoCalcSwitch aACSwitch(*this, false);
771  sc::RefUpdateDeleteTabContext aCxt( *this, nTab, nSheets);
772 
773  for (SCTAB aTab = 0; aTab < nSheets; ++aTab)
774  {
775  ScRange aRange( 0, 0, nTab, MaxCol(), MaxRow(), nTab + aTab );
776  DelBroadcastAreasInRange( aRange );
777 
778  // #i8180# remove database ranges etc. that are on the deleted tab
779  // (restored in undo with ScRefUndoData)
780 
781  xColNameRanges->DeleteOnTab( nTab + aTab );
782  xRowNameRanges->DeleteOnTab( nTab + aTab );
783  pDBCollection->DeleteOnTab( nTab + aTab );
784  if (pDPCollection)
785  pDPCollection->DeleteOnTab( nTab + aTab );
786  if (pDetOpList)
787  pDetOpList->DeleteOnTab( nTab + aTab );
788  DeleteAreaLinksOnTab( nTab + aTab );
789  }
790 
791  if (pRangeName)
792  pRangeName->UpdateDeleteTab(aCxt);
793 
794  // normal reference update
795 
796  ScRange aRange( 0, 0, nTab, MaxCol(), MaxRow(), nTabCount - 1 );
797  xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1*nSheets );
798  xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1*nSheets );
799  pDBCollection->UpdateReference(
800  URM_INSDEL, 0,0,nTab, MaxCol(),MaxRow(),MAXTAB, 0,0,-1*nSheets );
801  if (pDPCollection)
802  pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1*nSheets );
803  if (pDetOpList)
804  pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1*nSheets );
805  UpdateChartRef( URM_INSDEL, 0,0,nTab, MaxCol(),MaxRow(),MAXTAB, 0,0,-1*nSheets );
806  UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1*nSheets );
807  if (pValidationList)
808  {
810  pValidationList->UpdateDeleteTab(aCxt);
811  }
812  if ( pUnoBroadcaster )
813  pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1*nSheets ) );
814 
815  for (auto & pTab : maTabs)
816  if (pTab)
817  pTab->UpdateDeleteTab(aCxt);
818 
819  maTabs.erase(maTabs.begin() + nTab, maTabs.begin() + nTab + nSheets);
820  // UpdateBroadcastAreas must be called between UpdateDeleteTab,
821  // which ends listening, and StartAllListeners, to not modify
822  // areas that are to be inserted by starting listeners.
823  UpdateBroadcastAreas( URM_INSDEL, aRange, 0,0,-1*nSheets);
824  for (const auto& a : maTabs)
825  {
826  if (a)
827  a->UpdateCompile();
828  }
829  // Excel-Filter deletes some Tables while loading, Listeners will
830  // only be triggered after the loading is done.
831  if ( !bInsertingFromOtherDoc )
832  {
834 
835  sc::SetFormulaDirtyContext aFormulaDirtyCxt;
836  SetAllFormulasDirty(aFormulaDirtyCxt);
837  }
838 
840  {
841  ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>(this->GetDocumentShell()->GetModel());
843  }
844 
845  bValid = true;
846  }
847  }
848  }
849  return bValid;
850 }
851 
852 bool ScDocument::RenameTab( SCTAB nTab, const OUString& rName, bool bExternalDocument )
853 {
854  bool bValid = false;
855  SCTAB i;
856  if (ValidTab(nTab))
857  {
858  if (maTabs[nTab])
859  {
860  if ( bExternalDocument )
861  bValid = true; // composed name
862  else
863  bValid = ValidTabName(rName);
864  for (i=0; (i< static_cast<SCTAB>(maTabs.size())) && bValid; i++)
865  if (maTabs[i] && (i != nTab))
866  {
867  OUString aOldName = maTabs[i]->GetName();
868  bValid = !ScGlobal::GetpTransliteration()->isEqual( rName, aOldName );
869  }
870  if (bValid)
871  {
872  // #i75258# update charts before renaming, so they can get their live data objects.
873  // Once the charts are live, the sheet can be renamed without problems.
875  pChartListenerCollection->UpdateChartsContainingTab( nTab );
876  maTabs[nTab]->SetName(rName);
877 
878  // If formulas refer to the renamed sheet, the TokenArray remains valid,
879  // but the XML stream must be re-generated.
880  for (const auto& a : maTabs)
881  {
882  if (a)
883  a->SetStreamValid( false );
884  }
885 
887  {
888  ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>(this->GetDocumentShell()->GetModel());
890  }
891  }
892  }
893  }
894 
895  collectUIInformation({{"NewName", rName}}, "Rename_Sheet");
896 
897  return bValid;
898 }
899 
900 void ScDocument::SetVisible( SCTAB nTab, bool bVisible )
901 {
902  if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
903  if (maTabs[nTab])
904  maTabs[nTab]->SetVisible(bVisible);
905 }
906 
907 bool ScDocument::IsVisible( SCTAB nTab ) const
908 {
909  if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
910  if (maTabs[nTab])
911  return maTabs[nTab]->IsVisible();
912 
913  return false;
914 }
915 
917 {
918  if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
919  return maTabs[nTab]->IsStreamValid();
920 
921  return false;
922 }
923 
924 void ScDocument::SetStreamValid( SCTAB nTab, bool bSet, bool bIgnoreLock )
925 {
926  if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
927  maTabs[nTab]->SetStreamValid( bSet, bIgnoreLock );
928 }
929 
930 void ScDocument::LockStreamValid( bool bLock )
931 {
932  mbStreamValidLocked = bLock;
933 }
934 
936 {
937  if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
938  return maTabs[nTab]->IsPendingRowHeights();
939 
940  return false;
941 }
942 
944 {
945  if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
946  maTabs[nTab]->SetPendingRowHeights( bSet );
947 }
948 
949 void ScDocument::SetLayoutRTL( SCTAB nTab, bool bRTL )
950 {
951  if ( !(ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab]) )
952  return;
953 
954  if ( bImportingXML )
955  {
956  // #i57869# only set the LoadingRTL flag, the real setting (including mirroring)
957  // is applied in SetImportingXML(false). This is so the shapes can be loaded in
958  // normal LTR mode.
959 
960  maTabs[nTab]->SetLoadingRTL( bRTL );
961  return;
962  }
963 
964  maTabs[nTab]->SetLayoutRTL( bRTL ); // only sets the flag
965  maTabs[nTab]->SetDrawPageSize();
966 
967  // mirror existing objects:
968 
969  if (!mpDrawLayer)
970  return;
971 
972  SdrPage* pPage = mpDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
973  OSL_ENSURE(pPage,"Page ?");
974  if (!pPage)
975  return;
976 
977  SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
978  SdrObject* pObject = aIter.Next();
979  while (pObject)
980  {
981  // objects with ScDrawObjData are re-positioned in SetPageSize,
982  // don't mirror again
984  if ( !pData )
985  mpDrawLayer->MirrorRTL( pObject );
986 
987  pObject->SetContextWritingMode( bRTL ? WritingMode2::RL_TB : WritingMode2::LR_TB );
988 
989  pObject = aIter.Next();
990  }
991 }
992 
993 bool ScDocument::IsLayoutRTL( SCTAB nTab ) const
994 {
995  if ( ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab] )
996  return maTabs[nTab]->IsLayoutRTL();
997 
998  return false;
999 }
1000 
1002 {
1003  // Negative page area is always used for RTL layout.
1004  // The separate method is used to find all RTL handling of drawing objects.
1005  return IsLayoutRTL( nTab );
1006 }
1007 
1008 /* ----------------------------------------------------------------------------
1009  used search area:
1010 
1011  GetCellArea - Only Data
1012  GetTableArea - Data / Attributes
1013  GetPrintArea - intended for character objects,
1014  sweeps attributes all the way to bottom / right
1015 ---------------------------------------------------------------------------- */
1016 
1017 bool ScDocument::GetCellArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
1018 {
1019  if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
1020  if (maTabs[nTab])
1021  return maTabs[nTab]->GetCellArea( rEndCol, rEndRow );
1022 
1023  rEndCol = 0;
1024  rEndRow = 0;
1025  return false;
1026 }
1027 
1028 bool ScDocument::GetTableArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
1029 {
1030  if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
1031  if (maTabs[nTab])
1032  return maTabs[nTab]->GetTableArea( rEndCol, rEndRow );
1033 
1034  rEndCol = 0;
1035  rEndRow = 0;
1036  return false;
1037 }
1038 
1039 bool ScDocument::ShrinkToDataArea(SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow) const
1040 {
1041  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB> (maTabs.size()) || !maTabs[nTab])
1042  return false;
1043 
1044  SCCOL nCol1, nCol2;
1045  SCROW nRow1, nRow2;
1046  maTabs[nTab]->GetFirstDataPos(nCol1, nRow1);
1047  maTabs[nTab]->GetLastDataPos(nCol2, nRow2);
1048 
1049  if (nCol1 > nCol2 || nRow1 > nRow2)
1050  // invalid range.
1051  return false;
1052 
1053  // Make sure the area only shrinks, and doesn't grow.
1054  if (rStartCol < nCol1)
1055  rStartCol = nCol1;
1056  if (nCol2 < rEndCol)
1057  rEndCol = nCol2;
1058  if (rStartRow < nRow1)
1059  rStartRow = nRow1;
1060  if (nRow2 < rEndRow)
1061  rEndRow = nRow2;
1062 
1063  if (rStartCol > rEndCol || rStartRow > rEndRow)
1064  // invalid range.
1065  return false;
1066 
1067  return true; // success!
1068 }
1069 
1070 bool ScDocument::ShrinkToUsedDataArea( bool& o_bShrunk, SCTAB nTab, SCCOL& rStartCol,
1071  SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly,
1072  bool bStickyTopRow, bool bStickyLeftCol, bool bConsiderCellNotes,
1073  bool bConsiderCellDrawObjects ) const
1074 {
1075  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB> (maTabs.size()) || !maTabs[nTab])
1076  {
1077  o_bShrunk = false;
1078  return false;
1079  }
1080  return maTabs[nTab]->ShrinkToUsedDataArea( o_bShrunk, rStartCol, rStartRow, rEndCol, rEndRow,
1081  bColumnsOnly, bStickyTopRow, bStickyLeftCol, bConsiderCellNotes, bConsiderCellDrawObjects );
1082 }
1083 
1084 SCROW ScDocument::GetLastDataRow( SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nLastRow ) const
1085 {
1086  const ScTable* pTab = FetchTable(nTab);
1087  if (!pTab)
1088  return -1;
1089 
1090  return pTab->GetLastDataRow(nCol1, nCol2, nLastRow);
1091 }
1092 
1093 // connected area
1094 
1095 void ScDocument::GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
1096  SCCOL& rEndCol, SCROW& rEndRow, bool bIncludeOld, bool bOnlyDown ) const
1097 {
1098  if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab])
1099  maTabs[nTab]->GetDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bIncludeOld, bOnlyDown );
1100 }
1101 
1103 {
1104  SCTAB nTab = rRange.aStart.Tab();
1105  if (nTab != rRange.aEnd.Tab())
1106  return true;
1107 
1108  if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab])
1109  return maTabs[nTab]->GetDataAreaSubrange(rRange);
1110 
1111  return true;
1112 }
1113 
1114 void ScDocument::LimitChartArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
1115  SCCOL& rEndCol, SCROW& rEndRow )
1116 {
1117  if (ValidTab(nTab) && nTab < static_cast<SCTAB> (maTabs.size()))
1118  if (maTabs[nTab])
1119  maTabs[nTab]->LimitChartArea( rStartCol, rStartRow, rEndCol, rEndRow );
1120 }
1121 
1123 {
1124  ScRangeListRef aNew = new ScRangeList;
1125  if (rRangeList.is())
1126  {
1127  for ( size_t i = 0, nCount = rRangeList->size(); i < nCount; i++ )
1128  {
1129  ScRange aRange( (*rRangeList)[i] );
1130  if ( ( aRange.aStart.Col() == 0 && aRange.aEnd.Col() == MaxCol() ) ||
1131  ( aRange.aStart.Row() == 0 && aRange.aEnd.Row() == MaxRow() ) )
1132  {
1133  SCCOL nStartCol = aRange.aStart.Col();
1134  SCROW nStartRow = aRange.aStart.Row();
1135  SCCOL nEndCol = aRange.aEnd.Col();
1136  SCROW nEndRow = aRange.aEnd.Row();
1137  SCTAB nTab = aRange.aStart.Tab();
1138  if ( nTab < static_cast<SCTAB> (maTabs.size()) && maTabs[nTab])
1139  maTabs[nTab]->LimitChartArea(nStartCol, nStartRow, nEndCol, nEndRow);
1140  aRange.aStart.SetCol( nStartCol );
1141  aRange.aStart.SetRow( nStartRow );
1142  aRange.aEnd.SetCol( nEndCol );
1143  aRange.aEnd.SetRow( nEndRow );
1144  }
1145  aNew->push_back(aRange);
1146  }
1147  }
1148  else
1149  {
1150  OSL_FAIL("LimitChartIfAll: Ref==0");
1151  }
1152  rRangeList = aNew;
1153 }
1154 
1155 static void lcl_GetFirstTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark, SCTAB aMaxTab )
1156 {
1157  // without ScMarkData, leave start/end unchanged
1158  if ( !pTabMark )
1159  return;
1160 
1161  for (SCTAB nTab=0; nTab< aMaxTab; ++nTab)
1162  if (pTabMark->GetTableSelect(nTab))
1163  {
1164  // find first range of consecutive selected sheets
1165  rTabRangeStart = pTabMark->GetFirstSelected();
1166  while ( nTab+1 < aMaxTab && pTabMark->GetTableSelect(nTab+1) )
1167  ++nTab;
1168  rTabRangeEnd = nTab;
1169  return;
1170  }
1171 }
1172 
1173 static bool lcl_GetNextTabRange( SCTAB& rTabRangeStart, SCTAB& rTabRangeEnd, const ScMarkData* pTabMark, SCTAB aMaxTab )
1174 {
1175  if ( pTabMark )
1176  {
1177  // find next range of consecutive selected sheets after rTabRangeEnd
1178  for (SCTAB nTab=rTabRangeEnd+1; nTab< aMaxTab; ++nTab)
1179  if (pTabMark->GetTableSelect(nTab))
1180  {
1181  rTabRangeStart = nTab;
1182  while ( nTab+1 < aMaxTab && pTabMark->GetTableSelect(nTab+1) )
1183  ++nTab;
1184  rTabRangeEnd = nTab;
1185  return true;
1186  }
1187  }
1188  return false;
1189 }
1190 
1191 bool ScDocument::CanInsertRow( const ScRange& rRange ) const
1192 {
1193  SCCOL nStartCol = rRange.aStart.Col();
1194  SCROW nStartRow = rRange.aStart.Row();
1195  SCTAB nStartTab = rRange.aStart.Tab();
1196  SCCOL nEndCol = rRange.aEnd.Col();
1197  SCROW nEndRow = rRange.aEnd.Row();
1198  SCTAB nEndTab = rRange.aEnd.Tab();
1199  PutInOrder( nStartCol, nEndCol );
1200  PutInOrder( nStartRow, nEndRow );
1201  PutInOrder( nStartTab, nEndTab );
1202  SCSIZE nSize = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
1203 
1204  bool bTest = true;
1205  for (SCTAB i=nStartTab; i<=nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
1206  if (maTabs[i])
1207  bTest &= maTabs[i]->TestInsertRow( nStartCol, nEndCol, nStartRow, nSize );
1208 
1209  return bTest;
1210 }
1211 
1212 namespace {
1213 
1214 struct SetDirtyIfPostponedHandler
1215 {
1216  void operator() (const ScTableUniquePtr & p)
1217  {
1218  if (p)
1219  p->SetDirtyIfPostponed();
1220  }
1221 };
1222 
1223 struct BroadcastRecalcOnRefMoveHandler
1224 {
1225  void operator() (const ScTableUniquePtr & p)
1226  {
1227  if (p)
1228  p->BroadcastRecalcOnRefMove();
1229  }
1230 };
1231 
1232 struct BroadcastRecalcOnRefMoveGuard
1233 {
1234  explicit BroadcastRecalcOnRefMoveGuard( ScDocument* pDoc ) :
1235  aSwitch( *pDoc, false),
1236  aBulk( pDoc->GetBASM(), SfxHintId::ScDataChanged)
1237  {
1238  }
1239 
1240 private:
1241  sc::AutoCalcSwitch aSwitch; // first for ctor/dtor order, destroy second
1242  ScBulkBroadcast aBulk; // second for ctor/dtor order, destroy first
1243 };
1244 
1245 }
1246 
1247 bool ScDocument::InsertRow( SCCOL nStartCol, SCTAB nStartTab,
1248  SCCOL nEndCol, SCTAB nEndTab,
1249  SCROW nStartRow, SCSIZE nSize, ScDocument* pRefUndoDoc,
1250  const ScMarkData* pTabMark )
1251 {
1252  SCTAB i;
1253 
1254  PutInOrder( nStartCol, nEndCol );
1255  PutInOrder( nStartTab, nEndTab );
1256  if ( pTabMark )
1257  {
1258  nStartTab = 0;
1259  nEndTab = static_cast<SCTAB>(maTabs.size()) -1;
1260  }
1261 
1262  bool bTest = true;
1263  bool bRet = false;
1264  bool bOldAutoCalc = GetAutoCalc();
1265  SetAutoCalc( false ); // avoid multiple calculations
1266  for ( i = nStartTab; i <= nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
1267  if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1268  bTest &= maTabs[i]->TestInsertRow(nStartCol, nEndCol, nStartRow, nSize);
1269  if (bTest)
1270  {
1271  // UpdateBroadcastAreas have to be called before UpdateReference, so that entries
1272  // aren't shifted that would be rebuild at UpdateReference
1273 
1274  // handle chunks of consecutive selected sheets together
1275  SCTAB nTabRangeStart = nStartTab;
1276  SCTAB nTabRangeEnd = nEndTab;
1277  lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1278  ScRange aShiftedRange(nStartCol, nStartRow, nTabRangeStart, nEndCol, MaxRow(), nTabRangeEnd);
1279  sc::EndListeningContext aEndListenCxt(*this);
1280 
1281  std::vector<ScAddress> aGroupPos;
1282  do
1283  {
1284  aShiftedRange.aStart.SetTab(nTabRangeStart);
1285  aShiftedRange.aEnd.SetTab(nTabRangeEnd);
1286 
1287  // Collect all formula groups that will get split by the shifting,
1288  // and end all their listening. Record the position of the top
1289  // cell of the topmost group, and the position of the bottom cell
1290  // of the bottommost group.
1291  EndListeningIntersectedGroups(aEndListenCxt, aShiftedRange, &aGroupPos);
1292 
1293  UpdateBroadcastAreas(URM_INSDEL, aShiftedRange, 0, static_cast<SCROW>(nSize), 0);
1294  }
1295  while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1296 
1297  lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1298 
1299  sc::RefUpdateContext aCxt(*this);
1300  aCxt.meMode = URM_INSDEL;
1301  aCxt.maRange = aShiftedRange;
1302  aCxt.mnRowDelta = nSize;
1303  do
1304  {
1305  aCxt.maRange.aStart.SetTab(nTabRangeStart);
1306  aCxt.maRange.aEnd.SetTab(nTabRangeEnd);
1307  UpdateReference(aCxt, pRefUndoDoc, false); // without drawing objects
1308  }
1309  while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1310 
1311  // UpdateReference should have set "needs listening" flags to those
1312  // whose references have been modified. We also need to set this flag
1313  // to those that were in the groups that got split by shifting.
1314  SetNeedsListeningGroups(aGroupPos);
1315 
1316  for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
1317  if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1318  maTabs[i]->InsertRow( nStartCol, nEndCol, nStartRow, nSize );
1319 
1320  // UpdateRef for drawing layer must be after inserting,
1321  // when the new row heights are known.
1322  for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
1323  if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1324  maTabs[i]->UpdateDrawRef( URM_INSDEL,
1325  nStartCol, nStartRow, nStartTab, nEndCol, MaxRow(), nEndTab,
1326  0, static_cast<SCROW>(nSize), 0 );
1327 
1328  if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
1329  { // A new Listening is needed when references to deleted ranges are restored,
1330  // previous Listeners were removed in FormulaCell UpdateReference.
1332  }
1333  else
1334  { // Listeners have been removed in UpdateReference
1336 
1337  // At least all cells using range names pointing relative to the
1338  // moved range must be recalculated, and all cells marked postponed
1339  // dirty.
1340  for (const auto& a : maTabs)
1341  {
1342  if (a)
1343  a->SetDirtyIfPostponed();
1344  }
1345 
1346  {
1347  BroadcastRecalcOnRefMoveGuard g(this);
1348  std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler());
1349  }
1350  }
1351  bRet = true;
1352  }
1353  SetAutoCalc( bOldAutoCalc );
1354  if ( bRet && pChartListenerCollection )
1355  pChartListenerCollection->UpdateDirtyCharts();
1356  return bRet;
1357 }
1358 
1359 bool ScDocument::InsertRow( const ScRange& rRange )
1360 {
1361  return InsertRow( rRange.aStart.Col(), rRange.aStart.Tab(),
1362  rRange.aEnd.Col(), rRange.aEnd.Tab(),
1363  rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1) );
1364 }
1365 
1366 void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
1367  SCCOL nEndCol, SCTAB nEndTab,
1368  SCROW nStartRow, SCSIZE nSize,
1369  ScDocument* pRefUndoDoc, bool* pUndoOutline,
1370  const ScMarkData* pTabMark )
1371 {
1372  SCTAB i;
1373 
1374  PutInOrder( nStartCol, nEndCol );
1375  PutInOrder( nStartTab, nEndTab );
1376  if ( pTabMark )
1377  {
1378  nStartTab = 0;
1379  nEndTab = static_cast<SCTAB>(maTabs.size())-1;
1380  }
1381 
1382  sc::AutoCalcSwitch aACSwitch(*this, false); // avoid multiple calculations
1383 
1384  // handle chunks of consecutive selected sheets together
1385  SCTAB nTabRangeStart = nStartTab;
1386  SCTAB nTabRangeEnd = nEndTab;
1387  lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1388  do
1389  {
1390  if ( ValidRow(nStartRow+nSize) )
1391  {
1393  ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1394  ScAddress( nEndCol, nStartRow+nSize-1, nTabRangeEnd ) ) );
1396  ScAddress( nStartCol, nStartRow+nSize, nTabRangeStart ),
1397  ScAddress( nEndCol, MaxRow(), nTabRangeEnd )), 0, -static_cast<SCROW>(nSize), 0 );
1398  }
1399  else
1401  ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1402  ScAddress( nEndCol, MaxRow(), nTabRangeEnd ) ) );
1403  }
1404  while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1405 
1406  sc::RefUpdateContext aCxt(*this);
1407  const bool bLastRowIncluded = (nStartRow + nSize == MAXROWCOUNT && ValidRow(nStartRow));
1408  if ( ValidRow(nStartRow+nSize) || bLastRowIncluded )
1409  {
1410  lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1411  aCxt.meMode = URM_INSDEL;
1412  aCxt.mnRowDelta = -static_cast<SCROW>(nSize);
1413  if (bLastRowIncluded)
1414  {
1415  // Last row is included, shift a virtually non-existent row in.
1416  aCxt.maRange = ScRange( nStartCol, MAXROWCOUNT, nTabRangeStart, nEndCol, MAXROWCOUNT, nTabRangeEnd);
1417  }
1418  else
1419  {
1420  aCxt.maRange = ScRange( nStartCol, nStartRow+nSize, nTabRangeStart, nEndCol, MaxRow(), nTabRangeEnd);
1421  }
1422  do
1423  {
1424  UpdateReference(aCxt, pRefUndoDoc, true, false);
1425  }
1426  while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1427  }
1428 
1429  if (pUndoOutline)
1430  *pUndoOutline = false;
1431 
1432  // Keep track of the positions of all formula groups that have been joined
1433  // during row deletion.
1434  std::vector<ScAddress> aGroupPos;
1435 
1436  for ( i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
1437  if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1438  maTabs[i]->DeleteRow(aCxt.maRegroupCols, nStartCol, nEndCol, nStartRow, nSize, pUndoOutline, &aGroupPos);
1439 
1440  // Newly joined groups have some of their members still listening. We
1441  // need to make sure none of them are listening.
1442  EndListeningGroups(aGroupPos);
1443 
1444  // Mark all joined groups for group listening.
1445  SetNeedsListeningGroups(aGroupPos);
1446 
1447  if ( ValidRow(nStartRow+nSize) || bLastRowIncluded )
1448  {
1449  // Listeners have been removed in UpdateReference
1451 
1452  // At least all cells using range names pointing relative to the moved
1453  // range must be recalculated, and all cells marked postponed dirty.
1454  for (const auto& a : maTabs)
1455  {
1456  if (a)
1457  a->SetDirtyIfPostponed();
1458  }
1459 
1460  {
1461  BroadcastRecalcOnRefMoveGuard g(this);
1462  std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler());
1463  }
1464  }
1465 
1467  pChartListenerCollection->UpdateDirtyCharts();
1468 }
1469 
1470 void ScDocument::DeleteRow( const ScRange& rRange )
1471 {
1472  DeleteRow( rRange.aStart.Col(), rRange.aStart.Tab(),
1473  rRange.aEnd.Col(), rRange.aEnd.Tab(),
1474  rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1) );
1475 }
1476 
1477 bool ScDocument::CanInsertCol( const ScRange& rRange ) const
1478 {
1479  SCCOL nStartCol = rRange.aStart.Col();
1480  SCROW nStartRow = rRange.aStart.Row();
1481  SCTAB nStartTab = rRange.aStart.Tab();
1482  SCCOL nEndCol = rRange.aEnd.Col();
1483  SCROW nEndRow = rRange.aEnd.Row();
1484  SCTAB nEndTab = rRange.aEnd.Tab();
1485  PutInOrder( nStartCol, nEndCol );
1486  PutInOrder( nStartRow, nEndRow );
1487  PutInOrder( nStartTab, nEndTab );
1488  SCSIZE nSize = static_cast<SCSIZE>(nEndCol - nStartCol + 1);
1489 
1490  bool bTest = true;
1491  for (SCTAB i=nStartTab; i<=nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
1492  if (maTabs[i])
1493  bTest &= maTabs[i]->TestInsertCol( nStartRow, nEndRow, nSize );
1494 
1495  return bTest;
1496 }
1497 
1498 bool ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
1499  SCROW nEndRow, SCTAB nEndTab,
1500  SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
1501  const ScMarkData* pTabMark )
1502 {
1503  SCTAB i;
1504 
1505  PutInOrder( nStartRow, nEndRow );
1506  PutInOrder( nStartTab, nEndTab );
1507  if ( pTabMark )
1508  {
1509  nStartTab = 0;
1510  nEndTab = static_cast<SCTAB>(maTabs.size())-1;
1511  }
1512 
1513  bool bTest = true;
1514  bool bRet = false;
1515  bool bOldAutoCalc = GetAutoCalc();
1516  SetAutoCalc( false ); // avoid multiple calculations
1517  for ( i = nStartTab; i <= nEndTab && bTest && i < static_cast<SCTAB>(maTabs.size()); i++)
1518  if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1519  bTest &= maTabs[i]->TestInsertCol( nStartRow, nEndRow, nSize );
1520  if (bTest)
1521  {
1522  // handle chunks of consecutive selected sheets together
1523  SCTAB nTabRangeStart = nStartTab;
1524  SCTAB nTabRangeEnd = nEndTab;
1525  lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1526  do
1527  {
1529  ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1530  ScAddress( MaxCol(), nEndRow, nTabRangeEnd )), static_cast<SCCOL>(nSize), 0, 0 );
1531  }
1532  while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1533 
1534  lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1535 
1536  sc::RefUpdateContext aCxt(*this);
1537  aCxt.meMode = URM_INSDEL;
1538  aCxt.maRange = ScRange(nStartCol, nStartRow, nTabRangeStart, MaxCol(), nEndRow, nTabRangeEnd);
1539  aCxt.mnColDelta = nSize;
1540  do
1541  {
1542  UpdateReference(aCxt, pRefUndoDoc, true, false);
1543  }
1544  while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1545 
1546  for (i=nStartTab; i<=nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
1547  if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1548  maTabs[i]->InsertCol(aCxt.maRegroupCols, nStartCol, nStartRow, nEndRow, nSize);
1549 
1550  if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
1551  { // A new Listening is needed when references to deleted ranges are restored,
1552  // previous Listeners were removed in FormulaCell UpdateReference.
1554  }
1555  else
1556  {
1557  // Listeners have been removed in UpdateReference
1559  // At least all cells using range names pointing relative to the
1560  // moved range must be recalculated, and all cells marked postponed
1561  // dirty.
1562  std::for_each(maTabs.begin(), maTabs.end(), SetDirtyIfPostponedHandler());
1563  // Cells containing functions such as CELL, COLUMN or ROW may have
1564  // changed their values on relocation. Broadcast them.
1565  {
1566  BroadcastRecalcOnRefMoveGuard g(this);
1567  std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler());
1568  }
1569  }
1570  bRet = true;
1571  }
1572  SetAutoCalc( bOldAutoCalc );
1573  if ( bRet && pChartListenerCollection )
1574  pChartListenerCollection->UpdateDirtyCharts();
1575  return bRet;
1576 }
1577 
1578 bool ScDocument::InsertCol( const ScRange& rRange )
1579 {
1580  return InsertCol( rRange.aStart.Row(), rRange.aStart.Tab(),
1581  rRange.aEnd.Row(), rRange.aEnd.Tab(),
1582  rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1) );
1583 }
1584 
1585 void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTAB nEndTab,
1586  SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
1587  bool* pUndoOutline, const ScMarkData* pTabMark )
1588 {
1589  SCTAB i;
1590 
1591  PutInOrder( nStartRow, nEndRow );
1592  PutInOrder( nStartTab, nEndTab );
1593  if ( pTabMark )
1594  {
1595  nStartTab = 0;
1596  nEndTab = static_cast<SCTAB>(maTabs.size())-1;
1597  }
1598 
1599  sc::AutoCalcSwitch aACSwitch(*this, false); // avoid multiple calculations
1600 
1601  // handle chunks of consecutive selected sheets together
1602  SCTAB nTabRangeStart = nStartTab;
1603  SCTAB nTabRangeEnd = nEndTab;
1604  lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1605  do
1606  {
1607  if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
1608  {
1610  ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1611  ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize-1), nEndRow, nTabRangeEnd ) ) );
1613  ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart ),
1614  ScAddress( MaxCol(), nEndRow, nTabRangeEnd )), -static_cast<SCCOL>(nSize), 0, 0 );
1615  }
1616  else
1618  ScAddress( nStartCol, nStartRow, nTabRangeStart ),
1619  ScAddress( MaxCol(), nEndRow, nTabRangeEnd ) ) );
1620  }
1621  while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1622 
1623  sc::RefUpdateContext aCxt(*this);
1624  const bool bLastColIncluded = (nStartCol + nSize == MAXCOLCOUNT && ValidCol(nStartCol));
1625  if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) || bLastColIncluded )
1626  {
1627  lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
1628  aCxt.meMode = URM_INSDEL;
1629  aCxt.mnColDelta = -static_cast<SCCOL>(nSize);
1630  if (bLastColIncluded)
1631  {
1632  // Last column is included, shift a virtually non-existent column in.
1633  aCxt.maRange = ScRange( MAXCOLCOUNT, nStartRow, nTabRangeStart, MAXCOLCOUNT, nEndRow, nTabRangeEnd);
1634  }
1635  else
1636  {
1637  aCxt.maRange = ScRange( sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart,
1638  MaxCol(), nEndRow, nTabRangeEnd);
1639  }
1640  do
1641  {
1642  UpdateReference(aCxt, pRefUndoDoc, true, false);
1643  }
1644  while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
1645  }
1646 
1647  if (pUndoOutline)
1648  *pUndoOutline = false;
1649 
1650  for (i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); ++i)
1651  {
1652  if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
1653  maTabs[i]->DeleteCol(aCxt.maRegroupCols, nStartCol, nStartRow, nEndRow, nSize, pUndoOutline);
1654  }
1655 
1656  if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) || bLastColIncluded )
1657  {
1658  // Listeners have been removed in UpdateReference
1660 
1661  // At least all cells using range names pointing relative to the moved
1662  // range must be recalculated, and all cells marked postponed dirty.
1663  for (const auto& a : maTabs)
1664  {
1665  if (a)
1666  a->SetDirtyIfPostponed();
1667  }
1668 
1669  {
1670  BroadcastRecalcOnRefMoveGuard g(this);
1671  std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler());
1672  }
1673  }
1674 
1676  pChartListenerCollection->UpdateDirtyCharts();
1677 }
1678 
1679 void ScDocument::DeleteCol( const ScRange& rRange )
1680 {
1681  DeleteCol( rRange.aStart.Row(), rRange.aStart.Tab(),
1682  rRange.aEnd.Row(), rRange.aEnd.Tab(),
1683  rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1) );
1684 }
1685 
1686 // for Area-Links: Insert/delete cells, when the range is changed.
1687 // (without Paint)
1688 
1689 static void lcl_GetInsDelRanges( const ScRange& rOld, const ScRange& rNew,
1690  ScRange& rColRange, bool& rInsCol, bool& rDelCol,
1691  ScRange& rRowRange, bool& rInsRow, bool& rDelRow )
1692 {
1693  OSL_ENSURE( rOld.aStart == rNew.aStart, "FitBlock: Beginning is different" );
1694 
1695  rInsCol = rDelCol = rInsRow = rDelRow = false;
1696 
1697  SCCOL nStartX = rOld.aStart.Col();
1698  SCROW nStartY = rOld.aStart.Row();
1699  SCCOL nOldEndX = rOld.aEnd.Col();
1700  SCROW nOldEndY = rOld.aEnd.Row();
1701  SCCOL nNewEndX = rNew.aEnd.Col();
1702  SCROW nNewEndY = rNew.aEnd.Row();
1703  SCTAB nTab = rOld.aStart.Tab();
1704 
1705  // if more rows, columns are inserted/deleted at the old height.
1706  bool bGrowY = ( nNewEndY > nOldEndY );
1707  SCROW nColEndY = bGrowY ? nOldEndY : nNewEndY;
1708  SCCOL nRowEndX = bGrowY ? nNewEndX : nOldEndX;
1709 
1710  // Columns
1711 
1712  if ( nNewEndX > nOldEndX ) // Insert columns
1713  {
1714  rColRange = ScRange( nOldEndX+1, nStartY, nTab, nNewEndX, nColEndY, nTab );
1715  rInsCol = true;
1716  }
1717  else if ( nNewEndX < nOldEndX ) // Delete columns
1718  {
1719  rColRange = ScRange( nNewEndX+1, nStartY, nTab, nOldEndX, nColEndY, nTab );
1720  rDelCol = true;
1721  }
1722 
1723  // Rows
1724 
1725  if ( nNewEndY > nOldEndY ) // Insert rows
1726  {
1727  rRowRange = ScRange( nStartX, nOldEndY+1, nTab, nRowEndX, nNewEndY, nTab );
1728  rInsRow = true;
1729  }
1730  else if ( nNewEndY < nOldEndY ) // Delete rows
1731  {
1732  rRowRange = ScRange( nStartX, nNewEndY+1, nTab, nRowEndX, nOldEndY, nTab );
1733  rDelRow = true;
1734  }
1735 }
1736 
1738 {
1739  bool bPart = false;
1740  SCTAB nTab = rRange.aStart.Tab();
1741 
1742  SCCOL nStartX = rRange.aStart.Col();
1743  SCROW nStartY = rRange.aStart.Row();
1744  SCCOL nEndX = rRange.aEnd.Col();
1745  SCROW nEndY = rRange.aEnd.Row();
1746 
1747  if (HasAttrib( nStartX, nStartY, nTab, nEndX, nEndY, nTab,
1749  {
1750  ExtendMerge( nStartX, nStartY, nEndX, nEndY, nTab );
1751  ExtendOverlapped( nStartX, nStartY, nEndX, nEndY, nTab );
1752 
1753  bPart = ( nStartX != rRange.aStart.Col() || nEndX != rRange.aEnd.Col() ||
1754  nStartY != rRange.aStart.Row() || nEndY != rRange.aEnd.Row() );
1755  }
1756  return bPart;
1757 }
1758 
1759 size_t ScDocument::GetFormulaHash( const ScAddress& rPos ) const
1760 {
1761  SCTAB nTab = rPos.Tab();
1762  if (!ValidTab(nTab) || o3tl::make_unsigned(nTab) >= maTabs.size() || !maTabs[nTab])
1763  return 0;
1764 
1765  return maTabs[nTab]->GetFormulaHash(rPos.Col(), rPos.Row());
1766 }
1767 
1769 {
1770  SCTAB nTab = rPos.Tab();
1771  if (!ValidTab(nTab) || o3tl::make_unsigned(nTab) >= maTabs.size() || !maTabs[nTab])
1772  return FormulaVectorUnknown;
1773 
1774  return maTabs[nTab]->GetFormulaVectorState(rPos.Col(), rPos.Row());
1775 }
1776 
1778 {
1779  SCTAB nTab = rPos.Tab();
1780  if (!TableExists(nTab))
1781  return formula::FormulaTokenRef();
1782 
1783  return maTabs[nTab]->ResolveStaticReference(rPos.Col(), rPos.Row());
1784 }
1785 
1787 {
1788  SCTAB nTab = rRange.aStart.Tab();
1789  if (nTab != rRange.aEnd.Tab() || !TableExists(nTab))
1790  return formula::FormulaTokenRef();
1791 
1792  return maTabs[nTab]->ResolveStaticReference(
1793  rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
1794 }
1795 
1797 {
1798  SCTAB nTab = rPos.Tab();
1799  if (!TableExists(nTab))
1800  return formula::VectorRefArray();
1801 
1802  return maTabs[nTab]->FetchVectorRefArray(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
1803 }
1804 
1805 #ifdef DBG_UTIL
1807 {
1808  SCTAB nTab = rPos.Tab();
1809  assert(TableExists(nTab));
1810  return maTabs[nTab]->AssertNoInterpretNeeded(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
1811 }
1812 #endif
1813 
1815 {
1817  if(nAdjustHeightLock > 0)
1819 }
1820 
1822 {
1823  SCTAB nTab = rPos.Tab();
1824  if (!TableExists(nTab))
1825  return false;
1826 
1827  return maTabs[nTab]->HandleRefArrayForParallelism(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1, mxGroup);
1828 }
1829 
1830 bool ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
1831 {
1832  if ( rOld == rNew )
1833  return true;
1834 
1835  bool bOk = true;
1836  bool bInsCol,bDelCol,bInsRow,bDelRow;
1837  ScRange aColRange,aRowRange;
1838  lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
1839 
1840  if ( bInsCol && !CanInsertCol( aColRange ) ) // Cells at the edge ?
1841  bOk = false;
1842  if ( bInsRow && !CanInsertRow( aRowRange ) ) // Cells at the edge ?
1843  bOk = false;
1844 
1845  if ( bInsCol || bDelCol )
1846  {
1847  aColRange.aEnd.SetCol(MaxCol());
1848  if ( HasPartOfMerged(aColRange) )
1849  bOk = false;
1850  }
1851  if ( bInsRow || bDelRow )
1852  {
1853  aRowRange.aEnd.SetRow(MaxRow());
1854  if ( HasPartOfMerged(aRowRange) )
1855  bOk = false;
1856  }
1857 
1858  return bOk;
1859 }
1860 
1861 void ScDocument::FitBlock( const ScRange& rOld, const ScRange& rNew, bool bClear )
1862 {
1863  if (bClear)
1865 
1866  bool bInsCol,bDelCol,bInsRow,bDelRow;
1867  ScRange aColRange,aRowRange;
1868  lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
1869 
1870  if ( bInsCol )
1871  InsertCol( aColRange ); // First insert columns
1872  if ( bInsRow )
1873  InsertRow( aRowRange );
1874 
1875  if ( bDelRow )
1876  DeleteRow( aRowRange ); // First delete rows
1877  if ( bDelCol )
1878  DeleteCol( aColRange );
1879 
1880  // Expand references to inserted rows
1881 
1882  if ( bInsCol || bInsRow )
1883  {
1884  ScRange aGrowSource = rOld;
1885  aGrowSource.aEnd.SetCol(std::min( rOld.aEnd.Col(), rNew.aEnd.Col() ));
1886  aGrowSource.aEnd.SetRow(std::min( rOld.aEnd.Row(), rNew.aEnd.Row() ));
1887  SCCOL nGrowX = bInsCol ? ( rNew.aEnd.Col() - rOld.aEnd.Col() ) : 0;
1888  SCROW nGrowY = bInsRow ? ( rNew.aEnd.Row() - rOld.aEnd.Row() ) : 0;
1889  UpdateGrow( aGrowSource, nGrowX, nGrowY );
1890  }
1891 }
1892 
1894  SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const ScMarkData& rMark,
1895  InsertDeleteFlags nDelFlag, bool bBroadcast, sc::ColumnSpanSet* pBroadcastSpans )
1896 {
1897  sc::AutoCalcSwitch aACSwitch(*this, false);
1898 
1899  PutInOrder( nCol1, nCol2 );
1900  PutInOrder( nRow1, nRow2 );
1901 
1902  std::vector<ScAddress> aGroupPos;
1903  // Destroy and reconstruct listeners only if content is affected.
1904  bool bDelContent = ((nDelFlag & ~InsertDeleteFlags::CONTENTS) != nDelFlag);
1905  if (bDelContent)
1906  {
1907  // Record the positions of top and/or bottom formula groups that intersect
1908  // the area borders.
1909  sc::EndListeningContext aCxt(*this);
1910  ScRange aRange(nCol1, nRow1, 0, nCol2, nRow2, 0);
1911  for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); i++)
1912  {
1913  if (rMark.GetTableSelect(i))
1914  {
1915  aRange.aStart.SetTab(i);
1916  aRange.aEnd.SetTab(i);
1917 
1918  EndListeningIntersectedGroups(aCxt, aRange, &aGroupPos);
1919  }
1920  }
1921  aCxt.purgeEmptyBroadcasters();
1922  }
1923 
1924  for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); i++)
1925  if (maTabs[i])
1926  if ( rMark.GetTableSelect(i) || bIsUndo )
1927  maTabs[i]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag, bBroadcast, pBroadcastSpans);
1928 
1929  if (!bDelContent)
1930  return;
1931 
1932  // Re-start listeners on those top bottom groups that have been split.
1933  SetNeedsListeningGroups(aGroupPos);
1935 
1936  // If formula groups were split their listeners were destroyed and may
1937  // need to be notified now that they're restored, ScTable::DeleteArea()
1938  // couldn't do that.
1939  if (aGroupPos.empty())
1940  return;
1941 
1942  ScRange aRange(nCol1, nRow1, 0, nCol2, nRow2, 0);
1943  for (SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); i++)
1944  {
1945  if (rMark.GetTableSelect(i))
1946  {
1947  aRange.aStart.SetTab(i);
1948  aRange.aEnd.SetTab(i);
1949  SetDirty( aRange, true);
1950  }
1951  }
1952 }
1953 
1955  SCCOL nCol2, SCROW nRow2,
1956  SCTAB nTab, InsertDeleteFlags nDelFlag)
1957 {
1958  PutInOrder( nCol1, nCol2 );
1959  PutInOrder( nRow1, nRow2 );
1960  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
1961  {
1962  bool bOldAutoCalc = GetAutoCalc();
1963  SetAutoCalc( false ); // avoid multiple calculations
1964  maTabs[nTab]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
1965  SetAutoCalc( bOldAutoCalc );
1966  }
1967 }
1968 
1969 void ScDocument::DeleteAreaTab( const ScRange& rRange, InsertDeleteFlags nDelFlag )
1970 {
1971  for ( SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); nTab++ )
1972  DeleteAreaTab( rRange.aStart.Col(), rRange.aStart.Row(),
1973  rRange.aEnd.Col(), rRange.aEnd.Row(),
1974  nTab, nDelFlag );
1975 }
1976 
1977 void ScDocument::InitUndoSelected( const ScDocument* pSrcDoc, const ScMarkData& rTabSelection,
1978  bool bColInfo, bool bRowInfo )
1979 {
1980  if (bIsUndo)
1981  {
1982  Clear();
1983 
1984  SharePooledResources(pSrcDoc);
1985 
1986  for (SCTAB nTab = 0; nTab <= rTabSelection.GetLastSelected(); nTab++)
1987  if ( rTabSelection.GetTableSelect( nTab ) )
1988  {
1989  ScTableUniquePtr pTable(new ScTable(this, nTab, OUString(), bColInfo, bRowInfo));
1990  if (nTab < static_cast<SCTAB>(maTabs.size()))
1991  maTabs[nTab] = std::move(pTable);
1992  else
1993  maTabs.push_back(std::move(pTable));
1994  }
1995  else
1996  {
1997  if (nTab < static_cast<SCTAB>(maTabs.size()))
1998  maTabs[nTab]=nullptr;
1999  else
2000  maTabs.push_back(nullptr);
2001  }
2002  }
2003  else
2004  {
2005  OSL_FAIL("InitUndo");
2006  }
2007 }
2008 
2009 void ScDocument::InitUndo( const ScDocument* pSrcDoc, SCTAB nTab1, SCTAB nTab2,
2010  bool bColInfo, bool bRowInfo )
2011 {
2012  if (!bIsUndo)
2013  {
2014  OSL_FAIL("InitUndo");
2015  return;
2016  }
2017 
2018  Clear();
2019 
2020  // Undo document shares its pooled resources with the source document.
2021  SharePooledResources(pSrcDoc);
2022 
2023  if (pSrcDoc->mpShell->GetMedium())
2025 
2026  if ( nTab2 >= static_cast<SCTAB>(maTabs.size()))
2027  maTabs.resize(nTab2 + 1);
2028  for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
2029  {
2030  maTabs[nTab].reset(new ScTable(this, nTab, OUString(), bColInfo, bRowInfo));
2031  }
2032 }
2033 
2034 void ScDocument::AddUndoTab( SCTAB nTab1, SCTAB nTab2, bool bColInfo, bool bRowInfo )
2035 {
2036  if (!bIsUndo)
2037  {
2038  OSL_FAIL("AddUndoTab");
2039  return;
2040  }
2041 
2042  if (nTab2 >= static_cast<SCTAB>(maTabs.size()))
2043  {
2044  maTabs.resize(nTab2+1);
2045  }
2046 
2047  for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
2048  if (!maTabs[nTab])
2049  {
2050  maTabs[nTab].reset( new ScTable(this, nTab, OUString(), bColInfo, bRowInfo) );
2051  }
2052 }
2053 
2054 void ScDocument::SetCutMode( bool bVal )
2055 {
2056  if (bIsClip)
2057  GetClipParam().mbCutMode = bVal;
2058  else
2059  {
2060  OSL_FAIL("SetCutMode without bIsClip");
2061  }
2062 }
2063 
2065 {
2066  if (bIsClip)
2067  return GetClipParam().mbCutMode;
2068  else
2069  {
2070  OSL_FAIL("IsCutMode without bIsClip");
2071  return false;
2072  }
2073 }
2074 
2075 void ScDocument::CopyToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
2076  SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
2077  InsertDeleteFlags nFlags, bool bOnlyMarked, ScDocument& rDestDoc,
2078  const ScMarkData* pMarks, bool bColRowFlags )
2079 {
2080  if (ValidTab(nTab1) && ValidTab(nTab2))
2081  {
2082  ScRange aThisRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
2083  CopyToDocument(aThisRange, nFlags, bOnlyMarked, rDestDoc, pMarks, bColRowFlags);
2084  }
2085 }
2086 
2087 void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
2088  SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
2089  InsertDeleteFlags nFlags, bool bOnlyMarked, ScDocument& rDestDoc)
2090 {
2091  PutInOrder( nCol1, nCol2 );
2092  PutInOrder( nRow1, nRow2 );
2093  PutInOrder( nTab1, nTab2 );
2094  if (!(ValidTab(nTab1) && ValidTab(nTab2)))
2095  return;
2096 
2097  sc::AutoCalcSwitch aACSwitch(rDestDoc, false); // avoid multiple calculations
2098 
2099  if (nTab1 > 0)
2100  CopyToDocument(0, 0, 0, MaxCol(), MaxRow(), nTab1-1, InsertDeleteFlags::FORMULA, false, rDestDoc);
2101 
2102  sc::CopyToDocContext aCxt(rDestDoc);
2103  assert( nTab2 < static_cast<SCTAB>(maTabs.size()) && nTab2 < static_cast<SCTAB>(rDestDoc.maTabs.size()));
2104  for (SCTAB i = nTab1; i <= nTab2; i++)
2105  {
2106  if (maTabs[i] && rDestDoc.maTabs[i])
2107  maTabs[i]->UndoToTable(aCxt, nCol1, nRow1, nCol2, nRow2, nFlags,
2108  bOnlyMarked, rDestDoc.maTabs[i].get());
2109  }
2110 
2111  if (nTab2 < MAXTAB)
2112  CopyToDocument(0, 0, nTab2+1, MaxCol(), MaxRow(), MAXTAB, InsertDeleteFlags::FORMULA, false, rDestDoc);
2113 }
2114 
2116  InsertDeleteFlags nFlags, bool bOnlyMarked, ScDocument& rDestDoc,
2117  const ScMarkData* pMarks, bool bColRowFlags)
2118 {
2119  ScRange aNewRange = rRange;
2120  aNewRange.PutInOrder();
2121 
2122  if (rDestDoc.aDocName.isEmpty())
2123  rDestDoc.aDocName = aDocName;
2124 
2125  sc::AutoCalcSwitch aACSwitch(rDestDoc, false); // avoid multiple calculations
2126 
2127  sc::CopyToDocContext aCxt(rDestDoc);
2128  aCxt.setStartListening(false);
2129 
2130  SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), rDestDoc.maTabs.size()));
2131  for (SCTAB i = aNewRange.aStart.Tab(); i <= aNewRange.aEnd.Tab() && i < nMinSizeBothTabs; i++)
2132  {
2133  ScTable* pTab = FetchTable(i);
2134  ScTable* pDestTab = rDestDoc.FetchTable(i);
2135  if (!pTab || !pDestTab)
2136  continue;
2137 
2138  pTab->CopyToTable(
2139  aCxt, aNewRange.aStart.Col(), aNewRange.aStart.Row(), aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
2140  nFlags, bOnlyMarked, pDestTab, pMarks, false, bColRowFlags,
2141  /*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true);
2142  }
2143 
2144  rDestDoc.StartAllListeners(aNewRange);
2145 }
2146 
2148  InsertDeleteFlags nFlags, bool bOnlyMarked, ScDocument& rDestDoc)
2149 {
2150  sc::AutoCalcSwitch aAutoCalcSwitch(*this, false);
2151 
2152  ScRange aNewRange = rRange;
2153  aNewRange.PutInOrder();
2154  SCTAB nTab1 = aNewRange.aStart.Tab();
2155  SCTAB nTab2 = aNewRange.aEnd.Tab();
2156 
2157  sc::CopyToDocContext aCxt(rDestDoc);
2158  if (nTab1 > 0)
2159  CopyToDocument(0, 0, 0, MaxCol(), MaxRow(), nTab1-1, InsertDeleteFlags::FORMULA, false, rDestDoc);
2160 
2161  SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), rDestDoc.maTabs.size()));
2162  for (SCTAB i = nTab1; i <= nTab2 && i < nMinSizeBothTabs; i++)
2163  {
2164  if (maTabs[i] && rDestDoc.maTabs[i])
2165  maTabs[i]->UndoToTable(aCxt, aNewRange.aStart.Col(), aNewRange.aStart.Row(),
2166  aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
2167  nFlags, bOnlyMarked, rDestDoc.maTabs[i].get());
2168  }
2169 
2170  if (nTab2 < static_cast<SCTAB>(maTabs.size()))
2171  CopyToDocument(0, 0 , nTab2+1, MaxCol(), MaxRow(), maTabs.size(), InsertDeleteFlags::FORMULA, false, rDestDoc);
2172 }
2173 
2174 void ScDocument::CopyToClip(const ScClipParam& rClipParam,
2175  ScDocument* pClipDoc, const ScMarkData* pMarks,
2176  bool bKeepScenarioFlags, bool bIncludeObjects )
2177 {
2178  OSL_ENSURE( pMarks, "CopyToClip: ScMarkData fails" );
2179 
2180  if (bIsClip)
2181  return;
2182 
2183  if (!pClipDoc)
2184  {
2185  SAL_WARN("sc", "CopyToClip: no ClipDoc");
2186  pClipDoc = ScModule::GetClipDoc();
2187  }
2188 
2189  if (mpShell->GetMedium())
2190  {
2192  // for unsaved files use the title name and adjust during save of file
2193  if (pClipDoc->maFileURL.isEmpty())
2194  pClipDoc->maFileURL = mpShell->GetName();
2195  }
2196  else
2197  {
2198  pClipDoc->maFileURL = mpShell->GetName();
2199  }
2200 
2201  //init maTabNames
2202  for (const auto& rxTab : maTabs)
2203  {
2204  if( rxTab )
2205  {
2206  OUString aTabName = rxTab->GetName();
2207  pClipDoc->maTabNames.push_back(aTabName);
2208  }
2209  else
2210  pClipDoc->maTabNames.emplace_back();
2211  }
2212 
2213  pClipDoc->aDocName = aDocName;
2214  pClipDoc->SetClipParam(rClipParam);
2215  ScRange aClipRange = rClipParam.getWholeRange();
2216  SCTAB nEndTab = static_cast<SCTAB>(maTabs.size());
2217 
2218  pClipDoc->ResetClip(this, pMarks);
2219 
2220  sc::CopyToClipContext aCxt(*pClipDoc, bKeepScenarioFlags);
2221  CopyRangeNamesToClip(pClipDoc, aClipRange, pMarks);
2222 
2223  for (SCTAB i = 0; i < nEndTab; ++i)
2224  {
2225  if (!maTabs[i] || i >= static_cast<SCTAB>(pClipDoc->maTabs.size()) || !pClipDoc->maTabs[i])
2226  continue;
2227 
2228  if ( pMarks && !pMarks->GetTableSelect(i) )
2229  continue;
2230 
2231  maTabs[i]->CopyToClip(aCxt, rClipParam.maRanges, pClipDoc->maTabs[i].get());
2232 
2233  if (mpDrawLayer && bIncludeObjects)
2234  {
2235  // also copy drawing objects
2236  tools::Rectangle aObjRect = GetMMRect(
2237  aClipRange.aStart.Col(), aClipRange.aStart.Row(), aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i);
2238  mpDrawLayer->CopyToClip(pClipDoc, i, aObjRect);
2239  }
2240  }
2241 
2242  // Make sure to mark overlapped cells.
2243  pClipDoc->ExtendMerge(aClipRange, true);
2244 }
2245 
2246 void ScDocument::CopyStaticToDocument(const ScRange& rSrcRange, SCTAB nDestTab, ScDocument* pDestDoc)
2247 {
2248  if (!pDestDoc)
2249  return;
2250 
2251  ScTable* pSrcTab = rSrcRange.aStart.Tab() < static_cast<SCTAB>(maTabs.size()) ? maTabs[rSrcRange.aStart.Tab()].get() : nullptr;
2252  ScTable* pDestTab = nDestTab < static_cast<SCTAB>(pDestDoc->maTabs.size()) ? pDestDoc->maTabs[nDestTab].get() : nullptr;
2253 
2254  if (!pSrcTab || !pDestTab)
2255  return;
2256 
2257  pDestDoc->GetFormatTable()->MergeFormatter(*GetFormatTable());
2259 
2260  pSrcTab->CopyStaticToDocument(
2261  rSrcRange.aStart.Col(), rSrcRange.aStart.Row(), rSrcRange.aEnd.Col(), rSrcRange.aEnd.Row(),
2262  aMap, pDestTab);
2263 }
2264 
2265 void ScDocument::CopyCellToDocument( const ScAddress& rSrcPos, const ScAddress& rDestPos, ScDocument& rDestDoc )
2266 {
2267  if (!TableExists(rSrcPos.Tab()) || !rDestDoc.TableExists(rDestPos.Tab()))
2268  return;
2269 
2270  ScTable& rSrcTab = *maTabs[rSrcPos.Tab()];
2271  ScTable& rDestTab = *rDestDoc.maTabs[rDestPos.Tab()];
2272 
2273  rSrcTab.CopyCellToDocument(rSrcPos.Col(), rSrcPos.Row(), rDestPos.Col(), rDestPos.Row(), rDestTab);
2274 }
2275 
2277  SCCOL nCol2, SCROW nRow2,
2278  SCTAB nTab, ScDocument* pClipDoc)
2279 {
2280  if (bIsClip)
2281  return;
2282 
2283  if (!pClipDoc)
2284  {
2285  SAL_WARN("sc", "CopyTabToClip: no ClipDoc");
2286  pClipDoc = ScModule::GetClipDoc();
2287  }
2288 
2289  if (mpShell->GetMedium())
2290  {
2292  // for unsaved files use the title name and adjust during save of file
2293  if (pClipDoc->maFileURL.isEmpty())
2294  pClipDoc->maFileURL = mpShell->GetName();
2295  }
2296  else
2297  {
2298  pClipDoc->maFileURL = mpShell->GetName();
2299  }
2300 
2301  //init maTabNames
2302  for (const auto& rxTab : maTabs)
2303  {
2304  if( rxTab )
2305  {
2306  OUString aTabName = rxTab->GetName();
2307  pClipDoc->maTabNames.push_back(aTabName);
2308  }
2309  else
2310  pClipDoc->maTabNames.emplace_back();
2311  }
2312 
2313  PutInOrder( nCol1, nCol2 );
2314  PutInOrder( nRow1, nRow2 );
2315 
2316  ScClipParam& rClipParam = pClipDoc->GetClipParam();
2317  pClipDoc->aDocName = aDocName;
2318  rClipParam.maRanges.RemoveAll();
2319  rClipParam.maRanges.push_back(ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0));
2320  pClipDoc->ResetClip( this, nTab );
2321 
2322  sc::CopyToClipContext aCxt(*pClipDoc, false);
2323  if (nTab < static_cast<SCTAB>(maTabs.size()) && nTab < static_cast<SCTAB>(pClipDoc->maTabs.size()))
2324  if (maTabs[nTab] && pClipDoc->maTabs[nTab])
2325  maTabs[nTab]->CopyToClip(aCxt, nCol1, nRow1, nCol2, nRow2, pClipDoc->maTabs[nTab].get());
2326 
2327  pClipDoc->GetClipParam().mbCutMode = false;
2328 }
2329 
2330 void ScDocument::TransposeClip( ScDocument* pTransClip, InsertDeleteFlags nFlags, bool bAsLink )
2331 {
2332  OSL_ENSURE( bIsClip && pTransClip && pTransClip->bIsClip,
2333  "TransposeClip with wrong Document" );
2334 
2335  // initialize
2336  // -> pTransClip has to be deleted before the original document!
2337 
2338  pTransClip->ResetClip(this, nullptr); // all
2339 
2340  // Take over range
2341 
2342  if (pRangeName)
2343  {
2344  pTransClip->GetRangeName()->clear();
2345  for (const auto& rEntry : *pRangeName)
2346  {
2347  sal_uInt16 nIndex = rEntry.second->GetIndex();
2348  ScRangeData* pData = new ScRangeData(*rEntry.second);
2349  if (pTransClip->pRangeName->insert(pData))
2350  pData->SetIndex(nIndex);
2351  }
2352  }
2353 
2354  // The data
2355 
2356  ScRange aClipRange = GetClipParam().getWholeRange();
2357  if ( ValidRow(aClipRange.aEnd.Row()-aClipRange.aStart.Row()) )
2358  {
2359  for (SCTAB i=0; i< static_cast<SCTAB>(maTabs.size()); i++)
2360  if (maTabs[i])
2361  {
2362  OSL_ENSURE( pTransClip->maTabs[i], "TransposeClip: Table not there" );
2363  maTabs[i]->TransposeClip( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
2364  aClipRange.aEnd.Col(), aClipRange.aEnd.Row(),
2365  pTransClip->maTabs[i].get(), nFlags, bAsLink );
2366 
2367  if ( mpDrawLayer && ( nFlags & InsertDeleteFlags::OBJECTS ) )
2368  {
2369  // Drawing objects are copied to the new area without transposing.
2370  // CopyFromClip is used to adjust the objects to the transposed block's
2371  // cell range area.
2372  // (mpDrawLayer in the original clipboard document is set only if there
2373  // are drawing objects to copy)
2374 
2375  pTransClip->InitDrawLayer();
2376  tools::Rectangle aSourceRect = GetMMRect( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
2377  aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i );
2378  tools::Rectangle aDestRect = pTransClip->GetMMRect( 0, 0,
2379  static_cast<SCCOL>(aClipRange.aEnd.Row() - aClipRange.aStart.Row()),
2380  static_cast<SCROW>(aClipRange.aEnd.Col() - aClipRange.aStart.Col()), i );
2381  pTransClip->mpDrawLayer->CopyFromClip( mpDrawLayer.get(), i, aSourceRect, ScAddress(0,0,i), aDestRect );
2382  }
2383  }
2384 
2385  pTransClip->SetClipParam(GetClipParam());
2386  pTransClip->GetClipParam().transpose();
2387  }
2388  else
2389  {
2390  SAL_WARN("sc", "TransposeClip: Too big");
2391  }
2392 
2393  // This happens only when inserting...
2394 
2395  GetClipParam().mbCutMode = false;
2396 }
2397 
2398 namespace {
2399 
2400 void copyUsedNamesToClip(ScRangeName* pClipRangeName, ScRangeName* pRangeName,
2401  const sc::UpdatedRangeNames::NameIndicesType& rUsedNames)
2402 {
2403  pClipRangeName->clear();
2404  for (const auto& rEntry : *pRangeName) //TODO: also DB and Pivot regions!!!
2405  {
2406  sal_uInt16 nIndex = rEntry.second->GetIndex();
2407  bool bInUse = (rUsedNames.count(nIndex) > 0);
2408  if (!bInUse)
2409  continue;
2410 
2411  ScRangeData* pData = new ScRangeData(*rEntry.second);
2412  if (pClipRangeName->insert(pData))
2413  pData->SetIndex(nIndex);
2414  }
2415 }
2416 
2417 }
2418 
2419 void ScDocument::CopyRangeNamesToClip(ScDocument* pClipDoc, const ScRange& rClipRange, const ScMarkData* pMarks)
2420 {
2421  if (!pRangeName || pRangeName->empty())
2422  return;
2423 
2424  sc::UpdatedRangeNames aUsedNames; // indexes of named ranges that are used in the copied cells
2425  SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), pClipDoc->maTabs.size()));
2426  for (SCTAB i = 0; i < nMinSizeBothTabs; ++i)
2427  if (maTabs[i] && pClipDoc->maTabs[i])
2428  if ( !pMarks || pMarks->GetTableSelect(i) )
2429  maTabs[i]->FindRangeNamesInUse(
2430  rClipRange.aStart.Col(), rClipRange.aStart.Row(),
2431  rClipRange.aEnd.Col(), rClipRange.aEnd.Row(), aUsedNames);
2432 
2433  /* TODO: handle also sheet-local names */
2434  sc::UpdatedRangeNames::NameIndicesType aUsedGlobalNames( aUsedNames.getUpdatedNames(-1));
2435  copyUsedNamesToClip(pClipDoc->GetRangeName(), pRangeName.get(), aUsedGlobalNames);
2436 }
2437 
2439  mpDoc(pDoc)
2440 {
2441  mpDoc->MergeNumberFormatter(pSrcDoc);
2442 }
2443 
2445 {
2447  mpDoc->pFormatExchangeList = nullptr;
2448 }
2449 
2451 {
2453  mpFormulaGroupCxt.reset();
2454 }
2455 
2457 {
2458  ScTable* pTab = FetchTable(rPos.Tab());
2459  if (!pTab)
2460  return nullptr;
2461 
2462  return pTab->GetBroadcaster(rPos.Col(), rPos.Row());
2463 }
2464 
2466 {
2467  const ScTable* pTab = FetchTable(rPos.Tab());
2468  if (!pTab)
2469  return nullptr;
2470 
2471  return pTab->GetBroadcaster(rPos.Col(), rPos.Row());
2472 }
2473 
2474 void ScDocument::DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, const ScAddress& rTopPos, SCROW nLength )
2475 {
2476  ScTable* pTab = FetchTable(rTopPos.Tab());
2477  if (!pTab || nLength <= 0)
2478  return;
2479 
2480  pTab->DeleteBroadcasters(rBlockPos, rTopPos.Col(), rTopPos.Row(), rTopPos.Row()+nLength-1);
2481 }
2482 
2483 #if DUMP_COLUMN_STORAGE
2484 void ScDocument::DumpColumnStorage( SCTAB nTab, SCCOL nCol ) const
2485 {
2486  const ScTable* pTab = FetchTable(nTab);
2487  if (!pTab)
2488  return;
2489 
2490  pTab->DumpColumnStorage(nCol);
2491 }
2492 #endif
2493 
2494 #if DEBUG_AREA_BROADCASTER
2495 void ScDocument::DumpAreaBroadcasters() const
2496 {
2497  if (pBASM)
2498  pBASM->Dump();
2499 }
2500 #endif
2501 
2502 bool ScDocument::TableExists( SCTAB nTab ) const
2503 {
2504  return ValidTab(nTab) && o3tl::make_unsigned(nTab) < maTabs.size() && maTabs[nTab];
2505 }
2506 
2508 {
2509  if (!TableExists(nTab))
2510  return nullptr;
2511 
2512  return maTabs[nTab].get();
2513 }
2514 
2516 {
2517  if (!TableExists(nTab))
2518  return nullptr;
2519 
2520  return maTabs[nTab].get();
2521 }
2522 
2524 {
2525  if (!TableExists(nTab))
2526  {
2527  std::vector<std::unique_ptr<ScColumn, o3tl::default_delete<ScColumn>>> aEmptyVector;
2528  return ScColumnsRange(ScColumnsRange::Iterator(aEmptyVector.begin()),
2529  ScColumnsRange::Iterator(aEmptyVector.end()));
2530  }
2531 
2532  return maTabs[nTab]->GetColumnsRange(nColBegin, nColEnd);
2533 }
2534 
2536 {
2537  SvNumberFormatter* pThisFormatter = mxPoolHelper->GetFormTable();
2538  SvNumberFormatter* pOtherFormatter = pSrcDoc->mxPoolHelper->GetFormTable();
2539  if (pOtherFormatter && pOtherFormatter != pThisFormatter)
2540  {
2541  SvNumberFormatterIndexTable* pExchangeList =
2542  pThisFormatter->MergeFormatter(*pOtherFormatter);
2543  if (!pExchangeList->empty())
2544  {
2546  pFormatExchangeList = pExchangeList;
2547  }
2548  }
2549 }
2550 
2552 {
2553  if (!mpClipParam)
2554  mpClipParam.reset(new ScClipParam);
2555 
2556  return *mpClipParam;
2557 }
2558 
2560 {
2561  mpClipParam.reset(new ScClipParam(rParam));
2562 }
2563 
2565 {
2566  if (bIsClip || mpShell == nullptr || mpShell->IsLoading())
2567  return false;
2568 
2569  ScDocument* pClipDoc = ScModule::GetClipDoc();
2570  return pClipDoc && pClipDoc->bIsClip && pClipDoc->mxPoolHelper.is() && mxPoolHelper.is() &&
2571  mxPoolHelper->GetDocPool() == pClipDoc->mxPoolHelper->GetDocPool();
2572 }
2573 
2575  SCCOL nCol2, SCROW nRow2,
2576  const ScMarkData& rMark, InsertDeleteFlags nInsFlag )
2577 {
2578  if (!(nInsFlag & InsertDeleteFlags::CONTENTS))
2579  return;
2580 
2581  auto pSet = std::make_shared<sc::ColumnBlockPositionSet>(*this);
2582 
2583  sc::StartListeningContext aStartCxt(*this, pSet);
2584  sc::EndListeningContext aEndCxt(*this, pSet, nullptr);
2585 
2586  SCTAB nMax = static_cast<SCTAB>(maTabs.size());
2587  for (const auto& rTab : rMark)
2588  {
2589  if (rTab >= nMax)
2590  break;
2591  if (maTabs[rTab])
2592  maTabs[rTab]->StartListeningFormulaCells(aStartCxt, aEndCxt, nCol1, nRow1, nCol2, nRow2);
2593  }
2594 }
2595 
2597  SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const ScMarkData& rMark,
2598  InsertDeleteFlags nInsFlag, sc::ColumnSpanSet& rBroadcastSpans )
2599 {
2600  if (nInsFlag & InsertDeleteFlags::CONTENTS)
2601  {
2602  SCTAB nMax = static_cast<SCTAB>(maTabs.size());
2603  for (const auto& rTab : rMark)
2604  {
2605  if (rTab >= nMax)
2606  break;
2607  if (maTabs[rTab])
2608  maTabs[rTab]->SetDirtyFromClip(nCol1, nRow1, nCol2, nRow2, rBroadcastSpans);
2609  }
2610  }
2611 }
2612 
2614 {
2615  if (!TableExists(nTab))
2616  return false;
2617 
2618  return maTabs[nTab]->InitColumnBlockPosition(rBlockPos, nCol);
2619 }
2620 
2622  sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
2623  const ScMarkData& rMark, SCCOL nDx, SCROW nDy )
2624 {
2625  TableContainer& rClipTabs = rCxt.getClipDoc()->maTabs;
2626  SCTAB nTabEnd = rCxt.getTabEnd();
2627  SCTAB nClipTab = 0;
2628  for (SCTAB i = rCxt.getTabStart(); i <= nTabEnd && i < static_cast<SCTAB>(maTabs.size()); i++)
2629  {
2630  if (maTabs[i] && rMark.GetTableSelect(i) )
2631  {
2632  while (!rClipTabs[nClipTab]) nClipTab = (nClipTab+1) % static_cast<SCTAB>(rClipTabs.size());
2633 
2634  maTabs[i]->CopyFromClip(
2635  rCxt, nCol1, nRow1, nCol2, nRow2, nDx, nDy, rClipTabs[nClipTab].get());
2636 
2638  {
2639  // also copy drawing objects
2640 
2641  // drawing layer must be created before calling CopyFromClip
2642  // (ScDocShell::MakeDrawLayer also does InitItems etc.)
2643  OSL_ENSURE( mpDrawLayer, "CopyBlockFromClip: No drawing layer" );
2644  if ( mpDrawLayer )
2645  {
2646  // For GetMMRect, the row heights in the target document must already be valid
2647  // (copied in an extra step before pasting, or updated after pasting cells, but
2648  // before pasting objects).
2649 
2650  tools::Rectangle aSourceRect = rCxt.getClipDoc()->GetMMRect(
2651  nCol1-nDx, nRow1-nDy, nCol2-nDx, nRow2-nDy, nClipTab );
2652  tools::Rectangle aDestRect = GetMMRect( nCol1, nRow1, nCol2, nRow2, i );
2653  mpDrawLayer->CopyFromClip(rCxt.getClipDoc()->mpDrawLayer.get(), nClipTab, aSourceRect,
2654  ScAddress( nCol1, nRow1, i ), aDestRect );
2655  }
2656  }
2657 
2658  nClipTab = (nClipTab+1) % static_cast<SCTAB>(rClipTabs.size());
2659  }
2660  }
2662  return;
2663 
2664  nClipTab = 0;
2665  for (SCTAB i = rCxt.getTabStart(); i <= nTabEnd && i < static_cast<SCTAB>(maTabs.size()); i++)
2666  {
2667  if (maTabs[i] && rMark.GetTableSelect(i) )
2668  {
2669  while (!rClipTabs[nClipTab]) nClipTab = (nClipTab+1) % static_cast<SCTAB>(rClipTabs.size());
2670  SCTAB nDz = i - nClipTab;
2671 
2672  // ranges of consecutive selected tables (in clipboard and dest. doc)
2673  // must be handled in one UpdateReference call
2674  SCTAB nFollow = 0;
2675  while ( i + nFollow < nTabEnd
2676  && rMark.GetTableSelect( i + nFollow + 1 )
2677  && nClipTab + nFollow < MAXTAB
2678  && rClipTabs[(nClipTab + nFollow + 1) % static_cast<SCTAB>(rClipTabs.size())] )
2679  ++nFollow;
2680 
2681  sc::RefUpdateContext aRefCxt(*this);
2682  aRefCxt.maRange = ScRange(nCol1, nRow1, i, nCol2, nRow2, i+nFollow);
2683  aRefCxt.mnColDelta = nDx;
2684  aRefCxt.mnRowDelta = nDy;
2685  aRefCxt.mnTabDelta = nDz;
2686  aRefCxt.setBlockPositionReference(rCxt.getBlockPositionSet()); // share mdds position caching
2687  if (rCxt.getClipDoc()->GetClipParam().mbCutMode)
2688  {
2689  // Update references only if cut originates from the same
2690  // document we are pasting into.
2691  if (rCxt.getClipDoc()->GetPool() == GetPool())
2692  {
2693  bool bOldInserting = IsInsertingFromOtherDoc();
2694  SetInsertingFromOtherDoc( true);
2695  aRefCxt.meMode = URM_MOVE;
2696  UpdateReference(aRefCxt, rCxt.getUndoDoc(), false);
2697 
2698  // For URM_MOVE group listeners may have been removed,
2699  // re-establish them.
2700  if (!aRefCxt.maRegroupCols.empty())
2701  {
2702  /* TODO: holding the ColumnSet in a shared_ptr at
2703  * RefUpdateContext would eliminate the need of
2704  * copying it here. */
2705  auto pColSet = std::make_shared<sc::ColumnSet>( aRefCxt.maRegroupCols);
2706  StartNeededListeners( pColSet);
2707  }
2708 
2709  SetInsertingFromOtherDoc( bOldInserting);
2710  }
2711  }
2712  else
2713  {
2714  aRefCxt.meMode = URM_COPY;
2715  UpdateReference(aRefCxt, rCxt.getUndoDoc(), false);
2716  }
2717 
2718  nClipTab = (nClipTab+nFollow+1) % static_cast<SCTAB>(rClipTabs.size());
2719  i = sal::static_int_cast<SCTAB>( i + nFollow );
2720  }
2721  }
2722 }
2723 
2725  sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
2726  const ScMarkData& rMark, SCCOL nDx, SCROW & rClipStartRow )
2727 {
2728  // call CopyBlockFromClip for ranges of consecutive non-filtered rows
2729  // nCol1/nRow1 etc. is in target doc
2730 
2731  // filtered state is taken from first used table in clipboard (as in GetClipArea)
2732  SCTAB nFlagTab = 0;
2733  TableContainer& rClipTabs = rCxt.getClipDoc()->maTabs;
2734  while ( nFlagTab < static_cast<SCTAB>(rClipTabs.size()) && !rClipTabs[nFlagTab] )
2735  ++nFlagTab;
2736 
2737  SCROW nSourceRow = rClipStartRow;
2738  SCROW nSourceEnd = 0;
2739  if (!rCxt.getClipDoc()->GetClipParam().maRanges.empty())
2740  nSourceEnd = rCxt.getClipDoc()->GetClipParam().maRanges.front().aEnd.Row();
2741  SCROW nDestRow = nRow1;
2742 
2743  while ( nSourceRow <= nSourceEnd && nDestRow <= nRow2 )
2744  {
2745  // skip filtered rows
2746  nSourceRow = rCxt.getClipDoc()->FirstNonFilteredRow(nSourceRow, nSourceEnd, nFlagTab);
2747 
2748  if ( nSourceRow <= nSourceEnd )
2749  {
2750  // look for more non-filtered rows following
2751  SCROW nLastRow = nSourceRow;
2752  (void)rCxt.getClipDoc()->RowFiltered(nSourceRow, nFlagTab, nullptr, &nLastRow);
2753  SCROW nFollow = nLastRow - nSourceRow;
2754 
2755  if (nFollow > nSourceEnd - nSourceRow)
2756  nFollow = nSourceEnd - nSourceRow;
2757  if (nFollow > nRow2 - nDestRow)
2758  nFollow = nRow2 - nDestRow;
2759 
2760  SCROW nNewDy = nDestRow - nSourceRow;
2762  rCxt, nCol1, nDestRow, nCol2, nDestRow + nFollow, rMark, nDx, nNewDy);
2763 
2764  nSourceRow += nFollow + 1;
2765  nDestRow += nFollow + 1;
2766  }
2767  }
2768  rClipStartRow = nSourceRow;
2769 }
2770 
2771 namespace {
2772 
2773 class BroadcastAction : public sc::ColumnSpanSet::ColumnAction
2774 {
2775  ScDocument& mrDoc;
2776  ScColumn* mpCol;
2777 
2778 public:
2779  explicit BroadcastAction( ScDocument& rDoc ) : mrDoc(rDoc), mpCol(nullptr) {}
2780 
2781  virtual void startColumn( ScColumn* pCol ) override
2782  {
2783  mpCol = pCol;
2784  }
2785 
2786  virtual void execute( SCROW nRow1, SCROW nRow2, bool bVal ) override
2787  {
2788  if (!bVal)
2789  return;
2790 
2791  assert(mpCol);
2792  ScRange aRange(mpCol->GetCol(), nRow1, mpCol->GetTab());
2793  aRange.aEnd.SetRow(nRow2);
2794  mrDoc.BroadcastCells(aRange, SfxHintId::ScDataChanged);
2795  };
2796 };
2797 
2798 }
2799 
2800 void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMark,
2801  InsertDeleteFlags nInsFlag,
2802  ScDocument* pRefUndoDoc, ScDocument* pClipDoc, bool bResetCut,
2803  bool bAsLink, bool bIncludeFiltered, bool bSkipAttrForEmpty,
2804  const ScRangeList * pDestRanges )
2805 {
2806  if (bIsClip)
2807  return;
2808 
2809  if (!pClipDoc)
2810  {
2811  OSL_FAIL("CopyFromClip: no ClipDoc");
2812  pClipDoc = ScModule::GetClipDoc();
2813  }
2814 
2815  if (!pClipDoc->bIsClip || !pClipDoc->GetTableCount())
2816  return;
2817 
2818  sc::AutoCalcSwitch aACSwitch(*this, false); // temporarily turn off auto calc.
2819 
2820  NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
2821 
2822  SCCOL nAllCol1 = rDestRange.aStart.Col();
2823  SCROW nAllRow1 = rDestRange.aStart.Row();
2824  SCCOL nAllCol2 = rDestRange.aEnd.Col();
2825  SCROW nAllRow2 = rDestRange.aEnd.Row();
2826 
2827  SCCOL nXw = 0;
2828  SCROW nYw = 0;
2829  ScRange aClipRange = pClipDoc->GetClipParam().getWholeRange();
2830  for (SCTAB nTab = 0; nTab < static_cast<SCTAB>(pClipDoc->maTabs.size()); nTab++) // find largest merge overlap
2831  if (pClipDoc->maTabs[nTab]) // all sheets of the clipboard content
2832  {
2833  SCCOL nThisEndX = aClipRange.aEnd.Col();
2834  SCROW nThisEndY = aClipRange.aEnd.Row();
2835  pClipDoc->ExtendMerge( aClipRange.aStart.Col(),
2836  aClipRange.aStart.Row(),
2837  nThisEndX, nThisEndY, nTab );
2838  // only extra value from ExtendMerge
2839  nThisEndX = sal::static_int_cast<SCCOL>( nThisEndX - aClipRange.aEnd.Col() );
2840  nThisEndY = sal::static_int_cast<SCROW>( nThisEndY - aClipRange.aEnd.Row() );
2841  if ( nThisEndX > nXw )
2842  nXw = nThisEndX;
2843  if ( nThisEndY > nYw )
2844  nYw = nThisEndY;
2845  }
2846 
2847  SCCOL nDestAddX;
2848  SCROW nDestAddY;
2849  pClipDoc->GetClipArea( nDestAddX, nDestAddY, bIncludeFiltered );
2850  nXw = sal::static_int_cast<SCCOL>( nXw + nDestAddX );
2851  nYw = sal::static_int_cast<SCROW>( nYw + nDestAddY ); // ClipArea, plus ExtendMerge value
2852 
2853  /* Decide which contents to delete before copying. Delete all
2854  contents if nInsFlag contains any real content flag.
2855  #i102056# Notes are pasted from clipboard in a second pass,
2856  together with the special flag InsertDeleteFlags::ADDNOTES that states to not
2857  overwrite/delete existing cells but to insert the notes into
2858  these cells. In this case, just delete old notes from the
2859  destination area. */
2862  nDelFlag |= InsertDeleteFlags::NOTE;
2863  else if ( nInsFlag & InsertDeleteFlags::CONTENTS )
2864  nDelFlag |= InsertDeleteFlags::CONTENTS;
2865 
2866  if (nInsFlag & InsertDeleteFlags::ATTRIB)
2867  nDelFlag |= InsertDeleteFlags::ATTRIB;
2868 
2869  sc::CopyFromClipContext aCxt(*this, pRefUndoDoc, pClipDoc, nInsFlag, bAsLink, bSkipAttrForEmpty);
2870  std::pair<SCTAB,SCTAB> aTabRanges = getMarkedTableRange(maTabs, rMark);
2871  aCxt.setTabRange(aTabRanges.first, aTabRanges.second);
2872  aCxt.setDeleteFlag(nDelFlag);
2873 
2874  ScRangeList aLocalRangeList;
2875  if (!pDestRanges)
2876  {
2877  aLocalRangeList.push_back( rDestRange);
2878  pDestRanges = &aLocalRangeList;
2879  }
2880 
2881  bInsertingFromOtherDoc = true; // No Broadcast/Listener created at Insert
2882 
2883  sc::ColumnSpanSet aBroadcastSpans;
2884 
2885  SCCOL nClipStartCol = aClipRange.aStart.Col();
2886  SCROW nClipStartRow = aClipRange.aStart.Row();
2887  SCROW nClipEndRow = aClipRange.aEnd.Row();
2888  for ( size_t nRange = 0; nRange < pDestRanges->size(); ++nRange )
2889  {
2890  const ScRange & rRange = (*pDestRanges)[nRange];
2891  SCCOL nCol1 = rRange.aStart.Col();
2892  SCROW nRow1 = rRange.aStart.Row();
2893  SCCOL nCol2 = rRange.aEnd.Col();
2894  SCROW nRow2 = rRange.aEnd.Row();
2895 
2896  if (bSkipAttrForEmpty)
2897  {
2898  // Delete cells in the destination only if their corresponding clip cells are not empty.
2899  aCxt.setDestRange(nCol1, nRow1, nCol2, nRow2);
2900  DeleteBeforeCopyFromClip(aCxt, rMark, aBroadcastSpans);
2901  }
2902  else
2903  DeleteArea(nCol1, nRow1, nCol2, nRow2, rMark, nDelFlag, false, &aBroadcastSpans);
2904 
2905  if (CopyOneCellFromClip(aCxt, nCol1, nRow1, nCol2, nRow2))
2906  continue;
2907 
2908  SCCOL nC1 = nCol1;
2909  SCROW nR1 = nRow1;
2910  SCCOL nC2 = nC1 + nXw;
2911  if (nC2 > nCol2)
2912  nC2 = nCol2;
2913  SCROW nR2 = nR1 + nYw;
2914  if (nR2 > nRow2)
2915  nR2 = nRow2;
2916 
2917  const SCCOLROW nThreshold = 8192;
2918  bool bPreallocatePattern = ((nInsFlag & InsertDeleteFlags::ATTRIB) && (nRow2 - nRow1 > nThreshold));
2919  std::vector< SCTAB > vTables;
2920 
2921  if (bPreallocatePattern)
2922  {
2923  for (SCTAB i = aCxt.getTabStart(); i <= aCxt.getTabEnd(); ++i)
2924  if (maTabs[i] && rMark.GetTableSelect( i ) )
2925  vTables.push_back( i );
2926  }
2927 
2928  do
2929  {
2930  // Pasting is done column-wise, when pasting to a filtered
2931  // area this results in partitioning and we have to
2932  // remember and reset the start row for each column until
2933  // it can be advanced for the next chunk of unfiltered
2934  // rows.
2935  SCROW nSaveClipStartRow = nClipStartRow;
2936  do
2937  {
2938  nClipStartRow = nSaveClipStartRow;
2939  SCCOL nDx = nC1 - nClipStartCol;
2940  SCROW nDy = nR1 - nClipStartRow;
2941  if ( bIncludeFiltered )
2942  {
2944  aCxt, nC1, nR1, nC2, nR2, rMark, nDx, nDy);
2945  nClipStartRow += nR2 - nR1 + 1;
2946  }
2947  else
2948  {
2950  aCxt, nC1, nR1, nC2, nR2, rMark, nDx, nClipStartRow);
2951  }
2952  nC1 = nC2 + 1;
2953  nC2 = std::min(static_cast<SCCOL>(nC1 + nXw), nCol2);
2954  } while (nC1 <= nCol2);
2955  if (nClipStartRow > nClipEndRow)
2956  nClipStartRow = aClipRange.aStart.Row();
2957  nC1 = nCol1;
2958  nC2 = nC1 + nXw;
2959  if (nC2 > nCol2)
2960  nC2 = nCol2;
2961 
2962  // Preallocate pattern memory once if further chunks are to be pasted.
2963  if (bPreallocatePattern && (nR2+1) <= nRow2)
2964  {
2965  SCROW nR3 = nR2 + 1;
2966  for (SCTAB nTab : vTables)
2967  {
2968  for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
2969  {
2970  // Pattern count of the first chunk pasted.
2971  SCSIZE nChunk = GetPatternCount( nTab, nCol, nR1, nR2);
2972  // If it is only one pattern per chunk and chunks are
2973  // pasted consecutively then it will get its range
2974  // enlarged for each chunk and no further allocation
2975  // happens. For non-consecutive chunks we're out of
2976  // luck in this case.
2977  if (nChunk > 1)
2978  {
2979  SCSIZE nNeeded = nChunk * (nRow2 - nR3 + 1) / (nYw + 1);
2980  SCSIZE nRemain = GetPatternCount( nTab, nCol, nR3, nRow2);
2981  if (nNeeded > nRemain)
2982  {
2983  SCSIZE nCurr = GetPatternCount( nTab, nCol);
2984  ReservePatternCount( nTab, nCol, nCurr + nNeeded);
2985  }
2986  }
2987  }
2988  }
2989  bPreallocatePattern = false;
2990  }
2991 
2992  nR1 = nR2 + 1;
2993  nR2 = std::min(static_cast<SCROW>(nR1 + nYw), nRow2);
2994  } while (nR1 <= nRow2);
2995  }
2996 
2997  bInsertingFromOtherDoc = false;
2998 
2999  // Create Listener after everything has been inserted
3000  StartListeningFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
3001 
3002  {
3003  ScBulkBroadcast aBulkBroadcast( GetBASM(), SfxHintId::ScDataChanged);
3004 
3005  // Set all formula cells dirty, and collect non-empty non-formula cell
3006  // positions so that we can broadcast on them below.
3007  SetDirtyFromClip(nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag, aBroadcastSpans);
3008 
3009  BroadcastAction aAction(*this);
3010  aBroadcastSpans.executeColumnAction(*this, aAction);
3011  }
3012 
3013  if (bResetCut)
3014  pClipDoc->GetClipParam().mbCutMode = false;
3015 }
3016 
3018  const ScAddress& rDestPos, const ScMarkData& rMark, InsertDeleteFlags nInsFlag, ScDocument* pClipDoc,
3019  bool bResetCut, bool bAsLink, bool /*bIncludeFiltered*/, bool bSkipAttrForEmpty)
3020 {
3021  if (bIsClip)
3022  return;
3023 
3024  if (!pClipDoc->bIsClip || !pClipDoc->GetTableCount())
3025  // There is nothing in the clip doc to copy.
3026  return;
3027 
3028  // Right now, we don't allow pasting into filtered rows, so we don't even handle it here.
3029 
3030  sc::AutoCalcSwitch aACSwitch(*this, false); // turn of auto calc temporarily.
3031  NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
3032 
3033  ScRange aDestRange;
3034  rMark.GetMarkArea(aDestRange);
3035 
3036  bInsertingFromOtherDoc = true; // No Broadcast/Listener created at Insert
3037 
3038  SCCOL nCol1 = rDestPos.Col();
3039  SCROW nRow1 = rDestPos.Row();
3040  ScClipParam& rClipParam = pClipDoc->GetClipParam();
3041 
3042  sc::ColumnSpanSet aBroadcastSpans;
3043 
3044  if (!bSkipAttrForEmpty)
3045  {
3046  // Do the deletion first.
3047  SCCOL nColSize = rClipParam.getPasteColSize();
3048  SCROW nRowSize = rClipParam.getPasteRowSize();
3049 
3050  DeleteArea(nCol1, nRow1, nCol1+nColSize-1, nRow1+nRowSize-1, rMark, InsertDeleteFlags::CONTENTS, false, &aBroadcastSpans);
3051  }
3052 
3053  sc::CopyFromClipContext aCxt(*this, nullptr, pClipDoc, nInsFlag, bAsLink, bSkipAttrForEmpty);
3054  std::pair<SCTAB,SCTAB> aTabRanges = getMarkedTableRange(maTabs, rMark);
3055  aCxt.setTabRange(aTabRanges.first, aTabRanges.second);
3056 
3057  for (size_t i = 0, n = rClipParam.maRanges.size(); i < n; ++i)
3058  {
3059  const ScRange & rRange = rClipParam.maRanges[i];
3060 
3061  SCROW nRowCount = rRange.aEnd.Row() - rRange.aStart.Row() + 1;
3062  SCCOL nDx = static_cast<SCCOL>(nCol1 - rRange.aStart.Col());
3063  SCROW nDy = static_cast<SCROW>(nRow1 - rRange.aStart.Row());
3064  SCCOL nCol2 = nCol1 + rRange.aEnd.Col() - rRange.aStart.Col();
3065  SCROW nEndRow = nRow1 + nRowCount - 1;
3066 
3067  CopyBlockFromClip(aCxt, nCol1, nRow1, nCol2, nEndRow, rMark, nDx, nDy);
3068 
3069  switch (rClipParam.meDirection)
3070  {
3071  case ScClipParam::Row:
3072  // Begin row for the next range being pasted.
3073  nRow1 += nRowCount;
3074  break;
3075  case ScClipParam::Column:
3076  nCol1 += rRange.aEnd.Col() - rRange.aStart.Col() + 1;
3077  break;
3078  default:
3079  ;
3080  }
3081  }
3082 
3083  bInsertingFromOtherDoc = false;
3084 
3085  // Create Listener after everything has been inserted
3086  StartListeningFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
3087  aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
3088 
3089  {
3090  ScBulkBroadcast aBulkBroadcast( GetBASM(), SfxHintId::ScDataChanged);
3091 
3092  // Set formula cells dirty and collect non-formula cells.
3094  aDestRange.aStart.Col(), aDestRange.aStart.Row(), aDestRange.aEnd.Col(), aDestRange.aEnd.Row(),
3095  rMark, nInsFlag, aBroadcastSpans);
3096 
3097  BroadcastAction aAction(*this);
3098  aBroadcastSpans.executeColumnAction(*this, aAction);
3099  }
3100 
3101  if (bResetCut)
3102  pClipDoc->GetClipParam().mbCutMode = false;
3103 }
3104 
3105 void ScDocument::SetClipArea( const ScRange& rArea, bool bCut )
3106 {
3107  if (bIsClip)
3108  {
3109  ScClipParam& rClipParam = GetClipParam();
3110  rClipParam.maRanges.RemoveAll();
3111  rClipParam.maRanges.push_back(rArea);
3112  rClipParam.mbCutMode = bCut;
3113  }
3114  else
3115  {
3116  OSL_FAIL("SetClipArea: No Clip");
3117  }
3118 }
3119 
3120 void ScDocument::GetClipArea(SCCOL& nClipX, SCROW& nClipY, bool bIncludeFiltered)
3121 {
3122  if (!bIsClip)
3123  {
3124  OSL_FAIL("GetClipArea: No Clip");
3125  return;
3126  }
3127 
3128  ScRangeList& rClipRanges = GetClipParam().maRanges;
3129  if (rClipRanges.empty())
3130  // No clip range. Bail out.
3131  return;
3132 
3133  ScRange const & rRange = rClipRanges.front();
3134  SCCOL nStartCol = rRange.aStart.Col();
3135  SCCOL nEndCol = rRange.aEnd.Col();
3136  SCROW nStartRow = rRange.aStart.Row();
3137  SCROW nEndRow = rRange.aEnd.Row();
3138  for ( size_t i = 1, n = rClipRanges.size(); i < n; ++i )
3139  {
3140  ScRange const & rRange2 = rClipRanges[ i ];
3141  if (rRange2.aStart.Col() < nStartCol)
3142  nStartCol = rRange2.aStart.Col();
3143  if (rRange2.aStart.Row() < nStartRow)
3144  nStartRow = rRange2.aStart.Row();
3145  if (rRange2.aEnd.Col() > nEndCol)
3146  nEndCol = rRange2.aEnd.Col();
3147  if (rRange2.aEnd.Row() < nEndRow)
3148  nEndRow = rRange2.aEnd.Row();
3149  }
3150 
3151  nClipX = nEndCol - nStartCol;
3152 
3153  if ( bIncludeFiltered )
3154  nClipY = nEndRow - nStartRow;
3155  else
3156  {
3157  // count non-filtered rows
3158  // count on first used table in clipboard
3159  SCTAB nCountTab = 0;
3160  while ( nCountTab < static_cast<SCTAB>(maTabs.size()) && !maTabs[nCountTab] )
3161  ++nCountTab;
3162 
3163  SCROW nResult = CountNonFilteredRows(nStartRow, nEndRow, nCountTab);
3164 
3165  if ( nResult > 0 )
3166  nClipY = nResult - 1;
3167  else
3168  nClipY = 0; // always return at least 1 row
3169  }
3170 }
3171 
3172 void ScDocument::GetClipStart(SCCOL& nClipX, SCROW& nClipY)
3173 {
3174  if (bIsClip)
3175  {
3176  ScRangeList& rClipRanges = GetClipParam().maRanges;
3177  if ( !rClipRanges.empty() )
3178  {
3179  nClipX = rClipRanges.front().aStart.Col();
3180  nClipY = rClipRanges.front().aStart.Row();
3181  }
3182  }
3183  else
3184  {
3185  OSL_FAIL("GetClipStart: No Clip");
3186  }
3187 }
3188 
3190 {
3191  // count on first used table in clipboard
3192  SCTAB nCountTab = 0;
3193  while ( nCountTab < static_cast<SCTAB>(maTabs.size()) && !maTabs[nCountTab] )
3194  ++nCountTab;
3195 
3196  ScRangeList& rClipRanges = GetClipParam().maRanges;
3197  if ( rClipRanges.empty() )
3198  return false;
3199 
3200  for ( size_t i = 0, n = rClipRanges.size(); i < n; ++i )
3201  {
3202  ScRange & rRange = rClipRanges[ i ];
3203  bool bAnswer = maTabs[nCountTab]->HasFilteredRows(rRange.aStart.Row(), rRange.aEnd.Row());
3204  if (bAnswer)
3205  return true;
3206  }
3207  return false;
3208 }
3209 
3210 void ScDocument::MixDocument( const ScRange& rRange, ScPasteFunc nFunction, bool bSkipEmpty,
3211  ScDocument* pSrcDoc )
3212 {
3213  SCTAB nTab1 = rRange.aStart.Tab();
3214  SCTAB nTab2 = rRange.aEnd.Tab();
3215  sc::MixDocContext aCxt(*this);
3216  SCTAB nMinSizeBothTabs = static_cast<SCTAB>(std::min(maTabs.size(), pSrcDoc->maTabs.size()));
3217  for (SCTAB i = nTab1; i <= nTab2 && i < nMinSizeBothTabs; i++)
3218  {
3219  ScTable* pTab = FetchTable(i);
3220  const ScTable* pSrcTab = pSrcDoc->FetchTable(i);
3221  if (!pTab || !pSrcTab)
3222  continue;
3223 
3224  pTab->MixData(
3225  aCxt, rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(),
3226  nFunction, bSkipEmpty, pSrcTab);
3227  }
3228 }
3229 
3230 void ScDocument::FillTab( const ScRange& rSrcArea, const ScMarkData& rMark,
3231  InsertDeleteFlags nFlags, ScPasteFunc nFunction,
3232  bool bSkipEmpty, bool bAsLink )
3233 {
3234  InsertDeleteFlags nDelFlags = nFlags;
3235  if (nDelFlags & InsertDeleteFlags::CONTENTS)
3236  nDelFlags |= InsertDeleteFlags::CONTENTS; // Either all contents or delete nothing!
3237 
3238  SCTAB nSrcTab = rSrcArea.aStart.Tab();
3239 
3240  if (ValidTab(nSrcTab) && nSrcTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nSrcTab])
3241  {
3242  SCCOL nStartCol = rSrcArea.aStart.Col();
3243  SCROW nStartRow = rSrcArea.aStart.Row();
3244  SCCOL nEndCol = rSrcArea.aEnd.Col();
3245  SCROW nEndRow = rSrcArea.aEnd.Row();
3246  ScDocumentUniquePtr pMixDoc;
3247  bool bDoMix = ( bSkipEmpty || nFunction != ScPasteFunc::NONE ) && ( nFlags & InsertDeleteFlags::CONTENTS );
3248 
3249  bool bOldAutoCalc = GetAutoCalc();
3250  SetAutoCalc( false ); // avoid multiple calculations
3251 
3252  sc::CopyToDocContext aCxt(*this);
3253  sc::MixDocContext aMixDocCxt(*this);
3254 
3255  SCTAB nCount = static_cast<SCTAB>(maTabs.size());
3256  for (const SCTAB& i : rMark)
3257  {
3258  if (i >= nCount)
3259  break;
3260  if (i != nSrcTab && maTabs[i])
3261  {
3262  if (bDoMix)
3263  {
3264  if (!pMixDoc)
3265  {
3266  pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
3267  pMixDoc->InitUndo( this, i, i );
3268  }
3269  else
3270  pMixDoc->AddUndoTab( i, i );
3271 
3272  // context used for copying content to the temporary mix document.
3273  sc::CopyToDocContext aMixCxt(*pMixDoc);
3274  maTabs[i]->CopyToTable(aMixCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3275  InsertDeleteFlags::CONTENTS, false, pMixDoc->maTabs[i].get(),
3276  /*pMarkData*/nullptr, /*bAsLink*/false, /*bColRowFlags*/true,
3277  /*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true );
3278  }
3279  maTabs[i]->DeleteArea( nStartCol,nStartRow, nEndCol,nEndRow, nDelFlags);
3280  maTabs[nSrcTab]->CopyToTable(aCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3281  nFlags, false, maTabs[i].get(), nullptr, bAsLink,
3282  /*bColRowFlags*/true, /*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true );
3283 
3284  if (bDoMix)
3285  maTabs[i]->MixData(aMixDocCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3286  nFunction, bSkipEmpty, pMixDoc->maTabs[i].get() );
3287  }
3288  }
3289 
3290  SetAutoCalc( bOldAutoCalc );
3291  }
3292  else
3293  {
3294  OSL_FAIL("wrong table");
3295  }
3296 }
3297 
3298 void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
3299  InsertDeleteFlags nFlags, ScPasteFunc nFunction,
3300  bool bSkipEmpty, bool bAsLink )
3301 {
3302  InsertDeleteFlags nDelFlags = nFlags;
3303  if (nDelFlags & InsertDeleteFlags::CONTENTS)
3304  nDelFlags |= InsertDeleteFlags::CONTENTS; // Either all contents or delete nothing!
3305 
3306  if (ValidTab(nSrcTab) && nSrcTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nSrcTab])
3307  {
3308  ScDocumentUniquePtr pMixDoc;
3309  bool bDoMix = ( bSkipEmpty || nFunction != ScPasteFunc::NONE ) && ( nFlags & InsertDeleteFlags::CONTENTS );
3310 
3311  bool bOldAutoCalc = GetAutoCalc();
3312  SetAutoCalc( false ); // avoid multiple calculations
3313 
3314  ScRange aArea;
3315  rMark.GetMultiMarkArea( aArea );
3316  SCCOL nStartCol = aArea.aStart.Col();
3317  SCROW nStartRow = aArea.aStart.Row();
3318  SCCOL nEndCol = aArea.aEnd.Col();
3319  SCROW nEndRow = aArea.aEnd.Row();
3320 
3321  sc::CopyToDocContext aCxt(*this);
3322  sc::MixDocContext aMixDocCxt(*this);
3323  SCTAB nCount = static_cast<SCTAB>(maTabs.size());
3324  for (const SCTAB& i : rMark)
3325  {
3326  if (i >= nCount)
3327  break;
3328  if ( i != nSrcTab && maTabs[i] )
3329  {
3330  if (bDoMix)
3331  {
3332  if (!pMixDoc)
3333  {
3334  pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
3335  pMixDoc->InitUndo( this, i, i );
3336  }
3337  else
3338  pMixDoc->AddUndoTab( i, i );
3339 
3340  sc::CopyToDocContext aMixCxt(*pMixDoc);
3341  maTabs[i]->CopyToTable(aMixCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3342  InsertDeleteFlags::CONTENTS, true, pMixDoc->maTabs[i].get(), &rMark,
3343  /*bAsLink*/false, /*bColRowFlags*/true, /*bGlobalNamesToLocal*/false,
3344  /*bCopyCaptions*/true );
3345  }
3346 
3347  maTabs[i]->DeleteSelection( nDelFlags, rMark );
3348  maTabs[nSrcTab]->CopyToTable(aCxt, nStartCol,nStartRow, nEndCol,nEndRow,
3349  nFlags, true, maTabs[i].get(), &rMark, bAsLink,
3350  /*bColRowFlags*/true, /*bGlobalNamesToLocal*/false, /*bCopyCaptions*/true );
3351 
3352  if (bDoMix)
3353  maTabs[i]->MixMarked(aMixDocCxt, rMark, nFunction, bSkipEmpty, pMixDoc->maTabs[i].get());
3354  }
3355  }
3356 
3357  SetAutoCalc( bOldAutoCalc );
3358  }
3359  else
3360  {
3361  OSL_FAIL("wrong table");
3362  }
3363 }
3364 
3365 bool ScDocument::SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString& rString,
3366  const ScSetStringParam* pParam )
3367 {
3368  ScTable* pTab = FetchTable(nTab);
3369  if (!pTab)
3370  return false;
3371 
3372  const ScFormulaCell* pCurCellFormula = pTab->GetFormulaCell(nCol, nRow);
3373  if (pCurCellFormula && pCurCellFormula->IsShared())
3374  {
3375  // In case setting this string affects an existing formula group, end
3376  // its listening to purge then empty cell broadcasters. Affected
3377  // remaining split group listeners will be set up again via
3378  // ScColumn::DetachFormulaCell() and
3379  // ScColumn::StartListeningUnshared().
3380 
3381  sc::EndListeningContext aCxt(*this);
3382  ScAddress aPos(nCol, nRow, nTab);
3383  EndListeningIntersectedGroup(aCxt, aPos, nullptr);
3384  aCxt.purgeEmptyBroadcasters();
3385  }
3386 
3387  return pTab->SetString(nCol, nRow, nTab, rString, pParam);
3388 }
3389 
3391  const ScAddress& rPos, const OUString& rString, const ScSetStringParam* pParam )
3392 {
3393  return SetString(rPos.Col(), rPos.Row(), rPos.Tab(), rString, pParam);
3394 }
3395 
3396 bool ScDocument::SetEditText( const ScAddress& rPos, std::unique_ptr<EditTextObject> pEditText )
3397 {
3398  if (!TableExists(rPos.Tab()))
3399  {
3400  return false;
3401  }
3402 
3403  return maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), std::move(pEditText));
3404 }
3405 
3406 void ScDocument::SetEditText( const ScAddress& rPos, const EditTextObject& rEditText, const SfxItemPool* pEditPool )
3407 {
3408  if (!TableExists(rPos.Tab()))
3409  return;
3410 
3411  maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), rEditText, pEditPool);
3412 }
3413 
3414 void ScDocument::SetEditText( const ScAddress& rPos, const OUString& rStr )
3415 {
3416  if (!TableExists(rPos.Tab()))
3417  return;
3418 
3419  ScFieldEditEngine& rEngine = GetEditEngine();
3420  rEngine.SetTextCurrentDefaults(rStr);
3421  maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), rEngine.CreateTextObject());
3422 }
3423 
3425 {
3426  const ScTable* pTab = FetchTable(rRange.aStart.Tab());
3427  if (!pTab)
3428  return -1;
3429 
3430  return pTab->GetFirstEditTextRow(rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
3431 }
3432 
3433 void ScDocument::SetTextCell( const ScAddress& rPos, const OUString& rStr )
3434 {
3435  if (!TableExists(rPos.Tab()))
3436  return;
3437 
3438  if (ScStringUtil::isMultiline(rStr))
3439  {
3440  ScFieldEditEngine& rEngine = GetEditEngine();
3441  rEngine.SetTextCurrentDefaults(rStr);
3442  maTabs[rPos.Tab()]->SetEditText(rPos.Col(), rPos.Row(), rEngine.CreateTextObject());
3443  }
3444  else
3445  {
3446  ScSetStringParam aParam;
3447  aParam.setTextInput();
3448  maTabs[rPos.Tab()]->SetString(rPos.Col(), rPos.Row(), rPos.Tab(), rStr, &aParam);
3449  }
3450 }
3451 
3453 {
3454  if (!TableExists(rPos.Tab()))
3455  return;
3456 
3457  maTabs[rPos.Tab()]->SetEmptyCell(rPos.Col(), rPos.Row());
3458 }
3459 
3460 void ScDocument::SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal )
3461 {
3462  SetValue(ScAddress(nCol, nRow, nTab), rVal);
3463 }
3464 
3465 void ScDocument::SetValue( const ScAddress& rPos, double fVal )
3466 {
3467  ScTable* pTab = FetchTable(rPos.Tab());
3468  if (!pTab)
3469  return;
3470 
3471  const ScFormulaCell* pCurCellFormula = pTab->GetFormulaCell(rPos.Col(), rPos.Row());
3472  if (pCurCellFormula && pCurCellFormula->IsShared())
3473  {
3474  // In case setting this value affects an existing formula group, end
3475  // its listening to purge then empty cell broadcasters. Affected
3476  // remaining split group listeners will be set up again via
3477  // ScColumn::DetachFormulaCell() and
3478  // ScColumn::StartListeningUnshared().
3479 
3480  sc::EndListeningContext aCxt(*this);
3481  EndListeningIntersectedGroup(aCxt, rPos, nullptr);
3482  aCxt.purgeEmptyBroadcasters();
3483  }
3484 
3485  pTab->SetValue(rPos.Col(), rPos.Row(), fVal);
3486 }
3487 
3488 OUString ScDocument::GetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScInterpreterContext* pContext ) const
3489 {
3490  if (TableExists(nTab))
3491  {
3492  OUString aStr;
3493  maTabs[nTab]->GetString(nCol, nRow, aStr, pContext);
3494  return aStr;
3495  }
3496  else
3497  return EMPTY_OUSTRING;
3498 }
3499 
3500 OUString ScDocument::GetString( const ScAddress& rPos, const ScInterpreterContext* pContext ) const
3501 {
3502  if (!TableExists(rPos.Tab()))
3503  return EMPTY_OUSTRING;
3504 
3505  OUString aStr;
3506  maTabs[rPos.Tab()]->GetString(rPos.Col(), rPos.Row(), aStr, pContext);
3507  return aStr;
3508 }
3509 
3510 double* ScDocument::GetValueCell( const ScAddress& rPos )
3511 {
3512  if (!TableExists(rPos.Tab()))
3513  return nullptr;
3514 
3515  return maTabs[rPos.Tab()]->GetValueCell(rPos.Col(), rPos.Row());
3516 }
3517 
3519 {
3520  if (!TableExists(rPos.Tab()))
3521  return svl::SharedString();
3522 
3523  return maTabs[rPos.Tab()]->GetSharedString(rPos.Col(), rPos.Row());
3524 }
3525 
3526 std::shared_ptr<sc::FormulaGroupContext>& ScDocument::GetFormulaGroupContext()
3527 {
3529  if (!mpFormulaGroupCxt)
3530  mpFormulaGroupCxt = std::make_shared<sc::FormulaGroupContext>();
3531 
3532  return mpFormulaGroupCxt;
3533 }
3534 
3536 {
3539  mpFormulaGroupCxt.reset();
3540 }
3541 
3542 void ScDocument::GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rString )
3543 {
3544  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3545  maTabs[nTab]->GetInputString( nCol, nRow, rString );
3546  else
3547  rString.clear();
3548 }
3549 
3550 FormulaError ScDocument::GetStringForFormula( const ScAddress& rPos, OUString& rString )
3551 {
3552  // Used in formulas (add-in parameters etc), so it must use the same semantics as
3553  // ScInterpreter::GetCellString: always format values as numbers.
3554  // The return value is the error code.
3555 
3556  ScRefCellValue aCell(*this, rPos);
3557  if (aCell.isEmpty())
3558  {
3559  rString = EMPTY_OUSTRING;
3560  return FormulaError::NONE;
3561  }
3562 
3563  FormulaError nErr = FormulaError::NONE;
3564  OUString aStr;
3565  SvNumberFormatter* pFormatter = GetFormatTable();
3566  switch (aCell.meType)
3567  {
3568  case CELLTYPE_STRING:
3569  case CELLTYPE_EDIT:
3570  aStr = aCell.getString(this);
3571  break;
3572  case CELLTYPE_FORMULA:
3573  {
3574  ScFormulaCell* pFCell = aCell.mpFormula;
3575  nErr = pFCell->GetErrCode();
3576  if (pFCell->IsValue())
3577  {
3578  double fVal = pFCell->GetValue();
3579  sal_uInt32 nIndex = pFormatter->GetStandardFormat(
3580  SvNumFormatType::NUMBER,
3581  ScGlobal::eLnge);
3582  pFormatter->GetInputLineString(fVal, nIndex, aStr);
3583  }
3584  else
3585  aStr = pFCell->GetString().getString();
3586  }
3587  break;
3588  case CELLTYPE_VALUE:
3589  {
3590  double fVal = aCell.mfValue;
3591  sal_uInt32 nIndex = pFormatter->GetStandardFormat(
3592  SvNumFormatType::NUMBER,
3593  ScGlobal::eLnge);
3594  pFormatter->GetInputLineString(fVal, nIndex, aStr);
3595  }
3596  break;
3597  default:
3598  ;
3599  }
3600 
3601  rString = aStr;
3602  return nErr;
3603 }
3604 
3605 void ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, double& rValue ) const
3606 {
3607  if (TableExists(nTab))
3608  rValue = maTabs[nTab]->GetValue( nCol, nRow );
3609  else
3610  rValue = 0.0;
3611 }
3612 
3614 {
3615  SCTAB nTab = rPos.Tab();
3616  if (!TableExists(nTab))
3617  return nullptr;
3618 
3619  return maTabs[nTab]->GetEditText(rPos.Col(), rPos.Row());
3620 }
3621 
3623 {
3624  if (!TableExists(rPos.Tab()))
3625  return;
3626 
3627  return maTabs[rPos.Tab()]->RemoveEditTextCharAttribs(rPos.Col(), rPos.Row(), rAttr);
3628 }
3629 
3630 double ScDocument::GetValue( const ScAddress& rPos ) const
3631 {
3632  SCTAB nTab = rPos.Tab();
3633  if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3634  return maTabs[nTab]->GetValue(rPos.Col(), rPos.Row());
3635  return 0.0;
3636 }
3637 
3638 double ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3639 {
3640  ScAddress aAdr(nCol, nRow, nTab); return GetValue(aAdr);
3641 }
3642 
3644  sal_uInt32& rFormat ) const
3645 {
3646  if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
3647  if (maTabs[nTab])
3648  {
3649  rFormat = maTabs[nTab]->GetNumberFormat( nCol, nRow );
3650  return ;
3651  }
3652  rFormat = 0;
3653 }
3654 
3655 sal_uInt32 ScDocument::GetNumberFormat( const ScRange& rRange ) const
3656 {
3657  SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = rRange.aEnd.Tab();
3658  SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
3659  SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
3660 
3661  if (!TableExists(nTab1) || !TableExists(nTab2))
3662  return 0;
3663 
3664  sal_uInt32 nFormat = 0;
3665  bool bFirstItem = true;
3666  for (SCTAB nTab = nTab1; nTab <= nTab2 && nTab < static_cast<SCTAB>(maTabs.size()) ; ++nTab)
3667  for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
3668  {
3669  sal_uInt32 nThisFormat = maTabs[nTab]->GetNumberFormat(nCol, nRow1, nRow2);
3670  if (bFirstItem)
3671  {
3672  nFormat = nThisFormat;
3673  bFirstItem = false;
3674  }
3675  else if (nThisFormat != nFormat)
3676  return 0;
3677  }
3678 
3679  return nFormat;
3680 }
3681 
3682 sal_uInt32 ScDocument::GetNumberFormat( const ScInterpreterContext& rContext, const ScAddress& rPos ) const
3683 {
3684  SCTAB nTab = rPos.Tab();
3685  if (!TableExists(nTab))
3686  return 0;
3687 
3688  return maTabs[nTab]->GetNumberFormat( rContext, rPos );
3689 }
3690 
3691 void ScDocument::SetNumberFormat( const ScAddress& rPos, sal_uInt32 nNumberFormat )
3692 {
3694  SCTAB nTab = rPos.Tab();
3695  if (!TableExists(nTab))
3696  return;
3697 
3698  maTabs[nTab]->SetNumberFormat(rPos.Col(), rPos.Row(), nNumberFormat);
3699 }
3700 
3702  const ScAddress& rPos ) const
3703 {
3704  SCTAB nTab = rPos.Tab();
3705  if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3706  {
3707  nIndex = maTabs[nTab]->GetNumberFormat( rContext, rPos );
3708  nType = rContext.GetNumberFormatType( nIndex );
3709  }
3710  else
3711  {
3712  nType = SvNumFormatType::UNDEFINED;
3713  nIndex = 0;
3714  }
3715 }
3716 
3717 void ScDocument::GetFormula( SCCOL nCol, SCROW nRow, SCTAB nTab, OUString& rFormula ) const
3718 {
3719  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3720  maTabs[nTab]->GetFormula( nCol, nRow, rFormula );
3721  else
3722  rFormula.clear();
3723 }
3724 
3726 {
3727  if (!TableExists(rPos.Tab()))
3728  return nullptr;
3729 
3730  return maTabs[rPos.Tab()]->GetFormulaCell(rPos.Col(), rPos.Row());
3731 }
3732 
3734 {
3735  if (!TableExists(rPos.Tab()))
3736  return nullptr;
3737 
3738  return maTabs[rPos.Tab()]->GetFormulaCell(rPos.Col(), rPos.Row());
3739 }
3740 
3742 {
3743  SCTAB nTab = rPos.Tab();
3744  if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
3745  return maTabs[nTab]->GetCellType( rPos );
3746  return CELLTYPE_NONE;
3747 }
3748 
3749 void ScDocument::GetCellType( SCCOL nCol, SCROW nRow, SCTAB nTab,
3750  CellType& rCellType ) const
3751 {
3752  if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
3753  rCellType = maTabs[nTab]->GetCellType( nCol, nRow );
3754  else
3755  rCellType = CELLTYPE_NONE;
3756 }
3757 
3758 bool ScDocument::HasStringData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3759 {
3760  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab]
3761  && nCol < maTabs[nTab]->GetAllocatedColumnsCount())
3762  return maTabs[nTab]->HasStringData( nCol, nRow );
3763  else
3764  return false;
3765 }
3766 
3767 bool ScDocument::HasValueData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3768 {
3769  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab]
3770  && nCol < maTabs[nTab]->GetAllocatedColumnsCount())
3771  return maTabs[nTab]->HasValueData( nCol, nRow );
3772  else
3773  return false;
3774 }
3775 
3776 bool ScDocument::HasValueData( const ScAddress& rPos ) const
3777 {
3778  return HasValueData(rPos.Col(), rPos.Row(), rPos.Tab());
3779 }
3780 
3781 bool ScDocument::HasStringCells( const ScRange& rRange ) const
3782 {
3783  // true, if String- or Edit cells in range
3784 
3785  SCCOL nStartCol = rRange.aStart.Col();
3786  SCROW nStartRow = rRange.aStart.Row();
3787  SCTAB nStartTab = rRange.aStart.Tab();
3788  SCCOL nEndCol = rRange.aEnd.Col();
3789  SCROW nEndRow = rRange.aEnd.Row();
3790  SCTAB nEndTab = rRange.aEnd.Tab();
3791 
3792  for ( SCTAB nTab=nStartTab; nTab<=nEndTab && nTab < static_cast<SCTAB>(maTabs.size()); nTab++ )
3793  if ( maTabs[nTab] && maTabs[nTab]->HasStringCells( nStartCol, nStartRow, nEndCol, nEndRow ) )
3794  return true;
3795 
3796  return false;
3797 }
3798 
3799 bool ScDocument::HasSelectionData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3800 {
3801  sal_uInt32 nValidation = GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA )->GetValue();
3802  if( nValidation )
3803  {
3804  const ScValidationData* pData = GetValidationEntry( nValidation );
3805  if( pData && pData->HasSelectionList() )
3806  return true;
3807  }
3808  return HasStringCells( ScRange( nCol, 0, nTab, nCol, MaxRow(), nTab ) );
3809 }
3810 
3811 bool ScDocument::HasValidationData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
3812 {
3813  sal_uInt32 nValidation = GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA )->GetValue();
3814  if( nValidation )
3815  {
3816  const ScValidationData* pData = GetValidationEntry( nValidation );
3817  if( pData && pData->GetDataMode() != ScValidationMode::SC_VALID_ANY )
3818  return true;
3819  }
3820  return false;
3821 }
3822 
3824 {
3825  bool bOldAutoCalc = GetAutoCalc();
3826  bAutoCalc = false; // no multiple calculations
3827 
3828  for (const auto& a : maTabs)
3829  {
3830  if (a)
3831  a->CheckVectorizationState();
3832  }
3833 
3834  SetAutoCalc(bOldAutoCalc);
3835 }
3836 
3838 {
3839  bool bOldAutoCalc = GetAutoCalc();
3840  bAutoCalc = false; // no multiple calculations
3841  { // scope for bulk broadcast
3842  ScBulkBroadcast aBulkBroadcast( GetBASM(), SfxHintId::ScDataChanged);
3843  for (const auto& a : maTabs)
3844  {
3845  if (a)
3846  a->SetAllFormulasDirty(rCxt);
3847  }
3848  }
3849 
3850  // Although Charts are also set to dirty in Tracking without AutoCalc
3851  // if all formulas are dirty, the charts can no longer be caught
3852  // (#45205#) - that is why all Charts have to be explicitly handled again
3854  pChartListenerCollection->SetDirty();
3855 
3856  SetAutoCalc( bOldAutoCalc );
3857 }
3858 
3859 void ScDocument::SetDirty( const ScRange& rRange, bool bIncludeEmptyCells )
3860 {
3861  bool bOldAutoCalc = GetAutoCalc();
3862  bAutoCalc = false; // no multiple calculations
3863  { // scope for bulk broadcast
3864  ScBulkBroadcast aBulkBroadcast( GetBASM(), SfxHintId::ScDataChanged);
3865  SCTAB nTab2 = rRange.aEnd.Tab();
3866  for (SCTAB i=rRange.aStart.Tab(); i<=nTab2 && i < static_cast<SCTAB>(maTabs.size()); i++)
3867  if (maTabs[i]) maTabs[i]->SetDirty( rRange,
3869 
3870  /* TODO: this now also notifies conditional formatting and does a UNO
3871  * broadcast, which wasn't done here before. Is that an actually
3872  * desired side effect, or should we come up with a method that
3873  * doesn't? */
3874  if (bIncludeEmptyCells)
3875  BroadcastCells( rRange, SfxHintId::ScDataChanged, false);
3876  }
3877  SetAutoCalc( bOldAutoCalc );
3878 }
3879 
3881 {
3882  bool bOldAutoCalc = GetAutoCalc();
3883  bAutoCalc = false; // no multiple recalculation
3884  SCTAB nTab2 = rRange.aEnd.Tab();
3885  for (SCTAB i=rRange.aStart.Tab(); i<=nTab2 && i < static_cast<SCTAB>(maTabs.size()); i++)
3886  if (maTabs[i]) maTabs[i]->SetTableOpDirty( rRange );
3887  SetAutoCalc( bOldAutoCalc );
3888 }
3889 
3891 {
3892  if (!GetAutoCalc())
3893  return;
3894 
3896 
3897  for (size_t nPos=0, nRangeCount = rRanges.size(); nPos < nRangeCount; nPos++)
3898  {
3899  const ScRange& rRange = rRanges[nPos];
3900  for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
3901  {
3902  ScTable* pTab = FetchTable(nTab);
3903  if (!pTab)
3904  return;
3905 
3906  pTab->InterpretDirtyCells(
3907  rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
3908  }
3909  }
3910 
3912  mpFormulaGroupCxt.reset();
3913 }
3914 
3916 {
3917  if (m_TableOpList.empty())
3918  return;
3919 
3920  ScInterpreterTableOpParams *const p = m_TableOpList.back();
3921  if ( p->bCollectNotifications )
3922  {
3923  if ( p->bRefresh )
3924  { // refresh pointers only
3925  p->aNotifiedFormulaCells.push_back( pCell );
3926  }
3927  else
3928  { // init both, address and pointer
3929  p->aNotifiedFormulaCells.push_back( pCell );
3930  p->aNotifiedFormulaPos.push_back( pCell->aPos );
3931  }
3932  }
3933 }
3934 
3936 {
3938  ClearLookupCaches(); // Ensure we don't deliver zombie data.
3939  sc::AutoCalcSwitch aSwitch(*this, true);
3940  for (const auto& a : maTabs)
3941  {
3942  if (a)
3943  a->SetDirtyVar();
3944  }
3945  for (const auto& a : maTabs)
3946  {
3947  if (a)
3948  a->CalcAll();
3949  }
3950  ClearFormulaTree();
3951 
3952  // In eternal hard recalc state caches were not added as listeners,
3953  // invalidate them so the next non-CalcAll() normal lookup will not be
3954  // presented with outdated data.
3957 }
3958 
3960 {
3961  sc::CompileFormulaContext aCxt(this);
3962  for (const auto& a : maTabs)
3963  {
3964  if (a)
3965  a->CompileAll(aCxt);
3966  }
3967 
3968  sc::SetFormulaDirtyContext aFormulaDirtyCxt;
3969  SetAllFormulasDirty(aFormulaDirtyCxt);
3970 }
3971 
3973 {
3974  bool bOldAutoCalc = GetAutoCalc();
3975  SetAutoCalc( false );
3976  ScProgress aProgress( GetDocumentShell(), ScResId(
3977  STR_PROGRESS_CALCULATING ), GetXMLImportedFormulaCount(), true );
3978 
3979  sc::CompileFormulaContext aCxt(this);
3980 
3981  // set AutoNameCache to speed up automatic name lookup
3982  OSL_ENSURE( !pAutoNameCache, "AutoNameCache already set" );
3983  pAutoNameCache.reset( new ScAutoNameCache( this ) );
3984 
3985  if (pRangeName)
3986  pRangeName->CompileUnresolvedXML(aCxt);
3987 
3988  std::for_each(maTabs.begin(), maTabs.end(),
3989  [&](ScTableUniquePtr & pTab)
3990  {
3991  if (pTab)
3992  pTab->CompileXML(aCxt, aProgress);
3993  }
3994  );
3996 
3997  pAutoNameCache.reset(); // valid only during CompileXML, where cell contents don't change
3998 
3999  if ( pValidationList )
4000  {
4002  pValidationList->CompileXML();
4003  }
4004 
4005  // Track all formula cells that were appended to the FormulaTrack during
4006  // import or CompileXML().
4007  TrackFormulas();
4008 
4009  SetAutoCalc( bOldAutoCalc );
4010 }
4011 
4013 {
4014  bool bCompiled = false;
4015  sc::CompileFormulaContext aCxt(this);
4016  for (const auto& a : maTabs)
4017  {
4018  if (!a)
4019  continue;
4020 
4021  if (a->CompileErrorCells(aCxt, nErrCode))
4022  bCompiled = true;
4023  }
4024 
4025  return bCompiled;
4026 }
4027 
4028 void ScDocument::CalcAfterLoad( bool bStartListening )
4029 {
4030  if (bIsClip) // Excel data is loaded from the Clipboard to a Clip-Doc
4031  return; // the calculation is then only performed when inserting into the real document
4032 
4033  bCalcingAfterLoad = true;
4034  sc::CompileFormulaContext aCxt(this);
4035  {
4036  for (const auto& a : maTabs)
4037  {
4038  if (a)
4039  a->CalcAfterLoad(aCxt, bStartListening);
4040  }
4041  for (const auto& a : maTabs)
4042  {
4043  if (a)
4044  a->SetDirtyAfterLoad();
4045  }
4046  }
4047  bCalcingAfterLoad = false;
4048 
4049  SetDetectiveDirty(false); // No real changes yet
4050 
4051  // #i112436# If formula cells are already dirty, they don't broadcast further changes.
4052  // So the source ranges of charts must be interpreted even if they are not visible,
4053  // similar to ScMyShapeResizer::CreateChartListener for loading own files (i104899).
4055  {
4056  const ScChartListenerCollection::ListenersType& rListeners = pChartListenerCollection->getListeners();
4057  for (auto const& it : rListeners)
4058  {
4059  const ScChartListener *const p = it.second.get();
4061  }
4062  }
4063 }
4064 
4066 {
4067  SCTAB nTab = rPos.Tab();
4068  if ( nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4069  return maTabs[nTab]->GetErrCode( rPos );
4070  return FormulaError::NONE;
4071 }
4072 
4073 void ScDocument::ResetChanged( const ScRange& rRange )
4074 {
4075  SCTAB nTabSize = static_cast<SCTAB>(maTabs.size());
4076  SCTAB nTab1 = rRange.aStart.Tab();
4077  SCTAB nTab2 = rRange.aEnd.Tab();
4078  for (SCTAB nTab = nTab1; nTab1 <= nTab2 && nTab < nTabSize; ++nTab)
4079  if (maTabs[nTab])
4080  maTabs[nTab]->ResetChanged(rRange);
4081 }
4082 
4083 // Column widths / Row heights --------------------------------------
4084 
4085 void ScDocument::SetColWidth( SCCOL nCol, SCTAB nTab, sal_uInt16 nNewWidth )
4086 {
4087  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4088  maTabs[nTab]->SetColWidth( nCol, nNewWidth );
4089 }
4090 
4091 void ScDocument::SetColWidthOnly( SCCOL nCol, SCTAB nTab, sal_uInt16 nNewWidth )
4092 {
4093  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4094  maTabs[nTab]->SetColWidthOnly( nCol, nNewWidth );
4095 }
4096 
4097 void ScDocument::SetRowHeight( SCROW nRow, SCTAB nTab, sal_uInt16 nNewHeight )
4098 {
4099  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4100  maTabs[nTab]->SetRowHeight( nRow, nNewHeight );
4101 }
4102 
4103 void ScDocument::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
4104 {
4105  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4106  maTabs[nTab]->SetRowHeightRange
4107  ( nStartRow, nEndRow, nNewHeight, 1.0 );
4108 }
4109 
4110 void ScDocument::SetRowHeightOnly( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, sal_uInt16 nNewHeight )
4111 {
4112  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4113  maTabs[nTab]->SetRowHeightOnly( nStartRow, nEndRow, nNewHeight );
4114 }
4115 
4116 void ScDocument::SetManualHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bManual )
4117 {
4118  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4119  maTabs[nTab]->SetManualHeight( nStartRow, nEndRow, bManual );
4120 }
4121 
4122 sal_uInt16 ScDocument::GetColWidth( SCCOL nCol, SCTAB nTab, bool bHiddenAsZero ) const
4123 {
4124  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4125  return maTabs[nTab]->GetColWidth( nCol, bHiddenAsZero );
4126  OSL_FAIL("wrong table number");
4127  return 0;
4128 }
4129 
4130 sal_uLong ScDocument::GetColWidth( SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab ) const
4131 {
4132  const ScTable* pTab = FetchTable(nTab);
4133  if (!pTab)
4134  return 0;
4135 
4136  return pTab->GetColWidth(nStartCol, nEndCol);
4137 }
4138 
4139 sal_uInt16 ScDocument::GetOriginalWidth( SCCOL nCol, SCTAB nTab ) const
4140 {
4141  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4142  return maTabs[nTab]->GetOriginalWidth( nCol );
4143  OSL_FAIL("wrong table number");
4144  return 0;
4145 }
4146 
4147 sal_uInt16 ScDocument::GetCommonWidth( SCCOL nEndCol, SCTAB nTab ) const
4148 {
4149  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4150  return maTabs[nTab]->GetCommonWidth( nEndCol );
4151  OSL_FAIL("Wrong table number");
4152  return 0;
4153 }
4154 
4155 sal_uInt16 ScDocument::GetOriginalHeight( SCROW nRow, SCTAB nTab ) const
4156 {
4157  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4158  return maTabs[nTab]->GetOriginalHeight( nRow );
4159  OSL_FAIL("Wrong table number");
4160  return 0;
4161 }
4162 
4163 sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, bool bHiddenAsZero ) const
4164 {
4165  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4166  return maTabs[nTab]->GetRowHeight( nRow, nullptr, nullptr, bHiddenAsZero );
4167  OSL_FAIL("Wrong sheet number");
4168  return 0;
4169 }
4170 
4171 sal_uInt16 ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab, SCROW* pStartRow, SCROW* pEndRow ) const
4172 {
4173  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4174  return maTabs[nTab]->GetRowHeight( nRow, pStartRow, pEndRow );
4175  OSL_FAIL("Wrong sheet number");
4176  return 0;
4177 }
4178 
4179 sal_uLong ScDocument::GetRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHiddenAsZero ) const
4180 {
4181  if (nStartRow == nEndRow)
4182  return GetRowHeight( nStartRow, nTab, bHiddenAsZero ); // faster for a single row
4183 
4184  // check bounds because this method replaces former for(i=start;i<=end;++i) loops
4185  if (nStartRow > nEndRow)
4186  return 0;
4187 
4188  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4189  return maTabs[nTab]->GetRowHeight( nStartRow, nEndRow, bHiddenAsZero );
4190 
4191  OSL_FAIL("wrong sheet number");
4192  return 0;
4193 }
4194 
4196 {
4197  return maTabs[nTab]->GetRowForHeight(nHeight);
4198 }
4199 
4201  SCTAB nTab, double fScale, const sal_uLong* pnMaxHeight ) const
4202 {
4203  // faster for a single row
4204  if (nStartRow == nEndRow)
4205  return static_cast<sal_uLong>(GetRowHeight( nStartRow, nTab) * fScale);
4206 
4207  // check bounds because this method replaces former for(i=start;i<=end;++i) loops
4208  if (nStartRow > nEndRow)
4209  return 0;
4210 
4211  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4212  return maTabs[nTab]->GetScaledRowHeight( nStartRow, nEndRow, fScale, pnMaxHeight );
4213 
4214  OSL_FAIL("wrong sheet number");
4215  return 0;
4216 }
4217 
4219 {
4220  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4221  return maTabs[nTab]->GetHiddenRowCount( nRow );
4222  OSL_FAIL("wrong table number");
4223  return 0;
4224 }
4225 
4226 sal_uLong ScDocument::GetColOffset( SCCOL nCol, SCTAB nTab, bool bHiddenAsZero ) const
4227 {
4228  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4229  return maTabs[nTab]->GetColOffset( nCol, bHiddenAsZero );
4230  OSL_FAIL("wrong table number");
4231  return 0;
4232 }
4233 
4234 sal_uLong ScDocument::GetRowOffset( SCROW nRow, SCTAB nTab, bool bHiddenAsZero ) const
4235 {
4236  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4237  return maTabs[nTab]->GetRowOffset( nRow, bHiddenAsZero );
4238  OSL_FAIL("wrong table number");
4239  return 0;
4240 }
4241 
4243  double nPPTX, double nPPTY,
4244  const Fraction& rZoomX, const Fraction& rZoomY,
4245  bool bFormula, const ScMarkData* pMarkData,
4246  const ScColWidthParam* pParam )
4247 {
4248  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4249  return maTabs[nTab]->GetOptimalColWidth( nCol, pDev, nPPTX, nPPTY,
4250  rZoomX, rZoomY, bFormula, pMarkData, pParam );
4251  OSL_FAIL("wrong table number");
4252  return 0;
4253 }
4254 
4256  OutputDevice* pDev,
4257  double nPPTX, double nPPTY,
4258  const Fraction& rZoomX, const Fraction& rZoomY,
4259  bool bWidth, bool bTotalSize, bool bInPrintTwips )
4260 {
4261  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4262  return maTabs[nTab]->GetNeededSize
4263  ( nCol, nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, bTotalSize, bInPrintTwips );
4264  OSL_FAIL("wrong table number");
4265  return 0;
4266 }
4267 
4268 bool ScDocument::SetOptimalHeight( sc::RowHeightContext& rCxt, SCROW nStartRow, SCROW nEndRow, SCTAB nTab )
4269 {
4270  ScTable* pTab = FetchTable(nTab);
4271  if (!pTab)
4272  return false;
4273 
4274  return pTab->SetOptimalHeight(rCxt, nStartRow, nEndRow);
4275 }
4276 
4278 {
4279  // one progress across all (selected) sheets
4280 
4281  sal_uLong nCellCount = 0;
4282  for ( SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()); nTab++ )
4283  if ( maTabs[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
4284  nCellCount += maTabs[nTab]->GetWeightedCount();
4285 
4286  ScProgress aProgress( GetDocumentShell(), ScResId(STR_PROGRESS_HEIGHTING), nCellCount, true );
4287 
4288  sal_uLong nProgressStart = 0;
4289  for ( SCTAB nTab=0; nTab< static_cast<SCTAB>(maTabs.size()); nTab++ )
4290  if ( maTabs[nTab] && ( !pTabMark || pTabMark->GetTableSelect(nTab) ) )
4291  {
4292  maTabs[nTab]->SetOptimalHeightOnly(rCxt, 0, MaxRow(), &aProgress, nProgressStart);
4293  maTabs[nTab]->SetDrawPageSize();
4294  nProgressStart += maTabs[nTab]->GetWeightedCount();
4295  }
4296 }
4297 
4298 // Column/Row - Flags ----------------------------------------------
4299 
4300 void ScDocument::ShowCol(SCCOL nCol, SCTAB nTab, bool bShow)
4301 {
4302  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4303  maTabs[nTab]->ShowCol( nCol, bShow );
4304 }
4305 
4306 void ScDocument::ShowRow(SCROW nRow, SCTAB nTab, bool bShow)
4307 {
4308  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4309  maTabs[nTab]->ShowRow( nRow, bShow );
4310 }
4311 
4312 void ScDocument::ShowRows(SCROW nRow1, SCROW nRow2, SCTAB nTab, bool bShow)
4313 {
4314  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4315  maTabs[nTab]->ShowRows( nRow1, nRow2, bShow );
4316 }
4317 
4318 void ScDocument::SetRowFlags( SCROW nRow, SCTAB nTab, CRFlags nNewFlags )
4319 {
4320  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4321  maTabs[nTab]->SetRowFlags( nRow, nNewFlags );
4322 }
4323 
4324 void ScDocument::SetRowFlags( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, CRFlags nNewFlags )
4325 {
4326  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4327  maTabs[nTab]->SetRowFlags( nStartRow, nEndRow, nNewFlags );
4328 }
4329 
4331 {
4332  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4333  return maTabs[nTab]->GetColFlags( nCol );
4334  OSL_FAIL("wrong table number");
4335  return CRFlags::NONE;
4336 }
4337 
4339 {
4340  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4341  return maTabs[nTab]->GetRowFlags( nRow );
4342  OSL_FAIL("wrong table number");
4343  return CRFlags::NONE;
4344 }
4345 
4346 void ScDocument::GetAllRowBreaks(set<SCROW>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
4347 {
4348  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4349  return;
4350  maTabs[nTab]->GetAllRowBreaks(rBreaks, bPage, bManual);
4351 }
4352 
4353 void ScDocument::GetAllColBreaks(set<SCCOL>& rBreaks, SCTAB nTab, bool bPage, bool bManual) const
4354 {
4355  if (!ValidTab(nTab) || !maTabs[nTab])
4356  return;
4357 
4358  maTabs[nTab]->GetAllColBreaks(rBreaks, bPage, bManual);
4359 }
4360 
4362 {
4364  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
4365  return nType;
4366 
4367  if (maTabs[nTab]->HasRowPageBreak(nRow))
4368  nType |= ScBreakType::Page;
4369 
4370  if (maTabs[nTab]->HasRowManualBreak(nRow))
4371  nType |= ScBreakType::Manual;
4372 
4373  return nType;
4374 }
4375 
4377 {
4379  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
4380  return nType;
4381 
4382  if (maTabs[nTab]->HasColPageBreak(nCol))
4383  nType |= ScBreakType::Page;
4384 
4385  if (maTabs[nTab]->HasColManualBreak(nCol))
4386  nType |= ScBreakType::Manual;
4387 
4388  return nType;
4389 }
4390 
4391 void ScDocument::SetRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
4392 {
4393  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
4394  return;
4395 
4396  maTabs[nTab]->SetRowBreak(nRow, bPage, bManual);
4397 }
4398 
4399 void ScDocument::SetColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
4400 {
4401  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
4402  return;
4403 
4404  maTabs[nTab]->SetColBreak(nCol, bPage, bManual);
4405 }
4406 
4407 void ScDocument::RemoveRowBreak(SCROW nRow, SCTAB nTab, bool bPage, bool bManual)
4408 {
4409  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidRow(nRow))
4410  return;
4411 
4412  maTabs[nTab]->RemoveRowBreak(nRow, bPage, bManual);
4413 }
4414 
4415 void ScDocument::RemoveColBreak(SCCOL nCol, SCTAB nTab, bool bPage, bool bManual)
4416 {
4417  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab] || !ValidCol(nCol))
4418  return;
4419 
4420  maTabs[nTab]->RemoveColBreak(nCol, bPage, bManual);
4421 }
4422 
4423 Sequence<TablePageBreakData> ScDocument::GetRowBreakData(SCTAB nTab) const
4424 {
4425  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4426  return Sequence<TablePageBreakData>();
4427 
4428  return maTabs[nTab]->GetRowBreakData();
4429 }
4430 
4431 bool ScDocument::RowHidden(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow) const
4432 {
4433  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4434  return false;
4435 
4436  return maTabs[nTab]->RowHidden(nRow, pFirstRow, pLastRow);
4437 }
4438 
4439 bool ScDocument::HasHiddenRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4440 {
4441  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4442  return false;
4443 
4444  return maTabs[nTab]->HasHiddenRows(nStartRow, nEndRow);
4445 }
4446 
4447 bool ScDocument::ColHidden(SCCOL nCol, SCTAB nTab, SCCOL* pFirstCol, SCCOL* pLastCol) const
4448 {
4449  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4450  {
4451  if (pFirstCol)
4452  *pFirstCol = nCol;
4453  if (pLastCol)
4454  *pLastCol = nCol;
4455  return false;
4456  }
4457 
4458  return maTabs[nTab]->ColHidden(nCol, pFirstCol, pLastCol);
4459 }
4460 
4461 void ScDocument::SetRowHidden(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bHidden)
4462 {
4463  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4464  return;
4465 
4466  maTabs[nTab]->SetRowHidden(nStartRow, nEndRow, bHidden);
4467 }
4468 
4469 void ScDocument::SetColHidden(SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, bool bHidden)
4470 {
4471  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4472  return;
4473 
4474  maTabs[nTab]->SetColHidden(nStartCol, nEndCol, bHidden);
4475 }
4476 
4477 SCROW ScDocument::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4478 {
4479  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4480  return ::std::numeric_limits<SCROW>::max();
4481 
4482  return maTabs[nTab]->FirstVisibleRow(nStartRow, nEndRow);
4483 }
4484 
4485 SCROW ScDocument::LastVisibleRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4486 {
4487  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4488  return ::std::numeric_limits<SCROW>::max();
4489 
4490  return maTabs[nTab]->LastVisibleRow(nStartRow, nEndRow);
4491 }
4492 
4493 SCROW ScDocument::CountVisibleRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4494 {
4495  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4496  return 0;
4497 
4498  return maTabs[nTab]->CountVisibleRows(nStartRow, nEndRow);
4499 }
4500 
4501 bool ScDocument::RowFiltered(SCROW nRow, SCTAB nTab, SCROW* pFirstRow, SCROW* pLastRow) const
4502 {
4503  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4504  return false;
4505 
4506  return maTabs[nTab]->RowFiltered(nRow, pFirstRow, pLastRow);
4507 }
4508 
4509 bool ScDocument::HasFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4510 {
4511  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4512  return false;
4513 
4514  return maTabs[nTab]->HasFilteredRows(nStartRow, nEndRow);
4515 }
4516 
4517 bool ScDocument::ColFiltered(SCCOL nCol, SCTAB nTab) const
4518 {
4519  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4520  return false;
4521 
4522  return maTabs[nTab]->ColFiltered(nCol);
4523 }
4524 
4525 void ScDocument::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, bool bFiltered)
4526 {
4527  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4528  return;
4529 
4530  maTabs[nTab]->SetRowFiltered(nStartRow, nEndRow, bFiltered);
4531 }
4532 
4533 SCROW ScDocument::FirstNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4534 {
4535  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4536  return ::std::numeric_limits<SCROW>::max();
4537 
4538  return maTabs[nTab]->FirstNonFilteredRow(nStartRow, nEndRow);
4539 }
4540 
4541 SCROW ScDocument::LastNonFilteredRow(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4542 {
4543  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4544  return ::std::numeric_limits<SCROW>::max();
4545 
4546  return maTabs[nTab]->LastNonFilteredRow(nStartRow, nEndRow);
4547 }
4548 
4549 SCROW ScDocument::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow, SCTAB nTab) const
4550 {
4551  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4552  return 0;
4553 
4554  return maTabs[nTab]->CountNonFilteredRows(nStartRow, nEndRow);
4555 }
4556 
4558 {
4559  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4560  return false;
4561 
4562  return maTabs[nTab]->IsManualRowHeight(nRow);
4563 }
4564 
4566 {
4567  for (const auto& a : maTabs)
4568  {
4569  if (a)
4570  a->SyncColRowFlags();
4571  }
4572 }
4573 
4575 {
4576  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4577  return maTabs[nTab]->GetLastFlaggedRow();
4578  return 0;
4579 }
4580 
4582 {
4583  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4584  return maTabs[nTab]->GetLastChangedCol();
4585  return 0;
4586 }
4587 
4589 {
4590  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4591  return maTabs[nTab]->GetLastChangedRow();
4592  return 0;
4593 }
4594 
4596 {
4597  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4598  {
4599  CRFlags nStartFlags = maTabs[nTab]->GetColFlags(nStart);
4600  sal_uInt16 nStartWidth = maTabs[nTab]->GetOriginalWidth(nStart);
4601  for (SCCOL nCol : maTabs[nTab]->GetColumnsRange( nStart + 1, MaxCol()))
4602  {
4603  if (((nStartFlags & CRFlags::ManualBreak) != (maTabs[nTab]->GetColFlags(nCol) & CRFlags::ManualBreak)) ||
4604  (nStartWidth != maTabs[nTab]->GetOriginalWidth(nCol)) ||
4605  ((nStartFlags & CRFlags::Hidden) != (maTabs[nTab]->GetColFlags(nCol) & CRFlags::Hidden)) )
4606  return nCol;
4607  }
4608  return MaxCol()+1;
4609  }
4610  return 0;
4611 }
4612 
4614 {
4615  if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab])
4616  return 0;
4617 
4618  const ScBitMaskCompressedArray<SCROW, CRFlags>* pRowFlagsArray = maTabs[nTab]->GetRowFlagsArray();
4619  if (!pRowFlagsArray)
4620  return 0;
4621 
4622  if (!maTabs[nTab]->mpRowHeights || !maTabs[nTab]->mpHiddenRows)
4623  return 0;
4624 
4625  size_t nIndex; // ignored
4626  SCROW nFlagsEndRow;
4627  SCROW nHiddenEndRow;
4628  SCROW nHeightEndRow;
4629  CRFlags nFlags;
4630  bool bHidden;
4631  sal_uInt16 nHeight;
4632  CRFlags nStartFlags = nFlags = pRowFlagsArray->GetValue( nStart, nIndex, nFlagsEndRow);
4633  bool bStartHidden = bHidden = maTabs[nTab]->RowHidden( nStart, nullptr, &nHiddenEndRow);
4634  sal_uInt16 nStartHeight = nHeight = maTabs[nTab]->GetRowHeight( nStart, nullptr, &nHeightEndRow, false);
4635  SCROW nRow;
4636  while ((nRow = std::min( nHiddenEndRow, std::min( nFlagsEndRow, nHeightEndRow)) + 1) <= MaxRow())
4637  {
4638  if (nFlagsEndRow < nRow)
4639  nFlags = pRowFlagsArray->GetValue( nRow, nIndex, nFlagsEndRow);
4640  if (nHiddenEndRow < nRow)
4641  bHidden = maTabs[nTab]->RowHidden( nRow, nullptr, &nHiddenEndRow);
4642  if (nHeightEndRow < nRow)
4643  nHeight = maTabs[nTab]->GetRowHeight( nRow, nullptr, &nHeightEndRow, false);
4644 
4645  if (((nStartFlags & CRFlags::ManualBreak) != (nFlags & CRFlags::ManualBreak)) ||
4646  ((nStartFlags & CRFlags::ManualSize) != (nFlags & CRFlags::ManualSize)) ||
4647  (bStartHidden != bHidden) ||
4648  (nStartHeight != nHeight))
4649  return nRow;
4650  }
4651 
4652  return MaxRow()+1;
4653 }
4654 
4655 void ScDocument::GetColDefault( SCTAB nTab, SCCOL nCol, SCROW nLastRow, SCROW& nDefault)
4656 {
4657  nDefault = 0;
4658  ScDocAttrIterator aDocAttrItr(this, nTab, nCol, 0, nCol, nLastRow);
4659  SCCOL nColumn;
4660  SCROW nStartRow;
4661  SCROW nEndRow;
4662  const ScPatternAttr* pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
4663  if (nEndRow >= nLastRow)
4664  return;
4665 
4666  ScDefaultAttrSet aSet;
4667  ScDefaultAttrSet::iterator aItr = aSet.end();
4668  while (pAttr)
4669  {
4670  ScDefaultAttr aAttr(pAttr);
4671  aItr = aSet.find(aAttr);
4672  if (aItr == aSet.end())
4673  {
4674  aAttr.nCount = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
4675  aAttr.nFirst = nStartRow;
4676  aSet.insert(aAttr);
4677  }
4678  else
4679  {
4680  aAttr.nCount = aItr->nCount + static_cast<SCSIZE>(nEndRow - nStartRow + 1);
4681  aAttr.nFirst = aItr->nFirst;
4682  aSet.erase(aItr);
4683  aSet.insert(aAttr);
4684  }
4685  pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
4686  }
4687  ScDefaultAttrSet::iterator aDefaultItr = aSet.begin();
4688  aItr = aDefaultItr;
4689  ++aItr;
4690  while (aItr != aSet.end())
4691  {
4692  // for entries with equal count, use the one with the lowest start row,
4693  // don't use the random order of pointer comparisons
4694  if ( aItr->nCount > aDefaultItr->nCount ||
4695  ( aItr->nCount == aDefaultItr->nCount && aItr->nFirst < aDefaultItr->nFirst ) )
4696  aDefaultItr = aItr;
4697  ++aItr;
4698  }
4699  nDefault = aDefaultItr->nFirst;
4700 }
4701 
4702 void ScDocument::StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
4703 {
4704  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4705  maTabs[nTab]->StripHidden( rX1, rY1, rX2, rY2 );
4706 }
4707 
4708 void ScDocument::ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
4709 {
4710  if ( ValidTab(nTab) && maTabs[nTab] )
4711  maTabs[nTab]->ExtendHidden( rX1, rY1, rX2, rY2 );
4712 }
4713 
4714 // Attribute ----------------------------------------------------------
4715 
4716 const SfxPoolItem* ScDocument::GetAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich ) const
4717 {
4718  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] &&
4719  nCol < maTabs[nTab]->GetAllocatedColumnsCount())
4720  {
4721  const SfxPoolItem* pTemp = maTabs[nTab]->GetAttr( nCol, nRow, nWhich );
4722  if (pTemp)
4723  return pTemp;
4724  else
4725  {
4726  OSL_FAIL( "Attribute Null" );
4727  }
4728  }
4729  return &mxPoolHelper->GetDocPool()->GetDefaultItem( nWhich );
4730 }
4731 
4732 const SfxPoolItem* ScDocument::GetAttr( const ScAddress& rPos, sal_uInt16 nWhich ) const
4733 {
4734  return GetAttr(rPos.Col(), rPos.Row(), rPos.Tab(), nWhich);
4735 }
4736 
4737 const ScPatternAttr* ScDocument::GetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
4738 {
4739  if (TableExists(nTab))
4740  return maTabs[nTab]->GetPattern( nCol, nRow );
4741  return nullptr;
4742 }
4743 
4745 {
4746  if (TableExists(rPos.Tab()))
4747  return maTabs[rPos.Tab()]->GetPattern(rPos.Col(), rPos.Row());
4748 
4749  return nullptr;
4750 }
4751 
4752 const ScPatternAttr* ScDocument::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
4753 {
4754  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4755  return maTabs[nTab]->GetMostUsedPattern( nCol, nStartRow, nEndRow );
4756  return nullptr;
4757 }
4758 
4759 void ScDocument::ApplyAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem& rAttr )
4760 {
4761  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4762  maTabs[nTab]->ApplyAttr( nCol, nRow, rAttr );
4763 }
4764 
4765 void ScDocument::ApplyPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr )
4766 {
4767  if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
4768  maTabs[nTab]->ApplyPattern( nCol, nRow, rAttr );
4769 }
4770 
4771 void ScDocument::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow,
4772  SCCOL nEndCol, SCROW nEndRow,
4773  const ScMarkData& rMark,
4774  const ScPatternAttr& rAttr,
4775  ScEditDataArray* pDataArray,
4776  bool* const pIsChanged )
4777 {
4778  SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4779  for (const auto& rTab : rMark)
4780  {
4781  if (rTab >= nMax)
4782  break;
4783  if (maTabs[rTab])
4784  maTabs[rTab]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr, pDataArray, pIsChanged );
4785  }
4786 }
4787 
4788 void ScDocument::ApplyPatternAreaTab( SCCOL nStartCol, SCROW nStartRow,
4789  SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScPatternAttr& rAttr )
4790 {
4791  if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()))
4792  if (maTabs[nTab])
4793  maTabs[nTab]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
4794 }
4795 
4797  const ScMarkData& rMark, const ScPatternAttr& rPattern, SvNumFormatType nNewType )
4798 {
4799  SCTAB nMax = static_cast<SCTAB>(maTabs.size());
4800  for (const auto& rTab : rMark)
4801  {
4802  if (rTab >= nMax)
4803  break;
4804  if (maTabs[rTab])
4805  maTabs[rTab]->ApplyPatternIfNumberformatIncompatible( rRange, rPattern, nNewType );
4806  }
4807 }
4808 
4809 void ScDocument::AddCondFormatData( const ScRangeList& rRange, SCTAB nTab, sal_uInt32 nIndex )
4810 {
4811