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