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 < GetTableCount() && maTabs[nFTab] &&
81 nVTab < GetTableCount() && 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 = GetTableCount();
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 = GetTableCount();
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("="
392
393 const OUString& sSep = ScCompiler::GetNativeSymbol( ocSep);
394 if (rParam.meMode == ScTabOpParam::Column) // column only
395 {
396 aRef.Set( rParam.aRefFormulaCell.GetAddress(), true, false, false );
397 aForString.append(aRef.GetRefString(*this, nTab1)
398 + sSep
399 + rParam.aRefColCell.GetRefString(*this, nTab1)
400 + sSep);
401 aRef.Set( nCol1, nRow1, nTab1, false, true, true );
402 aForString.append(aRef.GetRefString(*this, nTab1));
403 nCol1++;
404 nCol2 = std::min( nCol2, static_cast<SCCOL>(rParam.aRefFormulaEnd.Col() -
405 rParam.aRefFormulaCell.Col() + nCol1 + 1));
406 }
407 else if (rParam.meMode == ScTabOpParam::Row) // row only
408 {
409 aRef.Set( rParam.aRefFormulaCell.GetAddress(), false, true, false );
410 aForString.append(aRef.GetRefString(*this, nTab1)
411 + sSep
412 + rParam.aRefRowCell.GetRefString(*this, nTab1)
413 + sSep);
414 aRef.Set( nCol1, nRow1, nTab1, true, false, true );
415 aForString.append(aRef.GetRefString(*this, nTab1));
416 nRow1++;
417 nRow2 = std::min( nRow2, static_cast<SCROW>(rParam.aRefFormulaEnd.Row() -
418 rParam.aRefFormulaCell.Row() + nRow1 + 1));
419 }
420 else // both
421 {
422 aForString.append(rParam.aRefFormulaCell.GetRefString(*this, nTab1)
423 + sSep
424 + rParam.aRefColCell.GetRefString(*this, nTab1)
425 + sSep);
426 aRef.Set( nCol1, nRow1 + 1, nTab1, false, true, true );
427 aForString.append(aRef.GetRefString(*this, nTab1)
428 + sSep
429 + rParam.aRefRowCell.GetRefString(*this, nTab1)
430 + sSep);
431 aRef.Set( nCol1 + 1, nRow1, nTab1, true, false, true );
432 aForString.append(aRef.GetRefString(*this, nTab1));
433 nCol1++; nRow1++;
434 }
435 aForString.append(ScCompiler::GetNativeSymbol( ocClose ));
436
437 ScFormulaCell aRefCell( *this, ScAddress( nCol1, nRow1, nTab1 ), aForString.makeStringAndClear(),
439 for( j = nCol1; j <= nCol2; j++ )
440 for( k = nRow1; k <= nRow2; k++ )
441 for (i = 0; i < GetTableCount(); i++)
442 {
443 for (const auto& rTab : rMark)
444 {
445 if (rTab >= nMax)
446 break;
447 if( maTabs[rTab] )
448 maTabs[rTab]->SetFormulaCell(
449 j, k, new ScFormulaCell(aRefCell, *this, ScAddress(j, k, rTab), ScCloneFlags::StartListening));
450 }
451 }
452}
453
454namespace {
455
456bool setCacheTableReferenced(const ScDocument& rDoc, formula::FormulaToken& rToken, ScExternalRefManager& rRefMgr, const ScAddress& rPos)
457{
458 switch (rToken.GetType())
459 {
461 return rRefMgr.setCacheTableReferenced(
462 rToken.GetIndex(), rToken.GetString().getString(), 1);
464 {
465 const ScComplexRefData& rRef = *rToken.GetDoubleRef();
466 ScRange aAbs = rRef.toAbs(rDoc, rPos);
467 size_t nSheets = aAbs.aEnd.Tab() - aAbs.aStart.Tab() + 1;
468 return rRefMgr.setCacheTableReferenced(
469 rToken.GetIndex(), rToken.GetString().getString(), nSheets);
470 }
471 case svExternalName:
472 /* TODO: external names aren't supported yet, but would
473 * have to be marked as well, if so. Mechanism would be
474 * different. */
475 OSL_FAIL("ScDocument::MarkUsedExternalReferences: implement the svExternalName case!");
476 break;
477 default:
478 break;
479 }
480 return false;
481}
482
483}
484
486{
487 if (!rArr.GetLen())
488 return false;
489
490 ScExternalRefManager* pRefMgr = nullptr;
492 bool bAllMarked = false;
493 while (!bAllMarked)
494 {
496 if (!t)
497 break;
498 if (t->IsExternalRef())
499 {
500 if (!pRefMgr)
501 pRefMgr = GetExternalRefManager();
502
503 bAllMarked = setCacheTableReferenced(*this, *t, *pRefMgr, rPos);
504 }
505 else if (t->GetType() == svIndex)
506 {
507 // this is a named range. Check if the range contains an external
508 // reference.
509 ScRangeData* pRangeData = GetRangeName()->findByIndex(t->GetIndex());
510 if (!pRangeData)
511 continue;
512
513 ScTokenArray* pArray = pRangeData->GetCode();
514 formula::FormulaTokenArrayPlainIterator aArrayIter(*pArray);
515 for (t = aArrayIter.First(); t; t = aArrayIter.Next())
516 {
517 if (!t->IsExternalRef())
518 continue;
519
520 if (!pRefMgr)
521 pRefMgr = GetExternalRefManager();
522
523 bAllMarked = setCacheTableReferenced(*this, *t, *pRefMgr, rPos);
524 }
525 }
526 }
527 return bAllMarked;
528}
529
531 bool bInSel, const ScMarkData& rMark) const
532{
533 if (const ScTable* pTable = FetchTable(nTab))
534 return pTable->GetNextSpellingCell( nCol, nRow, bInSel, rMark );
535 return false;
536}
537
539 const ScMarkData& rMark )
540{
541 if (ScTable* pTable = FetchTable(nTab))
542 return pTable->GetNextMarkedCell( rCol, rRow, rMark );
543 return false;
544}
545
547 SCCOL nCol, SCROW nRow, SCTAB nTab,
548 const ScMarkData& rMark)
549{
550 if (ScTable* pTable = FetchTable(nTab))
551 pTable->ReplaceStyle(rSearchItem, nCol, nRow, rMark, true/*bIsUndoP*/);
552}
553
555{
556 sc::CompileFormulaContext aCxt(*this);
557 for (auto& rxTab : maTabs)
558 {
559 if (rxTab)
560 rxTab->CompileDBFormula(aCxt);
561 }
562}
563
565{
566 sc::CompileFormulaContext aCxt(*this);
567 for (auto& rxTab : maTabs)
568 {
569 if (rxTab)
570 rxTab->CompileColRowNameFormula(aCxt);
571 }
572}
573
575{
576 for (auto& rxTab : maTabs)
577 {
578 if (!rxTab)
579 break;
580 rxTab->InvalidateTableArea();
581 if ( rxTab->IsScenario() )
582 rxTab->InvalidateScenarioRanges();
583 }
584}
585
587 SCROW nRowStart, SCROW nRowEnd, rtl_TextEncoding eCharSet ) const
588{
589 if (const ScTable* pTable = FetchTable(nTab))
590 return pTable->GetMaxStringLen(nCol, nRowStart, nRowEnd, eCharSet);
591 return 0;
592}
593
594sal_Int32 ScDocument::GetMaxNumberStringLen( sal_uInt16& nPrecision, SCTAB nTab,
595 SCCOL nCol, SCROW nRowStart, SCROW nRowEnd ) const
596{
597 if (const ScTable* pTable = FetchTable(nTab))
598 return pTable->GetMaxNumberStringLen(nPrecision, nCol, nRowStart, nRowEnd);
599 return 0;
600}
601
603 const ScAddress& rCursor, const ScMarkData& rMark,
604 double& rResult )
605{
606 ScFunctionData aData(eFunc);
607
608 ScMarkData aMark(rMark);
609 aMark.MarkToMulti();
610 if (!aMark.IsMultiMarked() && !aMark.IsCellMarked(rCursor.Col(), rCursor.Row()))
611 aMark.SetMarkArea(rCursor);
612
613 SCTAB nMax = GetTableCount();
614 ScMarkData::const_iterator itr = aMark.begin(), itrEnd = aMark.end();
615
616 for (; itr != itrEnd && *itr < nMax && !aData.getError(); ++itr)
617 if (maTabs[*itr])
618 maTabs[*itr]->UpdateSelectionFunction(aData, aMark);
619
620 rResult = aData.getResult();
621 if (aData.getError())
622 rResult = 0.0;
623
624 return !aData.getError();
625}
626
627double ScDocument::RoundValueAsShown( double fVal, sal_uInt32 nFormat, const ScInterpreterContext* pContext ) const
628{
629 const SvNumberFormatter* pFormatter = pContext ? pContext->GetFormatTable() : GetFormatTable();
630 const SvNumberformat* pFormat = pFormatter->GetEntry( nFormat );
631 if (!pFormat)
632 return fVal;
634 if (nType != SvNumFormatType::DATE && nType != SvNumFormatType::TIME && nType != SvNumFormatType::DATETIME )
635 {
636 // MSVC doesn't recognize all paths init nPrecision and wails about
637 // "potentially uninitialized local variable 'nPrecision' used"
638 // so init to some random sensible value preserving all decimals.
639 short nPrecision = 20;
640 bool bStdPrecision = ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0);
641 if (!bStdPrecision)
642 {
643 sal_uInt16 nIdx = pFormat->GetSubformatIndex( fVal );
644 nPrecision = static_cast<short>(pFormat->GetFormatPrecision( nIdx ));
645 switch ( nType )
646 {
647 case SvNumFormatType::PERCENT: // 0.41% == 0.0041
648 nPrecision += 2;
649 break;
650 case SvNumFormatType::SCIENTIFIC: // 1.23e-3 == 0.00123
651 {
652 short nExp = 0;
653 if ( fVal > 0.0 )
654 nExp = static_cast<short>(floor( log10( fVal ) ));
655 else if ( fVal < 0.0 )
656 nExp = static_cast<short>(floor( log10( -fVal ) ));
657 nPrecision -= nExp;
658 short nInteger = static_cast<short>(pFormat->GetFormatIntegerDigits( nIdx ));
659 if ( nInteger > 1 ) // Engineering notation
660 {
661 short nIncrement = nExp % nInteger;
662 if ( nIncrement != 0 )
663 {
664 nPrecision += nIncrement;
665 if (nExp < 0 )
666 nPrecision += nInteger;
667 }
668 }
669 break;
670 }
671 case SvNumFormatType::FRACTION: // get value of fraction representation
672 {
673 return pFormat->GetRoundFractionValue( fVal );
674 }
675 case SvNumFormatType::NUMBER:
676 case SvNumFormatType::CURRENCY:
677 { // tdf#106253 Thousands divisors for format "0,"
678 const sal_uInt16 nTD = pFormat->GetThousandDivisorPrecision( nIdx );
680 // Format contains General keyword, handled below.
681 bStdPrecision = true;
682 else
683 nPrecision -= nTD;
684 break;
685 }
686 default: break;
687 }
688 }
689 if (bStdPrecision)
690 {
691 nPrecision = static_cast<short>(GetDocOptions().GetStdPrecision());
692 // #i115512# no rounding for automatic decimals
693 if (nPrecision == static_cast<short>(SvNumberFormatter::UNLIMITED_PRECISION))
694 return fVal;
695 }
696 double fRound = ::rtl::math::round( fVal, nPrecision );
697 if ( ::rtl::math::approxEqual( fVal, fRound ) )
698 return fVal; // rounding might introduce some error
699 else
700 return fRound;
701 }
702 else
703 return fVal;
704}
705
706// conditional formats and validation ranges
707
708sal_uLong ScDocument::AddCondFormat( std::unique_ptr<ScConditionalFormat> pNew, SCTAB nTab )
709{
710 if(!pNew)
711 return 0;
712
713 if (ScTable* pTable = FetchTable(nTab))
714 return pTable->AddCondFormat(std::move(pNew));
715
716 return 0;
717}
718
720{
721 if (rNew.IsEmpty())
722 return 0; // empty is always 0
723
724 if (!pValidationList)
725 {
728 }
729
730 sal_uLong nMax = 0;
731 for( const auto& rxData : *pValidationList )
732 {
733 const ScValidationData* pData = rxData.get();
734 sal_uLong nKey = pData->GetKey();
735 if ( pData->EqualEntries( rNew ) )
736 return nKey;
737 if ( nKey > nMax )
738 nMax = nKey;
739 }
740
741 // might be called from ScPatternAttr::PutInPool; thus clone (real copy)
742
743 sal_uLong nNewKey = nMax + 1;
744 std::unique_ptr<ScValidationData> pInsert(rNew.Clone(this));
745 pInsert->SetKey( nNewKey );
747 pValidationList->InsertNew( std::move(pInsert) );
748 return nNewKey;
749}
750
752 SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich ) const
753{
754 const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab );
755 if ( pPattern )
756 {
757 const SfxItemSet& rSet = pPattern->GetItemSet();
758 if ( rSet.GetItemState( ATTR_CONDITIONAL ) == SfxItemState::SET )
759 {
760 const ScCondFormatIndexes& rIndex = pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData();
761 ScConditionalFormatList* pCondFormList = GetCondFormList( nTab );
762 if (!rIndex.empty() && pCondFormList)
763 {
764 for(const auto& rItem : rIndex)
765 {
766 const ScConditionalFormat* pForm = pCondFormList->GetFormat( rItem );
767 if ( pForm )
768 {
769 ScAddress aPos(nCol, nRow, nTab);
770 ScRefCellValue aCell(const_cast<ScDocument&>(*this), aPos);
771 const OUString& aStyle = pForm->GetCellStyle(aCell, aPos);
772 if (!aStyle.isEmpty())
773 {
774 SfxStyleSheetBase* pStyleSheet = mxPoolHelper->GetStylePool()->Find(
775 aStyle, SfxStyleFamily::Para );
776 const SfxPoolItem* pItem = nullptr;
777 if ( pStyleSheet && pStyleSheet->GetItemSet().GetItemState(
778 nWhich, true, &pItem ) == SfxItemState::SET )
779 return pItem;
780 }
781 }
782 }
783 }
784 }
785 return &rSet.Get( nWhich );
786 }
787 OSL_FAIL("no pattern");
788 return nullptr;
789}
790
791const SfxItemSet* ScDocument::GetCondResult( SCCOL nCol, SCROW nRow, SCTAB nTab, ScRefCellValue* pCell ) const
792{
793 ScConditionalFormatList* pFormatList = GetCondFormList(nTab);
794 if (!pFormatList)
795 return nullptr;
796
797 ScAddress aPos(nCol, nRow, nTab);
798 ScRefCellValue aCell;
799 if( pCell == nullptr )
800 {
801 aCell.assign(const_cast<ScDocument&>(*this), aPos);
802 pCell = &aCell;
803 }
804 const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab );
805 const ScCondFormatIndexes& rIndex =
806 pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData();
807
808 return GetCondResult(*pCell, aPos, *pFormatList, rIndex);
809}
810
812 ScRefCellValue& rCell, const ScAddress& rPos, const ScConditionalFormatList& rList,
813 const ScCondFormatIndexes& rIndex ) const
814{
815 for (const auto& rItem : rIndex)
816 {
817 const ScConditionalFormat* pForm = rList.GetFormat(rItem);
818 if (!pForm)
819 continue;
820
821 const OUString& aStyle = pForm->GetCellStyle(rCell, rPos);
822 if (!aStyle.isEmpty())
823 {
824 SfxStyleSheetBase* pStyleSheet =
825 mxPoolHelper->GetStylePool()->Find(aStyle, SfxStyleFamily::Para);
826
827 if (pStyleSheet)
828 return &pStyleSheet->GetItemSet();
829
830 // if style is not there, treat like no condition
831 }
832 }
833
834 return nullptr;
835}
836
838 SCCOL nCol, SCROW nRow, SCTAB nTab ) const
839{
840 sal_uInt32 nIndex = 0;
841 const ScCondFormatIndexes& rCondFormats = GetAttr(nCol, nRow, nTab, ATTR_CONDITIONAL)->GetCondFormatData();
842
843 if(!rCondFormats.empty())
844 nIndex = rCondFormats[0];
845
846 if (nIndex)
847 {
848 ScConditionalFormatList* pCondFormList = GetCondFormList(nTab);
849 if (pCondFormList)
850 return pCondFormList->GetFormat( nIndex );
851 else
852 {
853 OSL_FAIL("pCondFormList is 0");
854 }
855 }
856
857 return nullptr;
858}
859
861{
862 if (HasTable(nTab))
863 return maTabs[nTab]->GetCondFormList();
864 return nullptr;
865}
866
868{
869 if (ScTable* pTable = FetchTable(nTab))
870 pTable->SetCondFormList(pList);
871}
872
873const ScValidationData* ScDocument::GetValidationEntry( sal_uInt32 nIndex ) const
874{
875 if ( pValidationList )
876 return pValidationList->GetData( nIndex );
877 else
878 return nullptr;
879}
880
882{
883 if (ScTable* pTable = FetchTable(nTab))
884 pTable->DeleteConditionalFormat(nOldIndex);
885}
886
888{
889 return pDetOpList && pDetOpList->Count();
890}
891
893{
894 if (!pDetOpList)
895 pDetOpList.reset(new ScDetOpList);
896
897 pDetOpList->Append( rData );
898}
899
901{
902 pDetOpList.reset(); // deletes also the entries
903}
904
905void ScDocument::SetDetOpList(std::unique_ptr<ScDetOpList> pNew)
906{
907 pDetOpList = std::move(pNew);
908}
909
910// Comparison of Documents
911
912// Pfriemel-Factors
913#define SC_DOCCOMP_MAXDIFF 256
914#define SC_DOCCOMP_MINGOOD 128
915#define SC_DOCCOMP_COLUMNS 10
916#define SC_DOCCOMP_ROWS 100
917
918sal_uInt16 ScDocument::RowDifferences( SCROW nThisRow, SCTAB nThisTab,
919 ScDocument& rOtherDoc, SCROW nOtherRow, SCTAB nOtherTab,
920 SCCOL nMaxCol, const SCCOLROW* pOtherCols )
921{
922 sal_uLong nDif = 0;
923 sal_uLong nUsed = 0;
924 for (SCCOL nThisCol=0; nThisCol<=nMaxCol; nThisCol++)
925 {
926 SCCOL nOtherCol;
927 if ( pOtherCols )
928 nOtherCol = static_cast<SCCOL>(pOtherCols[nThisCol]);
929 else
930 nOtherCol = nThisCol;
931
932 if (ValidCol(nOtherCol)) // only compare columns that are common to both docs
933 {
934 ScRefCellValue aThisCell(*this, ScAddress(nThisCol, nThisRow, nThisTab));
935 ScRefCellValue aOtherCell(rOtherDoc, ScAddress(nOtherCol, nOtherRow, nOtherTab));
936 if (!aThisCell.equalsWithoutFormat(aOtherCell))
937 {
938 if (!aThisCell.isEmpty() && !aOtherCell.isEmpty())
939 nDif += 3;
940 else
941 nDif += 4; // content <-> empty counts more
942 }
943
944 if (!aThisCell.isEmpty() || !aOtherCell.isEmpty())
945 ++nUsed;
946 }
947 }
948
949 if (nUsed > 0)
950 return static_cast<sal_uInt16>((nDif*64)/nUsed); // max.256 (SC_DOCCOMP_MAXDIFF)
951
952 OSL_ENSURE(!nDif,"Diff without Used");
953 return 0;
954}
955
956sal_uInt16 ScDocument::ColDifferences( SCCOL nThisCol, SCTAB nThisTab,
957 ScDocument& rOtherDoc, SCCOL nOtherCol, SCTAB nOtherTab,
958 SCROW nMaxRow, const SCCOLROW* pOtherRows )
959{
960
961 //TODO: optimize e.g. with iterator?
962
963 sal_uInt64 nDif = 0;
964 sal_uInt64 nUsed = 0;
965 for (SCROW nThisRow=0; nThisRow<=nMaxRow; nThisRow++)
966 {
967 SCROW nOtherRow;
968 if ( pOtherRows )
969 nOtherRow = pOtherRows[nThisRow];
970 else
971 nOtherRow = nThisRow;
972
973 if (ValidRow(nOtherRow)) // only compare rows that are common to both docs
974 {
975 ScRefCellValue aThisCell(*this, ScAddress(nThisCol, nThisRow, nThisTab));
976 ScRefCellValue aOtherCell(rOtherDoc, ScAddress(nOtherCol, nOtherRow, nOtherTab));
977 if (!aThisCell.equalsWithoutFormat(aOtherCell))
978 {
979 if (!aThisCell.isEmpty() && !aOtherCell.isEmpty())
980 nDif += 3;
981 else
982 nDif += 4; // content <-> empty counts more
983 }
984
985 if (!aThisCell.isEmpty() || !aOtherCell.isEmpty())
986 ++nUsed;
987 }
988 }
989
990 if (nUsed > 0)
991 return static_cast<sal_uInt16>((nDif*64)/nUsed); // max.256
992
993 OSL_ENSURE(!nDif,"Diff without Used");
994 return 0;
995}
996
997void ScDocument::FindOrder( SCCOLROW* pOtherRows, SCCOLROW nThisEndRow, SCCOLROW nOtherEndRow,
998 bool bColumns, ScDocument& rOtherDoc, SCTAB nThisTab, SCTAB nOtherTab,
999 SCCOLROW nEndCol, const SCCOLROW* pTranslate, ScProgress* pProgress, sal_uInt64 nProAdd )
1000{
1001 // bColumns=true: rows are columns and vice versa
1002
1003 SCCOLROW nMaxCont; // continue by how much
1004 SCCOLROW nMinGood; // what is a hit (incl.)
1005 if ( bColumns )
1006 {
1007 nMaxCont = SC_DOCCOMP_COLUMNS; // 10 columns
1008 nMinGood = SC_DOCCOMP_MINGOOD;
1009
1010 //TODO: additional pass with nMinGood = 0 ????
1011
1012 }
1013 else
1014 {
1015 nMaxCont = SC_DOCCOMP_ROWS; // 100 rows
1016 nMinGood = SC_DOCCOMP_MINGOOD;
1017 }
1018 bool bUseTotal = bColumns && !pTranslate; // only for the 1st pass
1019
1020 SCCOLROW nOtherRow = 0;
1021 sal_uInt16 nComp;
1022 SCCOLROW nThisRow;
1023 bool bTotal = false; // hold for several nThisRow
1024 SCCOLROW nUnknown = 0;
1025 for (nThisRow = 0; nThisRow <= nThisEndRow; nThisRow++)
1026 {
1027 SCCOLROW nTempOther = nOtherRow;
1028 bool bFound = false;
1029 sal_uInt16 nBest = SC_DOCCOMP_MAXDIFF;
1030 SCCOLROW nMax = std::min( nOtherEndRow, static_cast<SCCOLROW>(( nTempOther + nMaxCont + nUnknown )) );
1031 for (SCCOLROW i=nTempOther; i<=nMax && nBest>0; i++) // stop at 0
1032 {
1033 if (bColumns)
1034 nComp = ColDifferences( static_cast<SCCOL>(nThisRow), nThisTab, rOtherDoc, static_cast<SCCOL>(i), nOtherTab, nEndCol, pTranslate );
1035 else
1036 nComp = RowDifferences( nThisRow, nThisTab, rOtherDoc, i, nOtherTab, static_cast<SCCOL>(nEndCol), pTranslate );
1037 if ( nComp < nBest && ( nComp <= nMinGood || bTotal ) )
1038 {
1039 nTempOther = i;
1040 nBest = nComp;
1041 bFound = true;
1042 }
1043 if ( nComp < SC_DOCCOMP_MAXDIFF || bFound )
1044 bTotal = false;
1045 else if ( i == nTempOther && bUseTotal )
1046 bTotal = true; // only at the very top
1047 }
1048 if ( bFound )
1049 {
1050 pOtherRows[nThisRow] = nTempOther;
1051 nOtherRow = nTempOther + 1;
1052 nUnknown = 0;
1053 }
1054 else
1055 {
1056 pOtherRows[nThisRow] = SCROW_MAX;
1057 ++nUnknown;
1058 }
1059
1060 if (pProgress)
1061 pProgress->SetStateOnPercent(nProAdd+static_cast<sal_uLong>(nThisRow));
1062 }
1063
1064 // fill in blocks that don't match
1065
1066 SCROW nFillStart = 0;
1067 SCROW nFillPos = 0;
1068 bool bInFill = false;
1069 for (nThisRow = 0; nThisRow <= nThisEndRow+1; nThisRow++)
1070 {
1071 SCROW nThisOther = ( nThisRow <= nThisEndRow ) ? pOtherRows[nThisRow] : (nOtherEndRow+1);
1072 if ( ValidRow(nThisOther) )
1073 {
1074 if ( bInFill )
1075 {
1076 if ( nThisOther > nFillStart ) // is there something to distribute?
1077 {
1078 SCROW nDiff1 = nThisOther - nFillStart;
1079 SCROW nDiff2 = nThisRow - nFillPos;
1080 SCROW nMinDiff = std::min(nDiff1, nDiff2);
1081 for (SCROW i=0; i<nMinDiff; i++)
1082 pOtherRows[nFillPos+i] = nFillStart+i;
1083 }
1084
1085 bInFill = false;
1086 }
1087 nFillStart = nThisOther + 1;
1088 nFillPos = nThisRow + 1;
1089 }
1090 else
1091 bInFill = true;
1092 }
1093}
1094
1096{
1097 if (!pChangeTrack)
1098 return;
1099
1100 SCTAB nThisCount = GetTableCount();
1101 SCTAB nOtherCount = rOtherDoc.GetTableCount();
1102 std::unique_ptr<SCTAB[]> pOtherTabs(new SCTAB[nThisCount]);
1103 SCTAB nThisTab;
1104
1105 // compare tables with identical names
1106 OUString aThisName;
1107 OUString aOtherName;
1108 for (nThisTab=0; nThisTab<nThisCount; nThisTab++)
1109 {
1110 SCTAB nOtherTab = SCTAB_MAX;
1111 if (!IsScenario(nThisTab)) // skip scenarios
1112 {
1113 GetName( nThisTab, aThisName );
1114 for (SCTAB nTemp=0; nTemp<nOtherCount && nOtherTab>MAXTAB; nTemp++)
1115 if (!rOtherDoc.IsScenario(nTemp))
1116 {
1117 rOtherDoc.GetName( nTemp, aOtherName );
1118 if ( aThisName == aOtherName )
1119 nOtherTab = nTemp;
1120 }
1121 }
1122 pOtherTabs[nThisTab] = nOtherTab;
1123 }
1124 // fill in, so that un-named tables don't get lost
1125 SCTAB nFillStart = 0;
1126 SCTAB nFillPos = 0;
1127 bool bInFill = false;
1128 for (nThisTab = 0; nThisTab <= nThisCount; nThisTab++)
1129 {
1130 SCTAB nThisOther = ( nThisTab < nThisCount ) ? pOtherTabs[nThisTab] : nOtherCount;
1131 if ( ValidTab(nThisOther) )
1132 {
1133 if ( bInFill )
1134 {
1135 if ( nThisOther > nFillStart ) // is there something to distribute?
1136 {
1137 SCTAB nDiff1 = nThisOther - nFillStart;
1138 SCTAB nDiff2 = nThisTab - nFillPos;
1139 SCTAB nMinDiff = std::min(nDiff1, nDiff2);
1140 for (SCTAB i=0; i<nMinDiff; i++)
1141 if ( !IsScenario(nFillPos+i) && !rOtherDoc.IsScenario(nFillStart+i) )
1142 pOtherTabs[nFillPos+i] = nFillStart+i;
1143 }
1144
1145 bInFill = false;
1146 }
1147 nFillStart = nThisOther + 1;
1148 nFillPos = nThisTab + 1;
1149 }
1150 else
1151 bInFill = true;
1152 }
1153
1154 // compare tables in the original order
1155
1156 for (nThisTab=0; nThisTab<nThisCount; nThisTab++)
1157 {
1158 SCTAB nOtherTab = pOtherTabs[nThisTab];
1159 if ( ValidTab(nOtherTab) )
1160 {
1161 SCCOL nThisEndCol = 0;
1162 SCROW nThisEndRow = 0;
1163 SCCOL nOtherEndCol = 0;
1164 SCROW nOtherEndRow = 0;
1165 GetCellArea( nThisTab, nThisEndCol, nThisEndRow );
1166 rOtherDoc.GetCellArea( nOtherTab, nOtherEndCol, nOtherEndRow );
1167 SCCOL nEndCol = std::max(nThisEndCol, nOtherEndCol);
1168 SCROW nEndRow = std::max(nThisEndRow, nOtherEndRow);
1169 SCCOL nThisCol;
1170 SCROW nThisRow;
1171 sal_uLong n1,n2; // for AppendDeleteRange
1172
1173 //TODO: one Progress over all tables ???
1174
1175 OUString aTabName;
1176 GetName( nThisTab, aTabName );
1177 OUString aTemplate = ScResId(STR_PROGRESS_COMPARING);
1178 sal_Int32 nIndex = 0;
1179 OUString aProText = o3tl::getToken(aTemplate, 0, '#', nIndex ) +
1180 aTabName +
1181 o3tl::getToken(aTemplate, 0, '#', nIndex );
1182 ScProgress aProgress( GetDocumentShell(), aProText, 3*nThisEndRow, true ); // 2x FindOrder, 1x here
1183 tools::Long nProgressStart = 2*nThisEndRow; // start for here
1184
1185 std::unique_ptr<SCCOLROW[]> pTempRows(new SCCOLROW[nThisEndRow+1]);
1186 std::unique_ptr<SCCOLROW[]> pOtherRows(new SCCOLROW[nThisEndRow+1]);
1187 std::unique_ptr<SCCOLROW[]> pOtherCols(new SCCOLROW[nThisEndCol+1]);
1188
1189 // find inserted/deleted columns/rows:
1190 // Two attempts:
1191 // 1) compare original rows (pTempRows)
1192 // 2) compare original columns (pOtherCols)
1193 // with this column order compare rows (pOtherRows)
1194
1195 //TODO: compare columns twice with different nMinGood ???
1196
1197 // 1
1198 FindOrder( pTempRows.get(), nThisEndRow, nOtherEndRow, false,
1199 rOtherDoc, nThisTab, nOtherTab, nEndCol, nullptr, &aProgress, 0 );
1200 // 2
1201 FindOrder( pOtherCols.get(), nThisEndCol, nOtherEndCol, true,
1202 rOtherDoc, nThisTab, nOtherTab, nEndRow, nullptr, nullptr, 0 );
1203 FindOrder( pOtherRows.get(), nThisEndRow, nOtherEndRow, false,
1204 rOtherDoc, nThisTab, nOtherTab, nThisEndCol,
1205 pOtherCols.get(), &aProgress, nThisEndRow );
1206
1207 sal_uLong nMatch1 = 0; // pTempRows, no columns
1208 for (nThisRow = 0; nThisRow<=nThisEndRow; nThisRow++)
1209 if (ValidRow(pTempRows[nThisRow]))
1210 nMatch1 += SC_DOCCOMP_MAXDIFF -
1211 RowDifferences( nThisRow, nThisTab, rOtherDoc, pTempRows[nThisRow],
1212 nOtherTab, nEndCol, nullptr );
1213
1214 sal_uLong nMatch2 = 0; // pOtherRows, pOtherCols
1215 for (nThisRow = 0; nThisRow<=nThisEndRow; nThisRow++)
1216 if (ValidRow(pOtherRows[nThisRow]))
1217 nMatch2 += SC_DOCCOMP_MAXDIFF -
1218 RowDifferences( nThisRow, nThisTab, rOtherDoc, pOtherRows[nThisRow],
1219 nOtherTab, nThisEndCol, pOtherCols.get() );
1220
1221 if ( nMatch1 >= nMatch2 ) // without columns ?
1222 {
1223 // reset columns
1224 for (nThisCol = 0; nThisCol<=nThisEndCol; nThisCol++)
1225 pOtherCols[nThisCol] = nThisCol;
1226
1227 // swap row-arrays (they get both deleted anyway)
1228 pTempRows.swap(pOtherRows);
1229 }
1230 else
1231 {
1232 // remains for pOtherCols, pOtherRows
1233 }
1234
1235 // Generate Change-Actions
1236 // 1) columns from the right
1237 // 2) rows from below
1238 // 3) single cells in normal order
1239
1240 // Actions for inserted/deleted columns
1241
1242 SCCOL nLastOtherCol = static_cast<SCCOL>(nOtherEndCol + 1);
1243 // nThisEndCol ... 0
1244 for ( nThisCol = nThisEndCol+1; nThisCol > 0; )
1245 {
1246 --nThisCol;
1247 SCCOL nOtherCol = static_cast<SCCOL>(pOtherCols[nThisCol]);
1248 if ( ValidCol(nOtherCol) && nOtherCol+1 < nLastOtherCol )
1249 {
1250 // gap -> deleted
1251 ScRange aDelRange( nOtherCol+1, 0, nOtherTab,
1252 nLastOtherCol-1, MaxRow(), nOtherTab );
1253 pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
1254 }
1255 if ( nOtherCol > MaxCol() ) // inserted
1256 {
1257 // combine
1258 if ( nThisCol == nThisEndCol || ValidCol(static_cast<SCCOL>(pOtherCols[nThisCol+1])) )
1259 {
1260 SCCOL nFirstNew = nThisCol;
1261 while ( nFirstNew > 0 && pOtherCols[nFirstNew-1] > MaxCol() )
1262 --nFirstNew;
1263 SCCOL nDiff = nThisCol - nFirstNew;
1264 ScRange aRange( nLastOtherCol, 0, nOtherTab,
1265 nLastOtherCol+nDiff, MaxRow(), nOtherTab );
1266 pChangeTrack->AppendInsert( aRange );
1267 }
1268 }
1269 else
1270 nLastOtherCol = nOtherCol;
1271 }
1272 if ( nLastOtherCol > 0 ) // deleted at the very top
1273 {
1274 ScRange aDelRange( 0, 0, nOtherTab,
1275 nLastOtherCol-1, MaxRow(), nOtherTab );
1276 pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
1277 }
1278
1279 // Actions for inserted/deleted rows
1280
1281 SCROW nLastOtherRow = nOtherEndRow + 1;
1282 // nThisEndRow ... 0
1283 for ( nThisRow = nThisEndRow+1; nThisRow > 0; )
1284 {
1285 --nThisRow;
1286 SCROW nOtherRow = pOtherRows[nThisRow];
1287 if ( ValidRow(nOtherRow) && nOtherRow+1 < nLastOtherRow )
1288 {
1289 // gap -> deleted
1290 ScRange aDelRange( 0, nOtherRow+1, nOtherTab,
1291 MaxCol(), nLastOtherRow-1, nOtherTab );
1292 pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
1293 }
1294 if ( nOtherRow > MaxRow() ) // inserted
1295 {
1296 // combine
1297 if ( nThisRow == nThisEndRow || ValidRow(pOtherRows[nThisRow+1]) )
1298 {
1299 SCROW nFirstNew = nThisRow;
1300 while ( nFirstNew > 0 && pOtherRows[nFirstNew-1] > MaxRow() )
1301 --nFirstNew;
1302 SCROW nDiff = nThisRow - nFirstNew;
1303 ScRange aRange( 0, nLastOtherRow, nOtherTab,
1304 MaxCol(), nLastOtherRow+nDiff, nOtherTab );
1305 pChangeTrack->AppendInsert( aRange );
1306 }
1307 }
1308 else
1309 nLastOtherRow = nOtherRow;
1310 }
1311 if ( nLastOtherRow > 0 ) // deleted at the very top
1312 {
1313 ScRange aDelRange( 0, 0, nOtherTab,
1314 MaxCol(), nLastOtherRow-1, nOtherTab );
1315 pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
1316 }
1317
1318 // walk rows to find single cells
1319
1320 for (nThisRow = 0; nThisRow <= nThisEndRow; nThisRow++)
1321 {
1322 SCROW nOtherRow = pOtherRows[nThisRow];
1323 for (nThisCol = 0; nThisCol <= nThisEndCol; nThisCol++)
1324 {
1325 SCCOL nOtherCol = static_cast<SCCOL>(pOtherCols[nThisCol]);
1326 ScAddress aThisPos( nThisCol, nThisRow, nThisTab );
1327 ScCellValue aThisCell;
1328 aThisCell.assign(*this, aThisPos);
1329 ScCellValue aOtherCell; // start empty
1330 if ( ValidCol(nOtherCol) && ValidRow(nOtherRow) )
1331 {
1332 ScAddress aOtherPos( nOtherCol, nOtherRow, nOtherTab );
1333 aOtherCell.assign(rOtherDoc, aOtherPos);
1334 }
1335
1336 if (!aThisCell.equalsWithoutFormat(aOtherCell))
1337 {
1338 ScRange aRange( aThisPos );
1339 ScChangeActionContent* pAction = new ScChangeActionContent( aRange );
1340 pAction->SetOldValue(aOtherCell, &rOtherDoc, this);
1341 pAction->SetNewValue(aThisCell, this);
1342 pChangeTrack->Append( pAction );
1343 }
1344 }
1345 aProgress.SetStateOnPercent(nProgressStart+nThisRow);
1346 }
1347 }
1348 }
1349}
1350
1352{
1354 FormulaGrammar::extractRefConvention( GetGrammar()));
1355 assert(pConv);
1356 return pConv ? pConv->getSpecialSymbol( ScCompiler::Convention::SHEET_SEPARATOR) : '.';
1357}
1358
1359/* 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:1321
void SetNewValue(const ScCellValue &rCell, ScDocument *pDoc)
Definition: chgtrack.cxx:1333
static const Convention * GetRefConvention(formula::FormulaGrammar::AddressConvention eConv)
Definition: compiler.cxx:2011
ScConditionalFormat * GetFormat(sal_uInt32 nKey)
Definition: conditio.cxx:2098
OUString GetCellStyle(ScRefCellValue &rCell, const ScAddress &rPos) const
Definition: conditio.cxx:1810
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:594
SC_DLLPUBLIC ScColumnsRange GetWritableColumnsRange(SCTAB nTab, SCCOL nColBegin, SCCOL nColEnd)
Definition: document.cxx:2525
SC_DLLPUBLIC double * GetValueCell(const ScAddress &rPos)
Return a pointer to the double value stored in value cell.
Definition: document.cxx:3519
bool ValidRow(SCROW nRow) const
Definition: document.hxx:900
SC_DLLPUBLIC ScRangeName * GetRangeName() const
Definition: documen3.cxx:178
SC_DLLPUBLIC ScTable * FetchTable(SCTAB nTab)
Definition: document.cxx:2509
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:574
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:892
SC_DLLPUBLIC const ScValidationData * GetValidationEntry(sal_uInt32 nIndex) const
Definition: documen4.cxx:873
sal_uInt16 RowDifferences(SCROW nThisRow, SCTAB nThisTab, ScDocument &rOtherDoc, SCROW nOtherRow, SCTAB nOtherTab, SCCOL nMaxCol, const SCCOLROW *pOtherCols)
Definition: documen4.cxx:918
rtl::Reference< ScPoolHelper > mxPoolHelper
Definition: document.hxx:358
const SfxPoolItem * GetEffItem(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich) const
Definition: documen4.cxx:751
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:893
SC_DLLPUBLIC void CompareDocument(ScDocument &rOtherDoc)
Definition: documen4.cxx:1095
bool HasDetectiveOperations() const
Definition: documen4.cxx:887
void AddDetectiveOperation(const ScDetOpData &rData)
Definition: documen4.cxx:892
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:881
SC_DLLPUBLIC double RoundValueAsShown(double fVal, sal_uInt32 nFormat, const ScInterpreterContext *pContext=nullptr) const
Definition: documen4.cxx:627
std::unique_ptr< ScValidationDataList > pValidationList
Definition: document.hxx:376
SC_DLLPUBLIC ScExternalRefManager * GetExternalRefManager() const
Definition: documen3.cxx:625
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:586
std::unique_ptr< ScDetOpList > pDetOpList
Definition: document.hxx:393
void SetCondFormList(ScConditionalFormatList *pList, SCTAB nTab)
Definition: documen4.cxx:867
void ReplaceStyle(const SvxSearchItem &rSearchItem, SCCOL nCol, SCROW nRow, SCTAB nTab, const ScMarkData &rMark)
Definition: documen4.cxx:546
TableContainer maTabs
Definition: document.hxx:378
void SetDetOpList(std::unique_ptr< ScDetOpList > pNew)
Definition: documen4.cxx:905
std::unique_ptr< ScChangeTrack > pChangeTrack
Definition: document.hxx:394
SC_DLLPUBLIC ScConditionalFormat * GetCondFormat(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: documen4.cxx:837
SC_DLLPUBLIC formula::FormulaGrammar::Grammar GetGrammar() const
Definition: document.hxx:1010
void MarkUsedExternalReferences()
Definition: documen3.cxx:639
void SetError(SCCOL nCol, SCROW nRow, SCTAB nTab, const FormulaError nError)
Definition: documen2.cxx:1129
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:997
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1083
bool ValidCol(SCCOL nCol) const
Definition: document.hxx:899
SC_DLLPUBLIC sal_uLong AddValidationEntry(const ScValidationData &rNew)
Definition: documen4.cxx:719
SC_DLLPUBLIC bool GetCellArea(SCTAB nTab, SCCOL &rEndCol, SCROW &rEndRow) const
Definition: document.cxx:998
SC_DLLPUBLIC ScConditionalFormatList * GetCondFormList(SCTAB nTab) const
Definition: documen4.cxx:860
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:467
bool GetNextSpellingCell(SCCOL &nCol, SCROW &nRow, SCTAB nTab, bool bInSel, const ScMarkData &rMark) const
Definition: documen4.cxx:530
void ClearDetectiveOperations()
Definition: documen4.cxx:900
bool GetNextMarkedCell(SCCOL &rCol, SCROW &rRow, SCTAB nTab, const ScMarkData &rMark)
Definition: documen4.cxx:538
SC_DLLPUBLIC const ScFormulaCell * GetFormulaCell(const ScAddress &rPos) const
Definition: document.cxx:3714
SC_DLLPUBLIC CellType GetCellType(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3736
SC_DLLPUBLIC bool HasTable(SCTAB nTab) const
Definition: document.cxx:2502
void CompileDBFormula()
Definition: documen4.cxx:554
bool GetSelectionFunction(ScSubTotalFunc eFunc, const ScAddress &rCursor, const ScMarkData &rMark, double &rResult)
Definition: documen4.cxx:602
void SetDirty(const ScRange &, bool bIncludeEmptyCells)
Definition: document.cxx:3841
SC_DLLPUBLIC bool GetName(SCTAB nTab, OUString &rName) const
Definition: document.cxx:204
SC_DLLPUBLIC sal_uLong AddCondFormat(std::unique_ptr< ScConditionalFormat > pNew, SCTAB nTab)
Definition: documen4.cxx:708
SC_DLLPUBLIC const SfxPoolItem * GetAttr(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich) const
Definition: document.cxx:4684
SC_DLLPUBLIC sal_Unicode GetSheetSeparator() const
Obtain the sheet separator corresponding to the document's grammar.
Definition: documen4.cxx:1351
SC_DLLPUBLIC const SfxItemSet * GetCondResult(SCCOL nCol, SCROW nRow, SCTAB nTab, ScRefCellValue *pCell=nullptr) const
Definition: documen4.cxx:791
SC_DLLPUBLIC const ScPatternAttr * GetPattern(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:4719
SC_DLLPUBLIC const ScDocOptions & GetDocOptions() const
Definition: documen3.cxx:1936
void CompileColRowNameFormula()
Definition: documen4.cxx:564
sal_uInt16 ColDifferences(SCCOL nThisCol, SCTAB nThisTab, ScDocument &rOtherDoc, SCCOL nOtherCol, SCTAB nOtherTab, SCROW nMaxRow, const SCCOLROW *pOtherRows)
Definition: documen4.cxx:956
SC_DLLPUBLIC SCTAB GetTableCount() const
Definition: document.cxx:297
bool ValidColRow(SCCOL nCol, SCROW nRow) const
Definition: document.hxx:901
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:192
const SfxPoolItem & GetItem(sal_uInt16 nWhichP) const
Definition: patattr.hxx:73
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:2488
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:1736
bool IsEmpty() const
Definition: validat.cxx:129
ScValidationData * Clone() const
Definition: validat.hxx:101
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
const OUString & getString() const
static bool IsFuzzing()
#define SC_DOCCOMP_ROWS
Definition: documen4.cxx:916
#define SC_DOCCOMP_MINGOOD
Definition: documen4.cxx:914
#define SC_DOCCOMP_MAXDIFF
Definition: documen4.cxx:913
#define SC_DOCCOMP_COLUMNS
Definition: documen4.cxx:915
@ CORE
Definition: document.hxx:317
CellType
Definition: global.hxx:272
@ CELLTYPE_FORMULA
Definition: global.hxx:276
@ CELLTYPE_VALUE
Definition: global.hxx:274
@ StartListening
If set, cloned formula cells will start to listen to the document.
ScSubTotalFunc
Definition: global.hxx:860
sal_Int32 nIndex
#define SAL_WARN(area, stream)
std::unique_ptr< sal_Int32[]> pData
int n2
int n1
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:242
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:2761
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