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