LibreOffice Module sc (master)  1
documen4.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 <svl/zforlist.hxx>
21 #include <svl/zformat.hxx>
22 #include <formula/token.hxx>
23 #include <sal/log.hxx>
24 #include <unotools/configmgr.hxx>
25 
26 #include <document.hxx>
27 #include <table.hxx>
28 #include <globstr.hrc>
29 #include <scresid.hxx>
30 #include <subtotal.hxx>
31 #include <docoptio.hxx>
32 #include <markdata.hxx>
33 #include <validat.hxx>
34 #include <scitems.hxx>
35 #include <stlpool.hxx>
36 #include <poolhelp.hxx>
37 #include <detdata.hxx>
38 #include <patattr.hxx>
39 #include <chgtrack.hxx>
40 #include <progress.hxx>
41 #include <paramisc.hxx>
42 #include <compiler.hxx>
43 #include <externalrefmgr.hxx>
44 #include <attrib.hxx>
45 #include <formulacell.hxx>
46 #include <tokenarray.hxx>
47 #include <tokenstringcontext.hxx>
48 #include <memory>
49 
50 using namespace formula;
51 
69 bool ScDocument::Solver(SCCOL nFCol, SCROW nFRow, SCTAB nFTab,
70  SCCOL nVCol, SCROW nVRow, SCTAB nVTab,
71  const OUString& sValStr, double& nX)
72 {
73  bool bRet = false;
74  nX = 0.0;
75  if ( ValidColRow( nFCol, nFRow ) && ValidTab( nFTab ) &&
76  ValidColRow( nVCol, nVRow ) && ValidTab( nVTab ) &&
77  nFTab < static_cast<SCTAB>( maTabs.size() ) && maTabs[nFTab] &&
78  nVTab < static_cast<SCTAB>( maTabs.size() ) && maTabs[nVTab] )
79  {
80  CellType eFType, eVType;
81  GetCellType(nFCol, nFRow, nFTab, eFType);
82  GetCellType(nVCol, nVRow, nVTab, eVType);
83  // #i108005# convert target value to number using default format,
84  // as previously done in ScInterpreter::GetDouble
85  ScFormulaCell* pFormula = nullptr;
86  double fTargetVal = 0.0;
87  sal_uInt32 nFIndex = 0;
88  if ( eFType == CELLTYPE_FORMULA && eVType == CELLTYPE_VALUE &&
89  GetFormatTable()->IsNumberFormat( sValStr, nFIndex, fTargetVal ) )
90  {
91  ScAddress aFormulaAdr( nFCol, nFRow, nFTab );
92  pFormula = GetFormulaCell( aFormulaAdr );
93  }
94  if (pFormula)
95  {
96  bool bDoneIteration = false;
97  ScAddress aValueAdr( nVCol, nVRow, nVTab );
98  double* pVCell = GetValueCell( aValueAdr );
99 
100  ScRange aVRange( aValueAdr, aValueAdr ); // for SetDirty
101  // Original value to be restored later if necessary
102  double fSaveVal = *pVCell;
103 
104  const sal_uInt16 nMaxIter = 100;
105  const double fEps = 1E-10;
106  const double fDelta = 1E-6;
107 
108  double fBestX, fXPrev;
109  double fBestF, fFPrev;
110  fBestX = fXPrev = fSaveVal;
111 
112  pFormula->Interpret();
113  bool bError = ( pFormula->GetErrCode() != FormulaError::NONE );
114  // bError always corresponds with fF
115 
116  fFPrev = pFormula->GetValue() - fTargetVal;
117 
118  fBestF = fabs( fFPrev );
119  if ( fBestF < fDelta )
120  bDoneIteration = true;
121 
122  double fX = fXPrev + fEps;
123  double fF = fFPrev;
124  double fSlope;
125 
126  sal_uInt16 nIter = 0;
127 
128  bool bHorMoveError = false;
129  // Conform Regula Falsi Method
130  while ( !bDoneIteration && ( nIter++ < nMaxIter ) )
131  {
132  *pVCell = fX;
133  SetDirty( aVRange, false );
134  pFormula->Interpret();
135  bError = ( pFormula->GetErrCode() != FormulaError::NONE );
136  fF = pFormula->GetValue() - fTargetVal;
137 
138  if ( fF == fFPrev && !bError )
139  {
140  // HORIZONTAL SEARCH: Keep moving x in both directions until the f(x)
141  // becomes different from the previous f(x). This routine is needed
142  // when a given function is discrete, in which case the resulting slope
143  // may become zero which ultimately causes the goal seek operation
144  // to fail. #i28955#
145 
146  sal_uInt16 nHorIter = 0;
147  const double fHorStepAngle = 5.0;
148  const double fHorMaxAngle = 80.0;
149  int const nHorMaxIter = static_cast<int>( fHorMaxAngle / fHorStepAngle );
150  bool bDoneHorMove = false;
151 
152  while ( !bDoneHorMove && !bHorMoveError && nHorIter++ < nHorMaxIter )
153  {
154  double fHorAngle = fHorStepAngle * static_cast<double>( nHorIter );
155  double fHorTangent = ::rtl::math::tan(basegfx::deg2rad(fHorAngle));
156 
157  sal_uInt16 nIdx = 0;
158  while( nIdx++ < 2 && !bDoneHorMove )
159  {
160  double fHorX;
161  if ( nIdx == 1 )
162  fHorX = fX + fabs( fF ) * fHorTangent;
163  else
164  fHorX = fX - fabs( fF ) * fHorTangent;
165 
166  *pVCell = fHorX;
167  SetDirty( aVRange, false );
168  pFormula->Interpret();
169  bHorMoveError = ( pFormula->GetErrCode() != FormulaError::NONE );
170  if ( bHorMoveError )
171  break;
172 
173  fF = pFormula->GetValue() - fTargetVal;
174  if ( fF != fFPrev )
175  {
176  fX = fHorX;
177  bDoneHorMove = true;
178  }
179  }
180  }
181  if ( !bDoneHorMove )
182  bHorMoveError = true;
183  }
184 
185  if ( bError )
186  {
187  // move closer to last valid value (fXPrev), keep fXPrev & fFPrev
188  double fDiff = ( fXPrev - fX ) / 2;
189  if ( fabs( fDiff ) < fEps )
190  fDiff = ( fDiff < 0.0 ? - fEps : fEps );
191  fX += fDiff;
192  }
193  else if ( bHorMoveError )
194  break;
195  else if ( fabs(fF) < fDelta )
196  {
197  // converged to root
198  fBestX = fX;
199  bDoneIteration = true;
200  }
201  else
202  {
203  if ( fabs(fF) + fDelta < fBestF )
204  {
205  fBestX = fX;
206  fBestF = fabs( fF );
207  }
208 
209  if ( ( fXPrev - fX ) != 0 )
210  {
211  fSlope = ( fFPrev - fF ) / ( fXPrev - fX );
212  if ( fabs( fSlope ) < fEps )
213  fSlope = fSlope < 0.0 ? -fEps : fEps;
214  }
215  else
216  fSlope = fEps;
217 
218  fXPrev = fX;
219  fFPrev = fF;
220  fX = fX - ( fF / fSlope );
221  }
222  }
223 
224  // Try a nice rounded input value if possible.
225  const double fNiceDelta = ( bDoneIteration && fabs( fBestX ) >= 1e-3 ? 1e-3 : fDelta );
226  nX = ::rtl::math::approxFloor( ( fBestX / fNiceDelta ) + 0.5 ) * fNiceDelta;
227 
228  if ( bDoneIteration )
229  {
230  *pVCell = nX;
231  SetDirty( aVRange, false );
232  pFormula->Interpret();
233  if ( fabs( pFormula->GetValue() - fTargetVal ) > fabs( fF ) )
234  nX = fBestX;
235  bRet = true;
236  }
237  else if ( bError || bHorMoveError )
238  {
239  nX = fBestX;
240  }
241  *pVCell = fSaveVal;
242  SetDirty( aVRange, false );
243  pFormula->Interpret();
244  if ( !bDoneIteration )
245  {
246  SetError( nVCol, nVRow, nVTab, FormulaError::NotAvailable );
247  }
248  }
249  else
250  {
251  SetError( nVCol, nVRow, nVTab, FormulaError::NotAvailable );
252  }
253  }
254  return bRet;
255 }
256 
258  SCCOL nCol2, SCROW nRow2,
259  const ScMarkData& rMark,
260  const OUString& rFormula,
261  const ScTokenArray* pArr,
263 {
264  PutInOrder(nCol1, nCol2);
265  PutInOrder(nRow1, nRow2);
266  nCol2 = std::min<SCCOL>(nCol2, MaxCol());
267  nRow2 = std::min<SCROW>(nRow2, MaxRow());
268  if (!rMark.GetSelectCount())
269  {
270  SAL_WARN("sc", "ScDocument::InsertMatrixFormula: No table marked");
271  return;
272  }
273  if (utl::ConfigManager::IsFuzzing()) //just too slow
274  return;
275  assert( ValidColRow( nCol1, nRow1) && ValidColRow( nCol2, nRow2));
276 
277  SCTAB nTab1 = *rMark.begin();
278 
279  ScFormulaCell* pCell;
280  ScAddress aPos( nCol1, nRow1, nTab1 );
281  if (pArr)
282  pCell = new ScFormulaCell(*this, aPos, *pArr, eGram, ScMatrixMode::Formula);
283  else
284  pCell = new ScFormulaCell(*this, aPos, rFormula, eGram, ScMatrixMode::Formula);
285  pCell->SetMatColsRows( nCol2 - nCol1 + 1, nRow2 - nRow1 + 1 );
286  SCTAB nMax = static_cast<SCTAB>(maTabs.size());
287  for (const auto& rTab : rMark)
288  {
289  if (rTab >= nMax)
290  break;
291 
292  if (!maTabs[rTab])
293  continue;
294 
295  if (rTab == nTab1)
296  {
297  pCell = maTabs[rTab]->SetFormulaCell(nCol1, nRow1, pCell);
298  if (!pCell) //NULL if nCol1/nRow1 is invalid, which it can't be here
299  break;
300  }
301  else
302  maTabs[rTab]->SetFormulaCell(
303  nCol1, nRow1,
304  new ScFormulaCell(
305  *pCell, *this, ScAddress(nCol1, nRow1, rTab), ScCloneFlags::StartListening));
306  }
307 
308  ScAddress aBasePos(nCol1, nRow1, nTab1);
309  ScSingleRefData aRefData;
310  aRefData.InitFlags();
311  aRefData.SetColRel( true );
312  aRefData.SetRowRel( true );
313  aRefData.SetTabRel( true );
314  aRefData.SetAddress(GetSheetLimits(), aBasePos, aBasePos);
315 
316  ScTokenArray aArr(*this); // consists only of one single reference token.
318 
319  for (const SCTAB& nTab : rMark)
320  {
321  if (nTab >= nMax)
322  break;
323 
324  ScTable* pTab = FetchTable(nTab);
325  if (!pTab)
326  continue;
327 
328  if (nTab != nTab1)
329  {
330  aRefData.SetRelTab(nTab - aBasePos.Tab());
331  *t->GetSingleRef() = aRefData;
332  }
333 
334  for (SCCOL nCol : GetColumnsRange(nTab1, nCol1, nCol2))
335  {
336  for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
337  {
338  if (nCol == nCol1 && nRow == nRow1)
339  // Skip the base position.
340  continue;
341 
342  // Token array must be cloned so that each formula cell receives its own copy.
343  aPos = ScAddress(nCol, nRow, nTab);
344  // Reference in each cell must point to the origin cell relative to the current cell.
345  aRefData.SetAddress(GetSheetLimits(), aBasePos, aPos);
346  *t->GetSingleRef() = aRefData;
347  std::unique_ptr<ScTokenArray> pTokArr(aArr.Clone());
348  pCell = new ScFormulaCell(*this, aPos, *pTokArr, eGram, ScMatrixMode::Reference);
349  pTab->SetFormulaCell(nCol, nRow, pCell);
350  }
351  }
352  }
353 }
354 
355 void ScDocument::InsertTableOp(const ScTabOpParam& rParam, // multiple (repeated?) operation
356  SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
357  const ScMarkData& rMark)
358 {
359  PutInOrder(nCol1, nCol2);
360  PutInOrder(nRow1, nRow2);
361  assert( ValidColRow( nCol1, nRow1) && ValidColRow( nCol2, nRow2));
362  SCTAB i, nTab1;
363  SCCOL j;
364  SCROW k;
365  i = 0;
366  bool bStop = false;
367  SCTAB nMax = static_cast<SCTAB>(maTabs.size());
368  for (const auto& rTab : rMark)
369  {
370  if (rTab >= nMax)
371  break;
372 
373  if (maTabs[rTab])
374  {
375  i = rTab;
376  bStop = true;
377  break;
378  }
379  }
380  nTab1 = i;
381  if (!bStop)
382  {
383  OSL_FAIL("ScDocument::InsertTableOp: No table marked");
384  return;
385  }
386 
387  ScRefAddress aRef;
388  OUStringBuffer aForString;
389  aForString.append('=');
390  aForString.append(ScCompiler::GetNativeSymbol(ocTableOp));
391  aForString.append(ScCompiler::GetNativeSymbol( ocOpen));
392 
393  const OUString& sSep = ScCompiler::GetNativeSymbol( ocSep);
394  if (rParam.meMode == ScTabOpParam::Column) // column only
395  {
396  aRef.Set( rParam.aRefFormulaCell.GetAddress(), true, false, false );
397  aForString.append(aRef.GetRefString(*this, nTab1));
398  aForString.append(sSep);
399  aForString.append(rParam.aRefColCell.GetRefString(*this, nTab1));
400  aForString.append(sSep);
401  aRef.Set( nCol1, nRow1, nTab1, false, true, true );
402  aForString.append(aRef.GetRefString(*this, nTab1));
403  nCol1++;
404  nCol2 = std::min( nCol2, static_cast<SCCOL>(rParam.aRefFormulaEnd.Col() -
405  rParam.aRefFormulaCell.Col() + nCol1 + 1));
406  }
407  else if (rParam.meMode == ScTabOpParam::Row) // row only
408  {
409  aRef.Set( rParam.aRefFormulaCell.GetAddress(), false, true, false );
410  aForString.append(aRef.GetRefString(*this, nTab1));
411  aForString.append(sSep);
412  aForString.append(rParam.aRefRowCell.GetRefString(*this, nTab1));
413  aForString.append(sSep);
414  aRef.Set( nCol1, nRow1, nTab1, true, false, true );
415  aForString.append(aRef.GetRefString(*this, nTab1));
416  nRow1++;
417  nRow2 = std::min( nRow2, static_cast<SCROW>(rParam.aRefFormulaEnd.Row() -
418  rParam.aRefFormulaCell.Row() + nRow1 + 1));
419  }
420  else // both
421  {
422  aForString.append(rParam.aRefFormulaCell.GetRefString(*this, nTab1));
423  aForString.append(sSep);
424  aForString.append(rParam.aRefColCell.GetRefString(*this, nTab1));
425  aForString.append(sSep);
426  aRef.Set( nCol1, nRow1 + 1, nTab1, false, true, true );
427  aForString.append(aRef.GetRefString(*this, nTab1));
428  aForString.append(sSep);
429  aForString.append(rParam.aRefRowCell.GetRefString(*this, nTab1));
430  aForString.append(sSep);
431  aRef.Set( nCol1 + 1, nRow1, nTab1, true, false, true );
432  aForString.append(aRef.GetRefString(*this, nTab1));
433  nCol1++; nRow1++;
434  }
435  aForString.append(ScCompiler::GetNativeSymbol( ocClose ));
436 
437  ScFormulaCell aRefCell( *this, ScAddress( nCol1, nRow1, nTab1 ), aForString.makeStringAndClear(),
439  for( j = nCol1; j <= nCol2; j++ )
440  for( k = nRow1; k <= nRow2; k++ )
441  for (i = 0; i < static_cast<SCTAB>(maTabs.size()); i++)
442  {
443  for (const auto& rTab : rMark)
444  {
445  if (rTab >= nMax)
446  break;
447  if( maTabs[rTab] )
448  maTabs[rTab]->SetFormulaCell(
449  j, k, new ScFormulaCell(aRefCell, *this, ScAddress(j, k, rTab), ScCloneFlags::StartListening));
450  }
451  }
452 }
453 
454 namespace {
455 
456 bool setCacheTableReferenced(const ScDocument& rDoc, formula::FormulaToken& rToken, ScExternalRefManager& rRefMgr, const ScAddress& rPos)
457 {
458  switch (rToken.GetType())
459  {
460  case svExternalSingleRef:
461  return rRefMgr.setCacheTableReferenced(
462  rToken.GetIndex(), rToken.GetString().getString(), 1);
463  case svExternalDoubleRef:
464  {
465  const ScComplexRefData& rRef = *rToken.GetDoubleRef();
466  ScRange aAbs = rRef.toAbs(rDoc, rPos);
467  size_t nSheets = aAbs.aEnd.Tab() - aAbs.aStart.Tab() + 1;
468  return rRefMgr.setCacheTableReferenced(
469  rToken.GetIndex(), rToken.GetString().getString(), nSheets);
470  }
471  case svExternalName:
472  /* TODO: external names aren't supported yet, but would
473  * have to be marked as well, if so. Mechanism would be
474  * different. */
475  OSL_FAIL("ScDocument::MarkUsedExternalReferences: implement the svExternalName case!");
476  break;
477  default:
478  break;
479  }
480  return false;
481 }
482 
483 }
484 
486 {
487  if (!rArr.GetLen())
488  return false;
489 
490  ScExternalRefManager* pRefMgr = nullptr;
492  bool bAllMarked = false;
493  while (!bAllMarked)
494  {
496  if (!t)
497  break;
498  if (t->IsExternalRef())
499  {
500  if (!pRefMgr)
501  pRefMgr = GetExternalRefManager();
502 
503  bAllMarked = setCacheTableReferenced(*this, *t, *pRefMgr, rPos);
504  }
505  else if (t->GetType() == svIndex)
506  {
507  // this is a named range. Check if the range contains an external
508  // reference.
509  ScRangeData* pRangeData = GetRangeName()->findByIndex(t->GetIndex());
510  if (!pRangeData)
511  continue;
512 
513  ScTokenArray* pArray = pRangeData->GetCode();
514  formula::FormulaTokenArrayPlainIterator aArrayIter(*pArray);
515  for (t = aArrayIter.First(); t; t = aArrayIter.Next())
516  {
517  if (!t->IsExternalRef())
518  continue;
519 
520  if (!pRefMgr)
521  pRefMgr = GetExternalRefManager();
522 
523  bAllMarked = setCacheTableReferenced(*this, *t, *pRefMgr, rPos);
524  }
525  }
526  }
527  return bAllMarked;
528 }
529 
531  bool bInSel, const ScMarkData& rMark) const
532 {
533  if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
534  return maTabs[nTab]->GetNextSpellingCell( nCol, nRow, bInSel, rMark );
535  else
536  return false;
537 }
538 
540  const ScMarkData& rMark )
541 {
542  if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
543  return maTabs[nTab]->GetNextMarkedCell( rCol, rRow, rMark );
544  else
545  return false;
546 }
547 
548 void ScDocument::ReplaceStyle(const SvxSearchItem& rSearchItem,
549  SCCOL nCol, SCROW nRow, SCTAB nTab,
550  const ScMarkData& rMark)
551 {
552  if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
553  maTabs[nTab]->ReplaceStyle(rSearchItem, nCol, nRow, rMark, true/*bIsUndoP*/);
554 }
555 
557 {
558  sc::CompileFormulaContext aCxt(*this);
559  for (auto& rxTab : maTabs)
560  {
561  if (rxTab)
562  rxTab->CompileDBFormula(aCxt);
563  }
564 }
565 
567 {
568  sc::CompileFormulaContext aCxt(*this);
569  for (auto& rxTab : maTabs)
570  {
571  if (rxTab)
572  rxTab->CompileColRowNameFormula(aCxt);
573  }
574 }
575 
577 {
578  for (auto& rxTab : maTabs)
579  {
580  if (!rxTab)
581  break;
582  rxTab->InvalidateTableArea();
583  if ( rxTab->IsScenario() )
584  rxTab->InvalidateScenarioRanges();
585  }
586 }
587 
589  SCROW nRowStart, SCROW nRowEnd, rtl_TextEncoding eCharSet ) const
590 {
591  if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
592  return maTabs[nTab]->GetMaxStringLen( nCol, nRowStart, nRowEnd, eCharSet );
593  else
594  return 0;
595 }
596 
597 sal_Int32 ScDocument::GetMaxNumberStringLen( sal_uInt16& nPrecision, SCTAB nTab,
598  SCCOL nCol,
599  SCROW nRowStart, SCROW nRowEnd ) const
600 {
601  if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
602  return maTabs[nTab]->GetMaxNumberStringLen( nPrecision, nCol,
603  nRowStart, nRowEnd );
604  else
605  return 0;
606 }
607 
609  const ScAddress& rCursor, const ScMarkData& rMark,
610  double& rResult )
611 {
612  ScFunctionData aData(eFunc);
613 
614  ScMarkData aMark(rMark);
615  aMark.MarkToMulti();
616  if (!aMark.IsMultiMarked() && !aMark.IsCellMarked(rCursor.Col(), rCursor.Row()))
617  aMark.SetMarkArea(rCursor);
618 
619  SCTAB nMax = static_cast<SCTAB>(maTabs.size());
620  ScMarkData::const_iterator itr = aMark.begin(), itrEnd = aMark.end();
621 
622  for (; itr != itrEnd && *itr < nMax && !aData.getError(); ++itr)
623  if (maTabs[*itr])
624  maTabs[*itr]->UpdateSelectionFunction(aData, aMark);
625 
626  rResult = aData.getResult();
627  if (aData.getError())
628  rResult = 0.0;
629 
630  return !aData.getError();
631 }
632 
633 double ScDocument::RoundValueAsShown( double fVal, sal_uInt32 nFormat, const ScInterpreterContext* pContext ) const
634 {
635  const SvNumberFormatter* pFormatter = pContext ? pContext->GetFormatTable() : GetFormatTable();
636  const SvNumberformat* pFormat = pFormatter->GetEntry( nFormat );
637  if (!pFormat)
638  return fVal;
639  SvNumFormatType nType = pFormat->GetMaskedType();
640  if (nType != SvNumFormatType::DATE && nType != SvNumFormatType::TIME && nType != SvNumFormatType::DATETIME )
641  {
642  short nPrecision;
643  if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
644  {
645  sal_uInt16 nIdx = pFormat->GetSubformatIndex( fVal );
646  nPrecision = static_cast<short>(pFormat->GetFormatPrecision( nIdx ));
647  switch ( nType )
648  {
649  case SvNumFormatType::PERCENT: // 0.41% == 0.0041
650  nPrecision += 2;
651  break;
652  case SvNumFormatType::SCIENTIFIC: // 1.23e-3 == 0.00123
653  {
654  short nExp = 0;
655  if ( fVal > 0.0 )
656  nExp = static_cast<short>(floor( log10( fVal ) ));
657  else if ( fVal < 0.0 )
658  nExp = static_cast<short>(floor( log10( -fVal ) ));
659  nPrecision -= nExp;
660  short nInteger = static_cast<short>(pFormat->GetFormatIntegerDigits( nIdx ));
661  if ( nInteger > 1 ) // Engineering notation
662  {
663  short nIncrement = nExp % nInteger;
664  if ( nIncrement != 0 )
665  {
666  nPrecision += nIncrement;
667  if (nExp < 0 )
668  nPrecision += nInteger;
669  }
670  }
671  break;
672  }
673  case SvNumFormatType::FRACTION: // get value of fraction representation
674  {
675  return pFormat->GetRoundFractionValue( fVal );
676  }
677  case SvNumFormatType::NUMBER:
678  case SvNumFormatType::CURRENCY:
679  { // tdf#106253 Thousands divisors for format "0,"
680  nPrecision -= pFormat->GetThousandDivisorPrecision( nIdx );
681  break;
682  }
683  default: break;
684  }
685  }
686  else
687  {
688  nPrecision = static_cast<short>(GetDocOptions().GetStdPrecision());
689  // #i115512# no rounding for automatic decimals
690  if (nPrecision == static_cast<short>(SvNumberFormatter::UNLIMITED_PRECISION))
691  return fVal;
692  }
693  double fRound = ::rtl::math::round( fVal, nPrecision );
694  if ( ::rtl::math::approxEqual( fVal, fRound ) )
695  return fVal; // rounding might introduce some error
696  else
697  return fRound;
698  }
699  else
700  return fVal;
701 }
702 
703 // conditional formats and validation ranges
704 
705 sal_uLong ScDocument::AddCondFormat( std::unique_ptr<ScConditionalFormat> pNew, SCTAB nTab )
706 {
707  if(!pNew)
708  return 0;
709 
710  if(ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
711  return maTabs[nTab]->AddCondFormat( std::move(pNew) );
712 
713  return 0;
714 }
715 
717 {
718  if (rNew.IsEmpty())
719  return 0; // empty is always 0
720 
721  if (!pValidationList)
722  {
724  pValidationList.reset(new ScValidationDataList);
725  }
726 
727  sal_uLong nMax = 0;
728  for( const auto& rxData : *pValidationList )
729  {
730  const ScValidationData* pData = rxData.get();
731  sal_uLong nKey = pData->GetKey();
732  if ( pData->EqualEntries( rNew ) )
733  return nKey;
734  if ( nKey > nMax )
735  nMax = nKey;
736  }
737 
738  // might be called from ScPatternAttr::PutInPool; thus clone (real copy)
739 
740  sal_uLong nNewKey = nMax + 1;
741  std::unique_ptr<ScValidationData> pInsert(rNew.Clone(this));
742  pInsert->SetKey( nNewKey );
744  pValidationList->InsertNew( std::move(pInsert) );
745  return nNewKey;
746 }
747 
749  SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich ) const
750 {
751  const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab );
752  if ( pPattern )
753  {
754  const SfxItemSet& rSet = pPattern->GetItemSet();
755  const SfxPoolItem* pItem;
756  if ( rSet.GetItemState( ATTR_CONDITIONAL, true, &pItem ) == SfxItemState::SET )
757  {
758  const ScCondFormatIndexes& rIndex = pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData();
759  ScConditionalFormatList* pCondFormList = GetCondFormList( nTab );
760  if (!rIndex.empty() && pCondFormList)
761  {
762  for(const auto& rItem : rIndex)
763  {
764  const ScConditionalFormat* pForm = pCondFormList->GetFormat( rItem );
765  if ( pForm )
766  {
767  ScAddress aPos(nCol, nRow, nTab);
768  ScRefCellValue aCell(const_cast<ScDocument&>(*this), aPos);
769  const OUString& aStyle = pForm->GetCellStyle(aCell, aPos);
770  if (!aStyle.isEmpty())
771  {
772  SfxStyleSheetBase* pStyleSheet = mxPoolHelper->GetStylePool()->Find(
773  aStyle, SfxStyleFamily::Para );
774  if ( pStyleSheet && pStyleSheet->GetItemSet().GetItemState(
775  nWhich, true, &pItem ) == SfxItemState::SET )
776  return pItem;
777  }
778  }
779  }
780  }
781  }
782  return &rSet.Get( nWhich );
783  }
784  OSL_FAIL("no pattern");
785  return nullptr;
786 }
787 
788 const SfxItemSet* ScDocument::GetCondResult( SCCOL nCol, SCROW nRow, SCTAB nTab, ScRefCellValue* pCell ) const
789 {
790  ScConditionalFormatList* pFormatList = GetCondFormList(nTab);
791  if (!pFormatList)
792  return nullptr;
793 
794  ScAddress aPos(nCol, nRow, nTab);
795  ScRefCellValue aCell;
796  if( pCell == nullptr )
797  {
798  aCell.assign(const_cast<ScDocument&>(*this), aPos);
799  pCell = &aCell;
800  }
801  const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab );
802  const ScCondFormatIndexes& rIndex =
803  pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData();
804 
805  return GetCondResult(*pCell, aPos, *pFormatList, rIndex);
806 }
807 
809  ScRefCellValue& rCell, const ScAddress& rPos, const ScConditionalFormatList& rList,
810  const ScCondFormatIndexes& rIndex ) const
811 {
812  for (const auto& rItem : rIndex)
813  {
814  const ScConditionalFormat* pForm = rList.GetFormat(rItem);
815  if (!pForm)
816  continue;
817 
818  const OUString& aStyle = pForm->GetCellStyle(rCell, rPos);
819  if (!aStyle.isEmpty())
820  {
821  SfxStyleSheetBase* pStyleSheet =
822  mxPoolHelper->GetStylePool()->Find(aStyle, SfxStyleFamily::Para);
823 
824  if (pStyleSheet)
825  return &pStyleSheet->GetItemSet();
826 
827  // if style is not there, treat like no condition
828  }
829  }
830 
831  return nullptr;
832 }
833 
835  SCCOL nCol, SCROW nRow, SCTAB nTab ) const
836 {
837  sal_uInt32 nIndex = 0;
838  const ScCondFormatIndexes& rCondFormats = GetAttr(nCol, nRow, nTab, ATTR_CONDITIONAL)->GetCondFormatData();
839 
840  if(!rCondFormats.empty())
841  nIndex = rCondFormats[0];
842 
843  if (nIndex)
844  {
845  ScConditionalFormatList* pCondFormList = GetCondFormList(nTab);
846  if (pCondFormList)
847  return pCondFormList->GetFormat( nIndex );
848  else
849  {
850  OSL_FAIL("pCondFormList is 0");
851  }
852  }
853 
854  return nullptr;
855 }
856 
858 {
859  if(ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
860  return maTabs[nTab]->GetCondFormList();
861 
862  return nullptr;
863 }
864 
866 {
867  if(ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
868  maTabs[nTab]->SetCondFormList(pList);
869 }
870 
872 {
873  if ( pValidationList )
874  return pValidationList->GetData( nIndex );
875  else
876  return nullptr;
877 }
878 
880 {
881  if(ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
882  maTabs[nTab]->DeleteConditionalFormat(nOldIndex);
883 }
884 
886 {
887  return pDetOpList && pDetOpList->Count();
888 }
889 
891 {
892  if (!pDetOpList)
893  pDetOpList.reset(new ScDetOpList);
894 
895  pDetOpList->Append( new ScDetOpData( rData ) );
896 }
897 
899 {
900  pDetOpList.reset(); // deletes also the entries
901 }
902 
903 void ScDocument::SetDetOpList(std::unique_ptr<ScDetOpList> pNew)
904 {
905  pDetOpList = std::move(pNew);
906 }
907 
908 // Comparison of Documents
909 
910 // Pfriemel-Factors
911 #define SC_DOCCOMP_MAXDIFF 256
912 #define SC_DOCCOMP_MINGOOD 128
913 #define SC_DOCCOMP_COLUMNS 10
914 #define SC_DOCCOMP_ROWS 100
915 
916 sal_uInt16 ScDocument::RowDifferences( SCROW nThisRow, SCTAB nThisTab,
917  ScDocument& rOtherDoc, SCROW nOtherRow, SCTAB nOtherTab,
918  SCCOL nMaxCol, const SCCOLROW* pOtherCols )
919 {
920  sal_uLong nDif = 0;
921  sal_uLong nUsed = 0;
922  for (SCCOL nThisCol=0; nThisCol<=nMaxCol; nThisCol++)
923  {
924  SCCOL nOtherCol;
925  if ( pOtherCols )
926  nOtherCol = static_cast<SCCOL>(pOtherCols[nThisCol]);
927  else
928  nOtherCol = nThisCol;
929 
930  if (ValidCol(nOtherCol)) // only compare columns that are common to both docs
931  {
932  ScRefCellValue aThisCell(*this, ScAddress(nThisCol, nThisRow, nThisTab));
933  ScRefCellValue aOtherCell(rOtherDoc, ScAddress(nOtherCol, nOtherRow, nOtherTab));
934  if (!aThisCell.equalsWithoutFormat(aOtherCell))
935  {
936  if (!aThisCell.isEmpty() && !aOtherCell.isEmpty())
937  nDif += 3;
938  else
939  nDif += 4; // content <-> empty counts more
940  }
941 
942  if (!aThisCell.isEmpty() || !aOtherCell.isEmpty())
943  ++nUsed;
944  }
945  }
946 
947  if (nUsed > 0)
948  return static_cast<sal_uInt16>((nDif*64)/nUsed); // max.256 (SC_DOCCOMP_MAXDIFF)
949 
950  OSL_ENSURE(!nDif,"Diff without Used");
951  return 0;
952 }
953 
954 sal_uInt16 ScDocument::ColDifferences( SCCOL nThisCol, SCTAB nThisTab,
955  ScDocument& rOtherDoc, SCCOL nOtherCol, SCTAB nOtherTab,
956  SCROW nMaxRow, const SCCOLROW* pOtherRows )
957 {
958 
959  //TODO: optimize e.g. with iterator?
960 
961  sal_uLong nDif = 0;
962  sal_uLong nUsed = 0;
963  for (SCROW nThisRow=0; nThisRow<=nMaxRow; nThisRow++)
964  {
965  SCROW nOtherRow;
966  if ( pOtherRows )
967  nOtherRow = pOtherRows[nThisRow];
968  else
969  nOtherRow = nThisRow;
970 
971  if (ValidRow(nOtherRow)) // only compare rows that are common to both docs
972  {
973  ScRefCellValue aThisCell(*this, ScAddress(nThisCol, nThisRow, nThisTab));
974  ScRefCellValue aOtherCell(rOtherDoc, ScAddress(nOtherCol, nOtherRow, nOtherTab));
975  if (!aThisCell.equalsWithoutFormat(aOtherCell))
976  {
977  if (!aThisCell.isEmpty() && !aOtherCell.isEmpty())
978  nDif += 3;
979  else
980  nDif += 4; // content <-> empty counts more
981  }
982 
983  if (!aThisCell.isEmpty() || !aOtherCell.isEmpty())
984  ++nUsed;
985  }
986  }
987 
988  if (nUsed > 0)
989  return static_cast<sal_uInt16>((nDif*64)/nUsed); // max.256
990 
991  OSL_ENSURE(!nDif,"Diff without Used");
992  return 0;
993 }
994 
995 void ScDocument::FindOrder( SCCOLROW* pOtherRows, SCCOLROW nThisEndRow, SCCOLROW nOtherEndRow,
996  bool bColumns, ScDocument& rOtherDoc, SCTAB nThisTab, SCTAB nOtherTab,
997  SCCOLROW nEndCol, const SCCOLROW* pTranslate, ScProgress* pProgress, sal_uLong nProAdd )
998 {
999  // bColumns=true: rows are columns and vice versa
1000 
1001  SCCOLROW nMaxCont; // continue by how much
1002  SCCOLROW nMinGood; // what is a hit (incl.)
1003  if ( bColumns )
1004  {
1005  nMaxCont = SC_DOCCOMP_COLUMNS; // 10 columns
1006  nMinGood = SC_DOCCOMP_MINGOOD;
1007 
1008  //TODO: additional pass with nMinGood = 0 ????
1009 
1010  }
1011  else
1012  {
1013  nMaxCont = SC_DOCCOMP_ROWS; // 100 rows
1014  nMinGood = SC_DOCCOMP_MINGOOD;
1015  }
1016  bool bUseTotal = bColumns && !pTranslate; // only for the 1st pass
1017 
1018  SCCOLROW nOtherRow = 0;
1019  sal_uInt16 nComp;
1020  SCCOLROW nThisRow;
1021  bool bTotal = false; // hold for several nThisRow
1022  SCCOLROW nUnknown = 0;
1023  for (nThisRow = 0; nThisRow <= nThisEndRow; nThisRow++)
1024  {
1025  SCCOLROW nTempOther = nOtherRow;
1026  bool bFound = false;
1027  sal_uInt16 nBest = SC_DOCCOMP_MAXDIFF;
1028  SCCOLROW nMax = std::min( nOtherEndRow, static_cast<SCCOLROW>(( nTempOther + nMaxCont + nUnknown )) );
1029  for (SCCOLROW i=nTempOther; i<=nMax && nBest>0; i++) // stop at 0
1030  {
1031  if (bColumns)
1032  nComp = ColDifferences( static_cast<SCCOL>(nThisRow), nThisTab, rOtherDoc, static_cast<SCCOL>(i), nOtherTab, nEndCol, pTranslate );
1033  else
1034  nComp = RowDifferences( nThisRow, nThisTab, rOtherDoc, i, nOtherTab, static_cast<SCCOL>(nEndCol), pTranslate );
1035  if ( nComp < nBest && ( nComp <= nMinGood || bTotal ) )
1036  {
1037  nTempOther = i;
1038  nBest = nComp;
1039  bFound = true;
1040  }
1041  if ( nComp < SC_DOCCOMP_MAXDIFF || bFound )
1042  bTotal = false;
1043  else if ( i == nTempOther && bUseTotal )
1044  bTotal = true; // only at the very top
1045  }
1046  if ( bFound )
1047  {
1048  pOtherRows[nThisRow] = nTempOther;
1049  nOtherRow = nTempOther + 1;
1050  nUnknown = 0;
1051  }
1052  else
1053  {
1054  pOtherRows[nThisRow] = SCROW_MAX;
1055  ++nUnknown;
1056  }
1057 
1058  if (pProgress)
1059  pProgress->SetStateOnPercent(nProAdd+static_cast<sal_uLong>(nThisRow));
1060  }
1061 
1062  // fill in blocks that don't match
1063 
1064  SCROW nFillStart = 0;
1065  SCROW nFillPos = 0;
1066  bool bInFill = false;
1067  for (nThisRow = 0; nThisRow <= nThisEndRow+1; nThisRow++)
1068  {
1069  SCROW nThisOther = ( nThisRow <= nThisEndRow ) ? pOtherRows[nThisRow] : (nOtherEndRow+1);
1070  if ( ValidRow(nThisOther) )
1071  {
1072  if ( bInFill )
1073  {
1074  if ( nThisOther > nFillStart ) // is there something to distribute?
1075  {
1076  SCROW nDiff1 = nThisOther - nFillStart;
1077  SCROW nDiff2 = nThisRow - nFillPos;
1078  SCROW nMinDiff = std::min(nDiff1, nDiff2);
1079  for (SCROW i=0; i<nMinDiff; i++)
1080  pOtherRows[nFillPos+i] = nFillStart+i;
1081  }
1082 
1083  bInFill = false;
1084  }
1085  nFillStart = nThisOther + 1;
1086  nFillPos = nThisRow + 1;
1087  }
1088  else
1089  bInFill = true;
1090  }
1091 }
1092 
1094 {
1095  if (!pChangeTrack)
1096  return;
1097 
1098  SCTAB nThisCount = GetTableCount();
1099  SCTAB nOtherCount = rOtherDoc.GetTableCount();
1100  std::unique_ptr<SCTAB[]> pOtherTabs(new SCTAB[nThisCount]);
1101  SCTAB nThisTab;
1102 
1103  // compare tables with identical names
1104  OUString aThisName;
1105  OUString aOtherName;
1106  for (nThisTab=0; nThisTab<nThisCount; nThisTab++)
1107  {
1108  SCTAB nOtherTab = SCTAB_MAX;
1109  if (!IsScenario(nThisTab)) // skip scenarios
1110  {
1111  GetName( nThisTab, aThisName );
1112  for (SCTAB nTemp=0; nTemp<nOtherCount && nOtherTab>MAXTAB; nTemp++)
1113  if (!rOtherDoc.IsScenario(nTemp))
1114  {
1115  rOtherDoc.GetName( nTemp, aOtherName );
1116  if ( aThisName == aOtherName )
1117  nOtherTab = nTemp;
1118  }
1119  }
1120  pOtherTabs[nThisTab] = nOtherTab;
1121  }
1122  // fill in, so that un-named tables don't get lost
1123  SCTAB nFillStart = 0;
1124  SCTAB nFillPos = 0;
1125  bool bInFill = false;
1126  for (nThisTab = 0; nThisTab <= nThisCount; nThisTab++)
1127  {
1128  SCTAB nThisOther = ( nThisTab < nThisCount ) ? pOtherTabs[nThisTab] : nOtherCount;
1129  if ( ValidTab(nThisOther) )
1130  {
1131  if ( bInFill )
1132  {
1133  if ( nThisOther > nFillStart ) // is there something to distribute?
1134  {
1135  SCTAB nDiff1 = nThisOther - nFillStart;
1136  SCTAB nDiff2 = nThisTab - nFillPos;
1137  SCTAB nMinDiff = std::min(nDiff1, nDiff2);
1138  for (SCTAB i=0; i<nMinDiff; i++)
1139  if ( !IsScenario(nFillPos+i) && !rOtherDoc.IsScenario(nFillStart+i) )
1140  pOtherTabs[nFillPos+i] = nFillStart+i;
1141  }
1142 
1143  bInFill = false;
1144  }
1145  nFillStart = nThisOther + 1;
1146  nFillPos = nThisTab + 1;
1147  }
1148  else
1149  bInFill = true;
1150  }
1151 
1152  // compare tables in the original order
1153 
1154  for (nThisTab=0; nThisTab<nThisCount; nThisTab++)
1155  {
1156  SCTAB nOtherTab = pOtherTabs[nThisTab];
1157  if ( ValidTab(nOtherTab) )
1158  {
1159  SCCOL nThisEndCol = 0;
1160  SCROW nThisEndRow = 0;
1161  SCCOL nOtherEndCol = 0;
1162  SCROW nOtherEndRow = 0;
1163  GetCellArea( nThisTab, nThisEndCol, nThisEndRow );
1164  rOtherDoc.GetCellArea( nOtherTab, nOtherEndCol, nOtherEndRow );
1165  SCCOL nEndCol = std::max(nThisEndCol, nOtherEndCol);
1166  SCROW nEndRow = std::max(nThisEndRow, nOtherEndRow);
1167  SCCOL nThisCol;
1168  SCROW nThisRow;
1169  sal_uLong n1,n2; // for AppendDeleteRange
1170 
1171  //TODO: one Progress over all tables ???
1172 
1173  OUString aTabName;
1174  GetName( nThisTab, aTabName );
1175  OUString aTemplate = ScResId(STR_PROGRESS_COMPARING);
1176  sal_Int32 nIndex = 0;
1177  OUString aProText = aTemplate.getToken( 0, '#', nIndex ) +
1178  aTabName +
1179  aTemplate.getToken( 0, '#', nIndex );
1180  ScProgress aProgress( GetDocumentShell(), aProText, 3*nThisEndRow, true ); // 2x FindOrder, 1x here
1181  tools::Long nProgressStart = 2*nThisEndRow; // start for here
1182 
1183  std::unique_ptr<SCCOLROW[]> pTempRows(new SCCOLROW[nThisEndRow+1]);
1184  std::unique_ptr<SCCOLROW[]> pOtherRows(new SCCOLROW[nThisEndRow+1]);
1185  std::unique_ptr<SCCOLROW[]> pOtherCols(new SCCOLROW[nThisEndCol+1]);
1186 
1187  // find inserted/deleted columns/rows:
1188  // Two attempts:
1189  // 1) compare original rows (pTempRows)
1190  // 2) compare original columns (pOtherCols)
1191  // with this column order compare rows (pOtherRows)
1192 
1193  //TODO: compare columns twice with different nMinGood ???
1194 
1195  // 1
1196  FindOrder( pTempRows.get(), nThisEndRow, nOtherEndRow, false,
1197  rOtherDoc, nThisTab, nOtherTab, nEndCol, nullptr, &aProgress, 0 );
1198  // 2
1199  FindOrder( pOtherCols.get(), nThisEndCol, nOtherEndCol, true,
1200  rOtherDoc, nThisTab, nOtherTab, nEndRow, nullptr, nullptr, 0 );
1201  FindOrder( pOtherRows.get(), nThisEndRow, nOtherEndRow, false,
1202  rOtherDoc, nThisTab, nOtherTab, nThisEndCol,
1203  pOtherCols.get(), &aProgress, nThisEndRow );
1204 
1205  sal_uLong nMatch1 = 0; // pTempRows, no columns
1206  for (nThisRow = 0; nThisRow<=nThisEndRow; nThisRow++)
1207  if (ValidRow(pTempRows[nThisRow]))
1208  nMatch1 += SC_DOCCOMP_MAXDIFF -
1209  RowDifferences( nThisRow, nThisTab, rOtherDoc, pTempRows[nThisRow],
1210  nOtherTab, nEndCol, nullptr );
1211 
1212  sal_uLong nMatch2 = 0; // pOtherRows, pOtherCols
1213  for (nThisRow = 0; nThisRow<=nThisEndRow; nThisRow++)
1214  if (ValidRow(pOtherRows[nThisRow]))
1215  nMatch2 += SC_DOCCOMP_MAXDIFF -
1216  RowDifferences( nThisRow, nThisTab, rOtherDoc, pOtherRows[nThisRow],
1217  nOtherTab, nThisEndCol, pOtherCols.get() );
1218 
1219  if ( nMatch1 >= nMatch2 ) // without columns ?
1220  {
1221  // reset columns
1222  for (nThisCol = 0; nThisCol<=nThisEndCol; nThisCol++)
1223  pOtherCols[nThisCol] = nThisCol;
1224 
1225  // swap row-arrays (they get both deleted anyway)
1226  pTempRows.swap(pOtherRows);
1227  }
1228  else
1229  {
1230  // remains for pOtherCols, pOtherRows
1231  }
1232 
1233  // Generate Change-Actions
1234  // 1) columns from the right
1235  // 2) rows from below
1236  // 3) single cells in normal order
1237 
1238  // Actions for inserted/deleted columns
1239 
1240  SCCOL nLastOtherCol = static_cast<SCCOL>(nOtherEndCol + 1);
1241  // nThisEndCol ... 0
1242  for ( nThisCol = nThisEndCol+1; nThisCol > 0; )
1243  {
1244  --nThisCol;
1245  SCCOL nOtherCol = static_cast<SCCOL>(pOtherCols[nThisCol]);
1246  if ( ValidCol(nOtherCol) && nOtherCol+1 < nLastOtherCol )
1247  {
1248  // gap -> deleted
1249  ScRange aDelRange( nOtherCol+1, 0, nOtherTab,
1250  nLastOtherCol-1, MaxRow(), nOtherTab );
1251  pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
1252  }
1253  if ( nOtherCol > MaxCol() ) // inserted
1254  {
1255  // combine
1256  if ( nThisCol == nThisEndCol || ValidCol(static_cast<SCCOL>(pOtherCols[nThisCol+1])) )
1257  {
1258  SCCOL nFirstNew = nThisCol;
1259  while ( nFirstNew > 0 && pOtherCols[nFirstNew-1] > MaxCol() )
1260  --nFirstNew;
1261  SCCOL nDiff = nThisCol - nFirstNew;
1262  ScRange aRange( nLastOtherCol, 0, nOtherTab,
1263  nLastOtherCol+nDiff, MaxRow(), nOtherTab );
1264  pChangeTrack->AppendInsert( aRange );
1265  }
1266  }
1267  else
1268  nLastOtherCol = nOtherCol;
1269  }
1270  if ( nLastOtherCol > 0 ) // deleted at the very top
1271  {
1272  ScRange aDelRange( 0, 0, nOtherTab,
1273  nLastOtherCol-1, MaxRow(), nOtherTab );
1274  pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
1275  }
1276 
1277  // Actions for inserted/deleted rows
1278 
1279  SCROW nLastOtherRow = nOtherEndRow + 1;
1280  // nThisEndRow ... 0
1281  for ( nThisRow = nThisEndRow+1; nThisRow > 0; )
1282  {
1283  --nThisRow;
1284  SCROW nOtherRow = pOtherRows[nThisRow];
1285  if ( ValidRow(nOtherRow) && nOtherRow+1 < nLastOtherRow )
1286  {
1287  // gap -> deleted
1288  ScRange aDelRange( 0, nOtherRow+1, nOtherTab,
1289  MaxCol(), nLastOtherRow-1, nOtherTab );
1290  pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
1291  }
1292  if ( nOtherRow > MaxRow() ) // inserted
1293  {
1294  // combine
1295  if ( nThisRow == nThisEndRow || ValidRow(pOtherRows[nThisRow+1]) )
1296  {
1297  SCROW nFirstNew = nThisRow;
1298  while ( nFirstNew > 0 && pOtherRows[nFirstNew-1] > MaxRow() )
1299  --nFirstNew;
1300  SCROW nDiff = nThisRow - nFirstNew;
1301  ScRange aRange( 0, nLastOtherRow, nOtherTab,
1302  MaxCol(), nLastOtherRow+nDiff, nOtherTab );
1303  pChangeTrack->AppendInsert( aRange );
1304  }
1305  }
1306  else
1307  nLastOtherRow = nOtherRow;
1308  }
1309  if ( nLastOtherRow > 0 ) // deleted at the very top
1310  {
1311  ScRange aDelRange( 0, 0, nOtherTab,
1312  MaxCol(), nLastOtherRow-1, nOtherTab );
1313  pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
1314  }
1315 
1316  // walk rows to find single cells
1317 
1318  for (nThisRow = 0; nThisRow <= nThisEndRow; nThisRow++)
1319  {
1320  SCROW nOtherRow = pOtherRows[nThisRow];
1321  for (nThisCol = 0; nThisCol <= nThisEndCol; nThisCol++)
1322  {
1323  SCCOL nOtherCol = static_cast<SCCOL>(pOtherCols[nThisCol]);
1324  ScAddress aThisPos( nThisCol, nThisRow, nThisTab );
1325  ScCellValue aThisCell;
1326  aThisCell.assign(*this, aThisPos);
1327  ScCellValue aOtherCell; // start empty
1328  if ( ValidCol(nOtherCol) && ValidRow(nOtherRow) )
1329  {
1330  ScAddress aOtherPos( nOtherCol, nOtherRow, nOtherTab );
1331  aOtherCell.assign(rOtherDoc, aOtherPos);
1332  }
1333 
1334  if (!aThisCell.equalsWithoutFormat(aOtherCell))
1335  {
1336  ScRange aRange( aThisPos );
1337  ScChangeActionContent* pAction = new ScChangeActionContent( aRange );
1338  pAction->SetOldValue(aOtherCell, &rOtherDoc, this);
1339  pAction->SetNewValue(aThisCell, this);
1340  pChangeTrack->Append( pAction );
1341  }
1342  }
1343  aProgress.SetStateOnPercent(nProgressStart+nThisRow);
1344  }
1345  }
1346  }
1347 }
1348 
1349 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
If set, cloned formula cells will start to listen to the document.
bool GetNextMarkedCell(SCCOL &rCol, SCROW &rRow, SCTAB nTab, const ScMarkData &rMark)
Definition: documen4.cxx:539
void Set(const ScAddress &rAdr, bool bNewRelCol, bool bNewRelRow, bool bNewRelTab)
Definition: address.hxx:921
void ClearDetectiveOperations()
Definition: documen4.cxx:898
bool equalsWithoutFormat(const ScCellValue &r) const
Definition: cellvalue.cxx:504
virtual svl::SharedString GetString() const
sal_Int32 nIndex
OUString getString() const
ScFormulaCell * SetFormulaCell(SCCOL nCol, SCROW nRow, ScFormulaCell *pCell)
Takes ownership of pCell.
Definition: table2.cxx:1562
void DeleteConditionalFormat(sal_uLong nIndex, SCTAB nTab)
Definition: documen4.cxx:879
ScAddress aStart
Definition: address.hxx:500
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:43
#define SC_DOCCOMP_MINGOOD
Definition: documen4.cxx:912
SCROW Row() const
Definition: address.hxx:262
const char aData[]
SC_DLLPUBLIC ScRange toAbs(const ScSheetLimits &rLimits, const ScAddress &rPos) const
Definition: refdata.cxx:493
void MarkToMulti()
Definition: markdata.cxx:224
Single reference (one address) into the sheet.
Definition: refdata.hxx:30
std::unique_ptr< ContentProperties > pData
formula::FormulaToken * AddMatrixSingleReference(const ScSingleRefData &rRef)
ScSingleRefOpToken with ocMatRef.
Definition: token.cxx:2207
int SetError()
bool isEmpty() const
Definition: cellvalue.cxx:670
int n1
void CompileColRowNameFormula()
Definition: documen4.cxx:566
sal_uIntPtr sal_uLong
long Long
sal_uInt16 GetSubformatIndex(double fNumber) const
void SetRelTab(SCTAB nVal)
Definition: refdata.cxx:99
ocOpen
void SetStateOnPercent(sal_uLong nVal)
Definition: progress.hxx:97
const SfxItemSet & GetItemSet() const
bool IsExternalRef() const
SC_DLLPUBLIC sal_uLong AddCondFormat(std::unique_ptr< ScConditionalFormat > pNew, SCTAB nTab)
Definition: documen4.cxx:705
ScAddress aEnd
Definition: address.hxx:501
SC_DLLPUBLIC void InsertTableOp(const ScTabOpParam &rParam, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const ScMarkData &rMark)
Definition: documen4.cxx:355
virtual SfxItemSet & GetItemSet()
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:104
void SetRowRel(bool bVal)
Definition: refdata.hxx:67
ScConditionalFormat * GetFormat(sal_uInt32 nKey)
Definition: conditio.cxx:2069
const SCROW SCROW_MAX
Definition: address.hxx:56
bool Solver(SCCOL nFCol, SCROW nFRow, SCTAB nFTab, SCCOL nVCol, SCROW nVRow, SCTAB nVTab, const OUString &sValStr, double &nX)
(Goal Seek) Find a value of x that is a root of f(x)
Definition: documen4.cxx:69
bool IsCellMarked(SCCOL nCol, SCROW nRow, bool bNoSimple=false) const
Definition: markdata.cxx:285
bool GetNextSpellingCell(SCCOL &nCol, SCROW &nRow, SCTAB nTab, bool bInSel, const ScMarkData &rMark) const
Definition: documen4.cxx:530
SC_DLLPUBLIC const ScValidationData * GetValidationEntry(sal_uLong nIndex) const
Definition: documen4.cxx:871
void InvalidateTableArea()
Definition: documen4.cxx:576
bool equalsWithoutFormat(const ScRefCellValue &r) const
Definition: cellvalue.cxx:686
Store arbitrary cell value of any kind.
Definition: cellvalue.hxx:36
SC_DLLPUBLIC ScConditionalFormatList * GetCondFormList(SCTAB nTab) const
Definition: documen4.cxx:857
int n2
sal_Int32 SCCOLROW
a type capable of holding either SCCOL or SCROW
Definition: types.hxx:24
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
SC_DLLPUBLIC SCTAB GetTableCount() const
Definition: document.cxx:314
#define SC_DOCCOMP_MAXDIFF
Definition: documen4.cxx:911
double GetValue()
bool IsMultiMarked() const
Definition: markdata.hxx:83
SCTAB GetSelectCount() const
Definition: markdata.cxx:195
double GetRoundFractionValue(double fNumber) const
FormulaError GetErrCode()
static bool IsFuzzing()
virtual const ScSingleRefData * GetSingleRef() const
SCTAB Tab() const
Definition: address.hxx:271
void SetTabRel(bool bVal)
Definition: refdata.hxx:69
sal_uInt16 ColDifferences(SCCOL nThisCol, SCTAB nThisTab, ScDocument &rOtherDoc, SCCOL nOtherCol, SCTAB nOtherTab, SCROW nMaxRow, const SCCOLROW *pOtherRows)
Definition: documen4.cxx:954
ScRefAddress aRefRowCell
Definition: paramisc.hxx:52
void ReplaceStyle(const SvxSearchItem &rSearchItem, SCCOL nCol, SCROW nRow, SCTAB nTab, const ScMarkData &rMark)
Definition: documen4.cxx:548
void MarkUsedExternalReferences()
Definition: documen3.cxx:632
sal_uInt16 GetLen() const
const SfxPoolItem & GetItem(sal_uInt16 nWhichP) const
Definition: patattr.hxx:70
void PutInOrder(T &nStart, T &nEnd)
Definition: address.hxx:954
ocSep
SC_DLLPUBLIC bool GetCellArea(SCTAB nTab, SCCOL &rEndCol, SCROW &rEndRow) const
Definition: document.cxx:1018
SC_DLLPUBLIC void InsertMatrixFormula(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const ScMarkData &rMark, const OUString &rFormula, const ScTokenArray *p=nullptr, const formula::FormulaGrammar::Grammar=formula::FormulaGrammar::GRAM_DEFAULT)
Definition: documen4.cxx:257
A pretty assertion that checks that the relevant bits in the are not set on the document at entry an...
Definition: document.hxx:2653
void AddDetectiveOperation(const ScDetOpData &rData)
Definition: documen4.cxx:890
bool ValidCol(SCCOL nCol, SCCOL nMaxCol)
Definition: address.hxx:93
void SetMarkArea(const ScRange &rRange)
Definition: markdata.cxx:97
Parameter for data table aka multiple operations.
Definition: paramisc.hxx:46
static const OUString & GetNativeSymbol(OpCode eOp)
sal_uInt16 RowDifferences(SCROW nThisRow, SCTAB nThisTab, ScDocument &rOtherDoc, SCROW nOtherRow, SCTAB nOtherTab, SCCOL nMaxCol, const SCCOLROW *pOtherCols)
Definition: documen4.cxx:916
virtual const ScComplexRefData * GetDoubleRef() const
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
int i
ocTableOp
sal_Int16 SCCOL
Definition: types.hxx:22
SvNumberFormatter * GetFormatTable() const
const SvxPageUsage aArr[]
bool Interpret(SCROW nStartOffset=-1, SCROW nEndOffset=-1)
ScRefAddress aRefFormulaCell
Definition: paramisc.hxx:50
#define SC_DOCCOMP_ROWS
Definition: documen4.cxx:914
OUString ScResId(const char *pId)
Definition: scdll.cxx:95
bool EqualEntries(const ScValidationData &r) const
Definition: validat.cxx:134
svExternalDoubleRef
SvNumFormatType
svExternalSingleRef
constexpr double deg2rad(double v)
void SetMatColsRows(SCCOL nCols, SCROW nRows)
iterator end()
Definition: markdata.cxx:953
#define SV_COUNTRY_LANGUAGE_OFFSET
bool empty() const
sal_Int32 GetMaxNumberStringLen(sal_uInt16 &nPrecision, SCTAB nTab, SCCOL nCol, SCROW nRowStart, SCROW nRowEnd) const
Maximum string length of numerical cells of a column, e.g.
Definition: documen4.cxx:597
const SCTAB MAXTAB
Definition: address.hxx:71
std::set< SCTAB >::const_iterator const_iterator
Definition: markdata.hxx:159
SC_DLLPUBLIC const SfxItemSet * GetCondResult(SCCOL nCol, SCROW nRow, SCTAB nTab, ScRefCellValue *pCell=nullptr) const
Definition: documen4.cxx:788
void CompileDBFormula()
Definition: documen4.cxx:556
sal_Int32 GetMaxStringLen(SCTAB nTab, SCCOL nCol, SCROW nRowStart, SCROW nRowEnd, rtl_TextEncoding eCharSet) const
Maximum string length of a column, e.g.
Definition: documen4.cxx:588
virtual sal_uInt16 GetIndex() const
SCCOL Col() const
Definition: address.hxx:267
double getResult()
Check getError() after (!) obtaining the result.
Definition: subtotal.cxx:129
XPropertyListType t
const OUString & GetCellStyle(ScRefCellValue &rCell, const ScAddress &rPos) const
Definition: conditio.cxx:1789
void SetOldValue(const ScCellValue &rCell, const ScDocument *pFromDoc, ScDocument *pToDoc, sal_uLong nFormat)
Definition: chgtrack.cxx:1363
static const sal_uInt16 UNLIMITED_PRECISION
SC_DLLPUBLIC double RoundValueAsShown(double fVal, sal_uInt32 nFormat, const ScInterpreterContext *pContext=nullptr) const
Definition: documen4.cxx:633
void SetDetOpList(std::unique_ptr< ScDetOpList > pNew)
Definition: documen4.cxx:903
void SetNewValue(const ScCellValue &rCell, ScDocument *pDoc)
Definition: chgtrack.cxx:1375
bool IsEmpty() const
Definition: validat.cxx:128
SC_DLLPUBLIC sal_uLong AddValidationEntry(const ScValidationData &rNew)
Definition: documen4.cxx:716
iterator begin()
Definition: markdata.cxx:948
sal_Int32 SCROW
Definition: types.hxx:18
To calculate a single subtotal function.
Definition: subtotal.hxx:61
const ScAddress & GetAddress() const
Definition: address.hxx:888
SC_DLLPUBLIC void CompareDocument(ScDocument &rOtherDoc)
Definition: documen4.cxx:1093
sal_uInt16 GetFormatIntegerDigits(sal_uInt16 nIx=0) const
sal_uInt16 GetFormatPrecision(sal_uInt16 nIx=0) const
SC_DLLPUBLIC bool IsScenario(SCTAB nTab) const
Definition: documen3.cxx:427
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
const SvNumberformat * GetEntry(sal_uInt32 nKey) const
CellType
Definition: global.hxx:282
void assign(ScDocument &rDoc, const ScAddress &rPos)
Take cell value from specified position in specified document.
Definition: cellvalue.cxx:582
SCROW Row() const
Definition: address.hxx:897
void assign(const ScDocument &rDoc, const ScAddress &rPos)
Take cell value from specified position in specified document.
Definition: cellvalue.cxx:330
void InitFlags()
No default ctor, because used in ScRawToken union, set InitFlags!
Definition: refdata.hxx:55
ScRefAddress aRefColCell
Definition: paramisc.hxx:53
#define SC_DOCCOMP_COLUMNS
Definition: documen4.cxx:913
void FindOrder(SCCOLROW *pOtherRows, SCCOLROW nThisEndRow, SCCOLROW nOtherEndRow, bool bColumns, ScDocument &rOtherDoc, SCTAB nThisTab, SCTAB nOtherTab, SCCOLROW nEndCol, const SCCOLROW *pTranslate, ScProgress *pProgress, sal_uLong nProAdd)
Definition: documen4.cxx:995
SCCOL Col() const
Definition: address.hxx:893
SvNumFormatType GetMaskedType() const
constexpr TypedWhichId< ScCondFormatItem > ATTR_CONDITIONAL(154)
QPRO_FUNC_TYPE nType
Definition: qproform.cxx:401
bool GetSelectionFunction(ScSubTotalFunc eFunc, const ScAddress &rCursor, const ScMarkData &rMark, double &rResult)
Definition: documen4.cxx:608
void SetAddress(const ScSheetLimits &rLimits, const ScAddress &rAddr, const ScAddress &rPos)
Definition: refdata.cxx:213
Complex reference (a range) into the sheet.
Definition: refdata.hxx:123
bool ValidColRow(SCCOL nCol, SCROW nRow, SCCOL nMaxCol, SCROW nMaxRow)
Definition: address.hxx:115
bool ValidRow(SCROW nRow, SCROW nMaxRow)
Definition: address.hxx:99
bool getError() const
Definition: subtotal.hxx:70
#define SAL_WARN(area, stream)
SC_DLLPUBLIC ScConditionalFormat * GetCondFormat(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: documen4.cxx:834
OUString GetRefString(const ScDocument &rDocument, SCTAB nActTab, const ScAddress::Details &rDetails=ScAddress::detailsOOOa1) const
Definition: address.cxx:2511
ScRefAddress aRefFormulaEnd
Definition: paramisc.hxx:51
sal_uInt32 GetKey() const
Definition: validat.hxx:161
ScSubTotalFunc
Definition: global.hxx:845
bool HasDetectiveOperations() const
Definition: documen4.cxx:885
const SCTAB SCTAB_MAX
Definition: address.hxx:58
StackVar GetType() const
void SetColRel(bool bVal)
Definition: refdata.hxx:65
ScTokenArray * GetCode()
Definition: rangenam.hxx:120
SC_DLLPUBLIC bool GetName(SCTAB nTab, OUString &rName) const
Definition: document.cxx:213
ScValidationData * Clone() const
Definition: validat.hxx:98
ocClose
bool ValidTab(SCTAB nTab)
Definition: address.hxx:105
bool setCacheTableReferenced(sal_uInt16 nFileId, const OUString &rTabName, size_t nSheets)
Set a table as referenced, used only during store-to-file.
sal_uInt16 GetThousandDivisorPrecision(sal_uInt16 nIx=0) const
std::unique_ptr< ScTokenArray > Clone() const
Definition: token.cxx:1920
void SetCondFormList(ScConditionalFormatList *pList, SCTAB nTab)
Definition: documen4.cxx:865
sal_Int16 SCTAB
Definition: types.hxx:23
const SfxPoolItem * GetEffItem(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich) const
Definition: documen4.cxx:748