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>
26#include <osl/diagnose.h>
27#include <o3tl/string_view.hxx>
28
29#include <document.hxx>
30#include <table.hxx>
31#include <globstr.hrc>
32#include <scresid.hxx>
33#include <subtotal.hxx>
34#include <docoptio.hxx>
35#include <markdata.hxx>
36#include <validat.hxx>
37#include <scitems.hxx>
38#include <stlpool.hxx>
39#include <poolhelp.hxx>
40#include <detdata.hxx>
41#include <patattr.hxx>
42#include <chgtrack.hxx>
43#include <progress.hxx>
44#include <paramisc.hxx>
45#include <compiler.hxx>
46#include <externalrefmgr.hxx>
47#include <attrib.hxx>
48#include <formulacell.hxx>
49#include <tokenarray.hxx>
51#include <memory>
52
53using namespace formula;
54
72bool ScDocument::Solver(SCCOL nFCol, SCROW nFRow, SCTAB nFTab,
73 SCCOL nVCol, SCROW nVRow, SCTAB nVTab,
74 const OUString& sValStr, double& nX)
75{
76 bool bRet = false;
77 nX = 0.0;
78 if ( ValidColRow( nFCol, nFRow ) && ValidTab( nFTab ) &&
79 ValidColRow( nVCol, nVRow ) && ValidTab( nVTab ) &&
80 nFTab < static_cast<SCTAB>( maTabs.size() ) && maTabs[nFTab] &&
81 nVTab < static_cast<SCTAB>( maTabs.size() ) && maTabs[nVTab] )
82 {
83 CellType eFType = GetCellType(nFCol, nFRow, nFTab);
84 CellType eVType = GetCellType(nVCol, nVRow, nVTab);
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 }
276 {
277 // just too slow
278 if (nCol2 - nCol1 > 64)
279 return;
280 if (nRow2 - nRow1 > 64)
281 return;
282 }
283 assert( ValidColRow( nCol1, nRow1) && ValidColRow( nCol2, nRow2));
284
285 SCTAB nTab1 = *rMark.begin();
286
287 ScFormulaCell* pCell;
288 ScAddress aPos( nCol1, nRow1, nTab1 );
289 if (pArr)
290 pCell = new ScFormulaCell(*this, aPos, *pArr, eGram, ScMatrixMode::Formula);
291 else
292 pCell = new ScFormulaCell(*this, aPos, rFormula, eGram, ScMatrixMode::Formula);
293 pCell->SetMatColsRows( nCol2 - nCol1 + 1, nRow2 - nRow1 + 1 );
294 SCTAB nMax = static_cast<SCTAB>(maTabs.size());
295 for (const auto& rTab : rMark)
296 {
297 if (rTab >= nMax)
298 break;
299
300 if (!maTabs[rTab])
301 continue;
302
303 if (rTab == nTab1)
304 {
305 pCell = maTabs[rTab]->SetFormulaCell(nCol1, nRow1, pCell);
306 if (!pCell) //NULL if nCol1/nRow1 is invalid, which it can't be here
307 break;
308 }
309 else
310 maTabs[rTab]->SetFormulaCell(
311 nCol1, nRow1,
312 new ScFormulaCell(
313 *pCell, *this, ScAddress(nCol1, nRow1, rTab), ScCloneFlags::StartListening));
314 }
315
316 ScSingleRefData aRefData;
317 aRefData.InitFlags();
318 aRefData.SetRelCol(0);
319 aRefData.SetRelRow(0);
320 aRefData.SetRelTab(0); // 2D matrix, always same sheet
321
322 ScTokenArray aArr(*this); // consists only of one single reference token.
323 formula::FormulaToken* t = aArr.AddMatrixSingleReference(aRefData);
324
325 for (const SCTAB& nTab : rMark)
326 {
327 if (nTab >= nMax)
328 break;
329
330 ScTable* pTab = FetchTable(nTab);
331 if (!pTab)
332 continue;
333
334 for (SCCOL nCol : GetWritableColumnsRange(nTab, nCol1, nCol2))
335 {
336 aRefData.SetRelCol(nCol1 - nCol);
337 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
338 {
339 if (nCol == nCol1 && nRow == nRow1)
340 // Skip the base position.
341 continue;
342
343 // Reference in each cell must point to the origin cell relative to the current cell.
344 aRefData.SetRelRow(nRow1 - nRow);
345 *t->GetSingleRef() = aRefData;
346 // Token array must be cloned so that each formula cell receives its own copy.
347 ScTokenArray aTokArr(aArr.CloneValue());
348 aPos = ScAddress(nCol, nRow, nTab);
349 pCell = new ScFormulaCell(*this, aPos, aTokArr, eGram, ScMatrixMode::Reference);
350 pTab->SetFormulaCell(nCol, nRow, pCell);
351 }
352 }
353 }
354}
355
356void 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
455namespace {
456
457bool setCacheTableReferenced(const ScDocument& rDoc, formula::FormulaToken& rToken, ScExternalRefManager& rRefMgr, const ScAddress& rPos)
458{
459 switch (rToken.GetType())
460 {
462 return rRefMgr.setCacheTableReferenced(
463 rToken.GetIndex(), rToken.GetString().getString(), 1);
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
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
598sal_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
634double 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;
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
715sal_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 {
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 if ( rSet.GetItemState( ATTR_CONDITIONAL ) == SfxItemState::SET )
766 {
767 const ScCondFormatIndexes& rIndex = pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData();
768 ScConditionalFormatList* pCondFormList = GetCondFormList( nTab );
769 if (!rIndex.empty() && pCondFormList)
770 {
771 for(const auto& rItem : rIndex)
772 {
773 const ScConditionalFormat* pForm = pCondFormList->GetFormat( rItem );
774 if ( pForm )
775 {
776 ScAddress aPos(nCol, nRow, nTab);
777 ScRefCellValue aCell(const_cast<ScDocument&>(*this), aPos);
778 const OUString& aStyle = pForm->GetCellStyle(aCell, aPos);
779 if (!aStyle.isEmpty())
780 {
781 SfxStyleSheetBase* pStyleSheet = mxPoolHelper->GetStylePool()->Find(
782 aStyle, SfxStyleFamily::Para );
783 const SfxPoolItem* pItem = nullptr;
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
798const 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
913void 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
926sal_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
964sal_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_uInt64 nDif = 0;
972 sal_uInt64 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
1005void 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_uInt64 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 = o3tl::getToken(aTemplate, 0, '#', nIndex ) +
1188 aTabName +
1189 o3tl::getToken(aTemplate, 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: */
XPropertyListType t
bool ValidTab(SCTAB nTab)
Definition: address.hxx:111
const SCTAB MAXTAB
Definition: address.hxx:70
const SCTAB SCTAB_MAX
Definition: address.hxx:57
const SCROW SCROW_MAX
Definition: address.hxx:55
void PutInOrder(T &nStart, T &nEnd)
Definition: address.hxx:150
SCTAB Tab() const
Definition: address.hxx:283
SCROW Row() const
Definition: address.hxx:274
SCCOL Col() const
Definition: address.hxx:279
void SetOldValue(const ScCellValue &rCell, const ScDocument *pFromDoc, ScDocument *pToDoc, sal_uLong nFormat)
Definition: chgtrack.cxx:1323
void SetNewValue(const ScCellValue &rCell, ScDocument *pDoc)
Definition: chgtrack.cxx:1335
static const Convention * GetRefConvention(formula::FormulaGrammar::AddressConvention eConv)
Definition: compiler.cxx:1982
ScConditionalFormat * GetFormat(sal_uInt32 nKey)
Definition: conditio.cxx:2073
OUString GetCellStyle(ScRefCellValue &rCell, const ScAddress &rPos) const
Definition: conditio.cxx:1793
sal_uInt16 GetStdPrecision() const
Definition: docoptio.hxx:78
SC_DLLPUBLIC bool IsScenario(SCTAB nTab) const
Definition: documen3.cxx:432
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
SC_DLLPUBLIC ScColumnsRange GetWritableColumnsRange(SCTAB nTab, SCCOL nColBegin, SCCOL nColEnd)
Definition: document.cxx:2559
SC_DLLPUBLIC double * GetValueCell(const ScAddress &rPos)
Return a pointer to the double value stored in value cell.
Definition: document.cxx:3558
bool ValidRow(SCROW nRow) const
Definition: document.hxx:899
SC_DLLPUBLIC ScRangeName * GetRangeName() const
Definition: documen3.cxx:176
ScTable * FetchTable(SCTAB nTab)
Definition: document.cxx:2543
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
SC_DLLPUBLIC void InsertTableOp(const ScTabOpParam &rParam, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const ScMarkData &rMark)
Definition: documen4.cxx:356
void InvalidateTableArea()
Definition: documen4.cxx:577
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:891
sal_uInt16 RowDifferences(SCROW nThisRow, SCTAB nThisTab, ScDocument &rOtherDoc, SCROW nOtherRow, SCTAB nOtherTab, SCCOL nMaxCol, const SCCOLROW *pOtherCols)
Definition: documen4.cxx:926
rtl::Reference< ScPoolHelper > mxPoolHelper
Definition: document.hxx:357
const SfxPoolItem * GetEffItem(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich) const
Definition: documen4.cxx:758
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:892
SC_DLLPUBLIC void CompareDocument(ScDocument &rOtherDoc)
Definition: documen4.cxx:1103
bool HasDetectiveOperations() const
Definition: documen4.cxx:895
void AddDetectiveOperation(const ScDetOpData &rData)
Definition: documen4.cxx:900
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:72
void DeleteConditionalFormat(sal_uLong nIndex, SCTAB nTab)
Definition: documen4.cxx:889
SC_DLLPUBLIC double RoundValueAsShown(double fVal, sal_uInt32 nFormat, const ScInterpreterContext *pContext=nullptr) const
Definition: documen4.cxx:634
std::unique_ptr< ScValidationDataList > pValidationList
Definition: document.hxx:375
SC_DLLPUBLIC ScExternalRefManager * GetExternalRefManager() const
Definition: documen3.cxx:627
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
std::unique_ptr< ScDetOpList > pDetOpList
Definition: document.hxx:392
void SetCondFormList(ScConditionalFormatList *pList, SCTAB nTab)
Definition: documen4.cxx:875
SC_DLLPUBLIC const ScValidationData * GetValidationEntry(sal_uLong nIndex) const
Definition: documen4.cxx:881
void ReplaceStyle(const SvxSearchItem &rSearchItem, SCCOL nCol, SCROW nRow, SCTAB nTab, const ScMarkData &rMark)
Definition: documen4.cxx:549
TableContainer maTabs
Definition: document.hxx:377
void SetDetOpList(std::unique_ptr< ScDetOpList > pNew)
Definition: documen4.cxx:913
std::unique_ptr< ScChangeTrack > pChangeTrack
Definition: document.hxx:393
SC_DLLPUBLIC ScConditionalFormat * GetCondFormat(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: documen4.cxx:844
SC_DLLPUBLIC formula::FormulaGrammar::Grammar GetGrammar() const
Definition: document.hxx:1008
void MarkUsedExternalReferences()
Definition: documen3.cxx:641
void SetError(SCCOL nCol, SCROW nRow, SCTAB nTab, const FormulaError nError)
Definition: documen2.cxx:1082
void FindOrder(SCCOLROW *pOtherRows, SCCOLROW nThisEndRow, SCCOLROW nOtherEndRow, bool bColumns, ScDocument &rOtherDoc, SCTAB nThisTab, SCTAB nOtherTab, SCCOLROW nEndCol, const SCCOLROW *pTranslate, ScProgress *pProgress, sal_uInt64 nProAdd)
Definition: documen4.cxx:1005
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1081
bool ValidCol(SCCOL nCol) const
Definition: document.hxx:898
SC_DLLPUBLIC sal_uLong AddValidationEntry(const ScValidationData &rNew)
Definition: documen4.cxx:726
SC_DLLPUBLIC bool GetCellArea(SCTAB nTab, SCCOL &rEndCol, SCROW &rEndRow) const
Definition: document.cxx:1020
SC_DLLPUBLIC ScConditionalFormatList * GetCondFormList(SCTAB nTab) const
Definition: documen4.cxx:867
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:460
bool GetNextSpellingCell(SCCOL &nCol, SCROW &nRow, SCTAB nTab, bool bInSel, const ScMarkData &rMark) const
Definition: documen4.cxx:531
void ClearDetectiveOperations()
Definition: documen4.cxx:908
bool GetNextMarkedCell(SCCOL &rCol, SCROW &rRow, SCTAB nTab, const ScMarkData &rMark)
Definition: documen4.cxx:540
SC_DLLPUBLIC const ScFormulaCell * GetFormulaCell(const ScAddress &rPos) const
Definition: document.cxx:3764
SC_DLLPUBLIC CellType GetCellType(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3788
void CompileDBFormula()
Definition: documen4.cxx:557
bool GetSelectionFunction(ScSubTotalFunc eFunc, const ScAddress &rCursor, const ScMarkData &rMark, double &rResult)
Definition: documen4.cxx:609
void SetDirty(const ScRange &, bool bIncludeEmptyCells)
Definition: document.cxx:3897
SC_DLLPUBLIC bool GetName(SCTAB nTab, OUString &rName) const
Definition: document.cxx:215
SC_DLLPUBLIC sal_uLong AddCondFormat(std::unique_ptr< ScConditionalFormat > pNew, SCTAB nTab)
Definition: documen4.cxx:715
SC_DLLPUBLIC const SfxPoolItem * GetAttr(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich) const
Definition: document.cxx:4771
SC_DLLPUBLIC sal_Unicode GetSheetSeparator() const
Obtain the sheet separator corresponding to the document's grammar.
Definition: documen4.cxx:1359
SC_DLLPUBLIC const SfxItemSet * GetCondResult(SCCOL nCol, SCROW nRow, SCTAB nTab, ScRefCellValue *pCell=nullptr) const
Definition: documen4.cxx:798
SC_DLLPUBLIC const ScPatternAttr * GetPattern(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:4806
SC_DLLPUBLIC const ScDocOptions & GetDocOptions() const
Definition: documen3.cxx:1946
void CompileColRowNameFormula()
Definition: documen4.cxx:567
sal_uInt16 ColDifferences(SCCOL nThisCol, SCTAB nThisTab, ScDocument &rOtherDoc, SCCOL nOtherCol, SCTAB nOtherTab, SCROW nMaxRow, const SCCOLROW *pOtherRows)
Definition: documen4.cxx:964
SC_DLLPUBLIC SCTAB GetTableCount() const
Definition: document.cxx:315
bool ValidColRow(SCCOL nCol, SCROW nRow) const
Definition: document.hxx:900
bool setCacheTableReferenced(sal_uInt16 nFileId, const OUString &rTabName, size_t nSheets)
Set a table as referenced, used only during store-to-file.
double GetValue()
FormulaError GetErrCode()
void SetMatColsRows(SCCOL nCols, SCROW nRows)
bool Interpret(SCROW nStartOffset=-1, SCROW nEndOffset=-1)
To calculate a single subtotal function.
Definition: subtotal.hxx:61
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:43
const_iterator end() const
Definition: markdata.hxx:164
bool IsMultiMarked() const
Definition: markdata.hxx:81
bool IsCellMarked(SCCOL nCol, SCROW nRow, bool bNoSimple=false) const
Definition: markdata.cxx:270
SCTAB GetSelectCount() const
Definition: markdata.cxx:180
void MarkToMulti()
Definition: markdata.cxx:209
void SetMarkArea(const ScRange &rRange)
Definition: markdata.cxx:92
const_iterator begin() const
Definition: markdata.hxx:163
std::set< SCTAB >::const_iterator const_iterator
Definition: markdata.hxx:161
SfxItemSet & GetItemSet()
Definition: patattr.hxx:155
const SfxPoolItem & GetItem(sal_uInt16 nWhichP) const
Definition: patattr.hxx:72
void SetStateOnPercent(sal_uInt64 nVal)
Definition: progress.hxx:96
ScTokenArray * GetCode()
Definition: rangenam.hxx:119
SC_DLLPUBLIC ScRangeData * findByIndex(sal_uInt16 i) const
Definition: rangenam.cxx:716
ScAddress aEnd
Definition: address.hxx:498
ScAddress aStart
Definition: address.hxx:497
SCCOL Col() const
Definition: address.hxx:886
OUString GetRefString(const ScDocument &rDocument, SCTAB nActTab, const ScAddress::Details &rDetails=ScAddress::detailsOOOa1) const
Definition: address.cxx:2490
const ScAddress & GetAddress() const
Definition: address.hxx:881
void Set(const ScAddress &rAdr, bool bNewRelCol, bool bNewRelRow, bool bNewRelTab)
Definition: address.hxx:914
SCROW Row() const
Definition: address.hxx:890
ScFormulaCell * SetFormulaCell(SCCOL nCol, SCROW nRow, ScFormulaCell *pCell)
Takes ownership of pCell.
Definition: table2.cxx:1735
bool IsEmpty() const
Definition: validat.cxx:128
ScValidationData * Clone() const
Definition: validat.hxx:97
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
virtual SfxItemSet & GetItemSet()
static const sal_uInt16 UNLIMITED_PRECISION
const SvNumberformat * GetEntry(sal_uInt32 nKey) const
SvNumFormatType GetMaskedType() const
sal_uInt16 GetThousandDivisorPrecision(sal_uInt16 nIx=0) const
sal_uInt16 GetFormatIntegerDigits(sal_uInt16 nIx=0) const
sal_uInt16 GetFormatPrecision(sal_uInt16 nIx=0) const
double GetRoundFractionValue(double fNumber) const
sal_uInt16 GetSubformatIndex(double fNumber) const
static const OUString & GetNativeSymbol(OpCode eOp)
sal_uInt16 GetLen() const
virtual sal_uInt16 GetIndex() const
StackVar GetType() const
virtual const ScComplexRefData * GetDoubleRef() const
virtual const svl::SharedString & GetString() const
bool empty() const
OUString getString() const
static bool IsFuzzing()
#define SC_DOCCOMP_ROWS
Definition: documen4.cxx:924
#define SC_DOCCOMP_MINGOOD
Definition: documen4.cxx:922
#define SC_DOCCOMP_MAXDIFF
Definition: documen4.cxx:921
#define SC_DOCCOMP_COLUMNS
Definition: documen4.cxx:923
@ CORE
Definition: document.hxx:316
CellType
Definition: global.hxx:270
@ CELLTYPE_FORMULA
Definition: global.hxx:274
@ CELLTYPE_VALUE
Definition: global.hxx:272
@ StartListening
If set, cloned formula cells will start to listen to the document.
ScSubTotalFunc
Definition: global.hxx:844
sal_Int32 nIndex
#define SAL_WARN(area, stream)
std::unique_ptr< sal_Int32[]> pData
int n2
int n1
const ContentProperties & rData
constexpr OUStringLiteral aData
constexpr double deg2rad(double v)
svIndex
svExternalDoubleRef
svExternalName
svExternalSingleRef
int i
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
const SvxPageUsage aArr[]
long Long
ocClose
ocOpen
ocSep
ocTableOp
QPRO_FUNC_TYPE nType
Definition: qproform.cxx:398
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:90
constexpr TypedWhichId< ScCondFormatItem > ATTR_CONDITIONAL(154)
static SfxItemSet & rSet
sal_uIntPtr sal_uLong
Store arbitrary cell value of any kind.
Definition: cellvalue.hxx:32
void assign(const ScDocument &rDoc, const ScAddress &rPos)
Take cell value from specified position in specified document.
Definition: cellvalue.cxx:359
bool equalsWithoutFormat(const ScCellValue &r) const
Definition: cellvalue.cxx:524
@ SHEET_SEPARATOR
Character between sheet name and address.
Definition: compiler.hxx:241
virtual sal_Unicode getSpecialSymbol(SpecialSymbolType eSymType) const =0
Complex reference (a range) into the sheet.
Definition: refdata.hxx:123
SC_DLLPUBLIC ScRange toAbs(const ScSheetLimits &rLimits, const ScAddress &rPos) const
Definition: refdata.cxx:493
SvNumberFormatter * GetFormatTable() const
A pretty assertion that checks that the relevant bits in the @nFlags are not set on the document at e...
Definition: document.hxx:2756
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:108
bool isEmpty() const
Definition: cellvalue.cxx:667
void assign(ScDocument &rDoc, const ScAddress &rPos)
Take cell value from specified position in specified document.
Definition: cellvalue.cxx:579
bool equalsWithoutFormat(const ScRefCellValue &r) const
Definition: cellvalue.cxx:683
Single reference (one address) into the sheet.
Definition: refdata.hxx:30
void SetRelRow(SCROW nVal)
Definition: refdata.cxx:82
void SetRelTab(SCTAB nVal)
Definition: refdata.cxx:99
void SetRelCol(SCCOL nVal)
Definition: refdata.cxx:65
void InitFlags()
No default ctor, because used in ScRawToken union, set InitFlags!
Definition: refdata.hxx:54
Parameter for data table aka multiple operations.
Definition: paramisc.hxx:46
ScRefAddress aRefFormulaEnd
Definition: paramisc.hxx:50
ScRefAddress aRefColCell
Definition: paramisc.hxx:52
ScRefAddress aRefFormulaCell
Definition: paramisc.hxx:49
ScRefAddress aRefRowCell
Definition: paramisc.hxx:51
sal_uInt16 sal_Unicode
sal_Int32 SCCOLROW
a type capable of holding either SCCOL or SCROW
Definition: types.hxx:23
sal_Int16 SCTAB
Definition: types.hxx:22
sal_Int16 SCCOL
Definition: types.hxx:21
sal_Int32 SCROW
Definition: types.hxx:17
SvNumFormatType
#define SV_COUNTRY_LANGUAGE_OFFSET