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