summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2023-06-17 01:05:48 +0200
committerEike Rathke <erack@redhat.com>2023-06-17 16:10:08 +0200
commit30c48379c7b791edc615e7691691e344baa455a3 (patch)
treef3362d54878dca77ab05447908864a4a03927f18
parent5c7196acbdd949005c1b52aeab34b5448e09011e (diff)
Resolves: tdf#153517 Use tools::Duration for FillSeries with (date+)time
Change-Id: I18567fdac512ee786ce4b0785b01b2ae6da7450e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153203 Tested-by: Jenkins Reviewed-by: Eike Rathke <erack@redhat.com>
-rw-r--r--sc/inc/table.hxx8
-rw-r--r--sc/source/core/data/documen3.cxx3
-rw-r--r--sc/source/core/data/table4.cxx117
3 files changed, 81 insertions, 47 deletions
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index a2cc60f9d70e..0662053cb89c 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -715,7 +715,8 @@ public:
sc::UpdatedRangeNames& rIndexes) const;
void Fill( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
sal_uInt64 nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
- double nStepValue, double nMaxValue, ScProgress* pProgress);
+ double nStepValue, const tools::Duration& rDurationStep,
+ double nMaxValue, ScProgress* pProgress);
OUString GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW nEndY );
void UpdateSelectionFunction( ScFunctionData& rData, const ScMarkData& rMark );
@@ -1191,13 +1192,14 @@ private:
void FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
sal_uInt64 nFillCount, FillDir eFillDir, FillCmd eFillCmd,
FillDateCmd eFillDateCmd,
- double nStepValue, double nMaxValue, sal_uInt16 nMinDigits,
+ double nStepValue, const tools::Duration& rDurationStep,
+ double nMaxValue, sal_uInt16 nMinDigits,
bool bAttribs, ScProgress* pProgress,
bool bSkipOverlappedCells = false,
std::vector<sal_Int32>* pNonOverlappedCellIdx = nullptr);
void FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
FillCmd& rCmd, FillDateCmd& rDateCmd,
- double& rInc, sal_uInt16& rMinDigits,
+ double& rInc, tools::Duration& rDuration, sal_uInt16& rMinDigits,
ScUserListData*& rListData, sal_uInt16& rListIndex,
bool bHasFiltered, bool& rSkipOverlappedCells,
std::vector<sal_Int32>& rNonOverlappedCellIdx );
diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx
index b1cf5fe81b8c..8d0d2ba9a665 100644
--- a/sc/source/core/data/documen3.cxx
+++ b/sc/source/core/data/documen3.cxx
@@ -29,6 +29,7 @@
#include <vcl/svapp.hxx>
#include <osl/thread.hxx>
#include <osl/diagnose.h>
+#include <tools/duration.hxx>
#include <document.hxx>
#include <attrib.hxx>
#include <table.hxx>
@@ -1171,7 +1172,7 @@ void ScDocument::Fill(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScProg
{
maTabs[rTab]->Fill(nCol1, nRow1, nCol2, nRow2,
nFillCount, eFillDir, eFillCmd, eFillDateCmd,
- nStepValue, nMaxValue, pProgress);
+ nStepValue, tools::Duration(), nMaxValue, pProgress);
RefreshAutoFilter(aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(), rTab);
}
}
diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx
index 10c27f8d2c84..9c6852990efe 100644
--- a/sc/source/core/data/table4.cxx
+++ b/sc/source/core/data/table4.cxx
@@ -28,6 +28,7 @@
#include <vcl/keycodes.hxx>
#include <rtl/math.hxx>
#include <unotools/charclass.hxx>
+#include <tools/duration.hxx>
#include <osl/diagnose.h>
#include <attrib.hxx>
@@ -215,32 +216,20 @@ double approxDiff( double a, double b )
return rtl::math::round(c, -std::max(nExp, nExpArg));
}
-double approxTimeDiff( double a, double b )
+double approxTypedDiff( double a, double b, bool bTime, tools::Duration& rDuration )
{
- // Scale to hours, round to "nanohours" (multiple nanoseconds), scale back.
- // Get back 0.0416666666666667 instead of 0.041666666700621136 or
- // 0.041666666664241347 (raw a-b) for one hour, or worse the approxDiff()
- // 0.041666666659999997 value. Though there is no such correct value,
- // IEEE-754 nearest values are
- // 0.041666666666666664353702032030923874117434024810791015625
- // (0x3FA5555555555555) and
- // 0.04166666666666667129259593593815225176513195037841796875
- // (0x3FA5555555555556).
- // This works also for a diff of seconds, unless corner cases would be
- // discovered, which would make it necessary to ditch the floating point
- // and convert to/from time structure values instead.
- return rtl::math::round((a - b) * 24, 9) / 24;
-}
-
-double approxTypedDiff( double a, double b, bool bTime )
-{
- return bTime ? approxTimeDiff( a, b) : approxDiff( a, b);
+ if (bTime)
+ {
+ rDuration = tools::Duration(a - b);
+ return rDuration.GetInDays();
+ }
+ return approxDiff( a, b);
}
}
void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
FillCmd& rCmd, FillDateCmd& rDateCmd,
- double& rInc, sal_uInt16& rMinDigits,
+ double& rInc, tools::Duration& rDuration, sal_uInt16& rMinDigits,
ScUserListData*& rListData, sal_uInt16& rListIndex,
bool bHasFiltered, bool& rSkipOverlappedCells,
std::vector<sal_Int32>& rNonOverlappedCellIdx)
@@ -248,6 +237,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
OSL_ENSURE( nCol1==nCol2 || nRow1==nRow2, "FillAnalyse: invalid range" );
rInc = 0.0;
+ rDuration = tools::Duration();
rMinDigits = 0;
rListData = nullptr;
rCmd = FILL_SIMPLE;
@@ -413,6 +403,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
}
else if (nValueCount >= 2)
{
+ tools::Duration aDuration;
for (SCSIZE i = 1; i < nValueCount && bVal; i++)
{
aPrevCell = aCurrCell;
@@ -421,11 +412,16 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
aCurrCell = GetCellValue(nColCurr, nRowCurr);
if (aCurrCell.getType() == CELLTYPE_VALUE)
{
+ const bool bTime = (nCurrCellFormatType == SvNumFormatType::TIME ||
+ nCurrCellFormatType == SvNumFormatType::DATETIME);
double nDiff = approxTypedDiff(aCurrCell.getDouble(), aPrevCell.getDouble(),
- (nCurrCellFormatType == SvNumFormatType::TIME ||
- nCurrCellFormatType == SvNumFormatType::DATETIME));
+ bTime, aDuration);
if (i == 1)
+ {
rInc = nDiff;
+ if (bTime)
+ rDuration = aDuration;
+ }
if (!::rtl::math::approxEqual(nDiff, rInc, 13))
bVal = false;
else if ((aCurrCell.getDouble() == 0.0 || aCurrCell.getDouble() == 1.0)
@@ -645,9 +641,10 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
{
if (nCount > 1)
{
+ tools::Duration aDuration;
double nVal1 = aFirstCell.getDouble();
double nVal2 = GetValue(nCol+nAddX, nRow+nAddY);
- rInc = approxTypedDiff( nVal2, nVal1, bTime);
+ rInc = approxTypedDiff( nVal2, nVal1, bTime, aDuration);
nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
bool bVal = true;
@@ -657,7 +654,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
if (aCell.getType() == CELLTYPE_VALUE)
{
nVal2 = aCell.getDouble();
- double nDiff = approxTypedDiff( nVal2, nVal1, bTime);
+ double nDiff = approxTypedDiff( nVal2, nVal1, bTime, aDuration);
if ( !::rtl::math::approxEqual( nDiff, rInc, 13 ) )
bVal = false;
else if ((nVal2 == 0.0 || nVal2 == 1.0) &&
@@ -670,6 +667,8 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
bVal = false;
nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
+ if (bVal && bTime)
+ rDuration = aDuration;
}
if (bVal)
rCmd = FILL_LINEAR;
@@ -1092,6 +1091,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
FillCmd eFillCmd;
FillDateCmd eDateCmd = {};
double nInc;
+ tools::Duration aDurationInc;
sal_uInt16 nMinDigits;
ScUserListData* pListData = nullptr;
sal_uInt16 nListIndex;
@@ -1100,12 +1100,12 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
if (bVertical)
FillAnalyse(static_cast<SCCOL>(nCol),nRow1,
static_cast<SCCOL>(nCol),nRow2, eFillCmd,eDateCmd,
- nInc, nMinDigits, pListData, nListIndex,
+ nInc, aDurationInc, nMinDigits, pListData, nListIndex,
bHasFiltered, bSkipOverlappedCells, aNonOverlappedCellIdx);
else
FillAnalyse(nCol1,static_cast<SCROW>(nRow),
nCol2,static_cast<SCROW>(nRow), eFillCmd,eDateCmd,
- nInc, nMinDigits, pListData, nListIndex,
+ nInc, aDurationInc, nMinDigits, pListData, nListIndex,
bHasFiltered, bSkipOverlappedCells, aNonOverlappedCellIdx);
if (pListData)
@@ -1214,17 +1214,20 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
else
{
if (!bPositive)
+ {
nInc = -nInc;
+ aDurationInc = -aDurationInc;
+ }
double nEndVal = (nInc>=0.0) ? MAXDOUBLE : -MAXDOUBLE;
if (bVertical)
FillSeries( static_cast<SCCOL>(nCol), nRow1,
static_cast<SCCOL>(nCol), nRow2, nFillCount, eFillDir,
- eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, false,
+ eFillCmd, eDateCmd, nInc, aDurationInc, nEndVal, nMinDigits, false,
pProgress, bSkipOverlappedCells, &aNonOverlappedCellIdx);
else
FillSeries( nCol1, static_cast<SCROW>(nRow), nCol2,
static_cast<SCROW>(nRow), nFillCount, eFillDir,
- eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, false,
+ eFillCmd, eDateCmd, nInc, aDurationInc, nEndVal, nMinDigits, false,
pProgress, bSkipOverlappedCells, &aNonOverlappedCellIdx);
if (pProgress)
nProgress = pProgress->GetState();
@@ -1375,6 +1378,7 @@ OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW
FillCmd eFillCmd;
FillDateCmd eDateCmd;
double nInc;
+ tools::Duration aDurationInc;
sal_uInt16 nMinDigits;
ScUserListData* pListData = nullptr;
sal_uInt16 nListIndex;
@@ -1385,7 +1389,7 @@ OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW
// after FillAnalyse / FillSeries fully handle them.
// Now FillAnalyse called as if there are filtered rows, so it will work in the old way.
FillAnalyse(nCol1, nRow1, nCol2, nRow2, eFillCmd, eDateCmd,
- nInc, nMinDigits, pListData, nListIndex,
+ nInc, aDurationInc, nMinDigits, pListData, nListIndex,
true, bSkipOverlappedCells, aNonOverlappedCellIdx);
if ( pListData ) // user defined list
@@ -1530,9 +1534,18 @@ OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW
nStart = 0.0;
if ( eFillCmd == FILL_LINEAR )
{
- double nAdd = nInc;
- bValueOk = ( SubTotal::SafeMult( nAdd, static_cast<double>(nIndex) ) &&
- SubTotal::SafePlus( nStart, nAdd ) );
+ if (aDurationInc)
+ {
+ bool bOverflow;
+ tools::Duration aDuration( aDurationInc.Mult( nIndex, bOverflow));
+ bValueOk = SubTotal::SafePlus( nStart, aDuration.GetInDays()) && !bOverflow;
+ }
+ else
+ {
+ double nAdd = nInc;
+ bValueOk = ( SubTotal::SafeMult( nAdd, static_cast<double>(nIndex) ) &&
+ SubTotal::SafePlus( nStart, nAdd ) );
+ }
}
else // date
{
@@ -2153,7 +2166,8 @@ inline bool isOverflow( const double& rVal, const double& rMax, const double& rS
void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
sal_uInt64 nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
- double nStepValue, double nMaxValue, sal_uInt16 nArgMinDigits,
+ double nStepValue, const tools::Duration& rDurationStep,
+ double nMaxValue, sal_uInt16 nArgMinDigits,
bool bAttribs, ScProgress* pProgress,
bool bSkipOverlappedCells, std::vector<sal_Int32>* pNonOverlappedCellIdx )
{
@@ -2420,10 +2434,18 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
// use multiplication instead of repeated addition
// to avoid accumulating rounding errors
nVal = nStartVal;
- double nAdd = nStepValue;
- if ( !SubTotal::SafeMult( nAdd, static_cast<double>(++nIndex) ) ||
- !SubTotal::SafePlus( nVal, nAdd ) )
- bError = true;
+ if (rDurationStep)
+ {
+ tools::Duration aDuration( rDurationStep.Mult( ++nIndex, bError));
+ bError |= !SubTotal::SafePlus( nVal, aDuration.GetInDays());
+ }
+ else
+ {
+ double nAdd = nStepValue;
+ if ( !SubTotal::SafeMult( nAdd, static_cast<double>(++nIndex) ) ||
+ !SubTotal::SafePlus( nVal, nAdd ) )
+ bError = true;
+ }
}
break;
case FILL_GROWTH:
@@ -2525,10 +2547,18 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
// use multiplication instead of repeated addition
// to avoid accumulating rounding errors
nVal = nStartVal;
- double nAdd = nStepValue;
- if ( !SubTotal::SafeMult( nAdd, static_cast<double>(++nIndex) ) ||
- !SubTotal::SafePlus( nVal, nAdd ) )
- bError = true;
+ if (rDurationStep)
+ {
+ tools::Duration aDuration( rDurationStep.Mult( ++nIndex, bError));
+ bError |= !SubTotal::SafePlus( nVal, aDuration.GetInDays());
+ }
+ else
+ {
+ double nAdd = nStepValue;
+ if ( !SubTotal::SafeMult( nAdd, static_cast<double>(++nIndex) ) ||
+ !SubTotal::SafePlus( nVal, nAdd ) )
+ bError = true;
+ }
}
break;
case FILL_GROWTH:
@@ -2598,13 +2628,14 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
void ScTable::Fill( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
sal_uInt64 nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
- double nStepValue, double nMaxValue, ScProgress* pProgress)
+ double nStepValue, const tools::Duration& rDurationStep,
+ double nMaxValue, ScProgress* pProgress)
{
if (eFillCmd == FILL_AUTO)
FillAuto(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir, pProgress);
else
FillSeries(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir,
- eFillCmd, eFillDateCmd, nStepValue, nMaxValue, 0, true, pProgress);
+ eFillCmd, eFillDateCmd, nStepValue, rDurationStep, nMaxValue, 0, true, pProgress);
}
void ScTable::AutoFormatArea(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,