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