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