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