[Libreoffice-commits] core.git: sc/inc sc/source

Eike Rathke (via logerrit) logerrit at kemper.freedesktop.org
Thu Sep 5 21:19:29 UTC 2019


 sc/inc/table.hxx               |    2 
 sc/source/core/data/table2.cxx |   17 ++
 sc/source/core/data/table4.cxx |  276 ++++++++++++++++++++++++++---------------
 3 files changed, 195 insertions(+), 100 deletions(-)

New commits:
commit de146784684789174616108817f5c9df7c000e81
Author:     Eike Rathke <erack at redhat.com>
AuthorDate: Thu Sep 5 22:17:32 2019 +0200
Commit:     Eike Rathke <erack at redhat.com>
CommitDate: Thu Sep 5 23:18:29 2019 +0200

    Resolves: tdf#126577 stop filling a series when threshold is reached
    
    ... instead of filling the remainder of the selection with #NUM! errors.
    
    Change-Id: I12f3943196878c7631f3dc6ac182631faab17323
    Reviewed-on: https://gerrit.libreoffice.org/78675
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Jenkins

diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 29a7b28fe635..7d28afcf102d 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -715,6 +715,8 @@ public:
                             const ScPatternAttr& rPattern, SvNumFormatType nNewType );
     void        AddCondFormatData( const ScRangeList& rRange, sal_uInt32 nIndex );
     void        RemoveCondFormatData( const ScRangeList& rRange, sal_uInt32 nIndex );
+    void        SetPatternAreaCondFormat( SCCOL nCol, SCROW nStartRow, SCROW nEndRow,
+                    const ScPatternAttr& rAttr, const ScCondFormatIndexes& rCondFormatIndexes );
 
     void        ApplyStyle( SCCOL nCol, SCROW nRow, const ScStyleSheet* rStyle );
     void        ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, const ScStyleSheet& rStyle );
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index df0a1517f63a..e4d062f98e71 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -2667,6 +2667,23 @@ void ScTable::RemoveCondFormatData( const ScRangeList& rRangeList, sal_uInt32 nI
     }
 }
 
+void  ScTable::SetPatternAreaCondFormat( SCCOL nCol, SCROW nStartRow, SCROW nEndRow,
+        const ScPatternAttr& rAttr, const ScCondFormatIndexes& rCondFormatIndexes )
+{
+    aCol[nCol].SetPatternArea( nStartRow, nEndRow, rAttr);
+
+    for (const auto& rIndex : rCondFormatIndexes)
+    {
+        ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(rIndex);
+        if (pCondFormat)
+        {
+            ScRangeList aRange = pCondFormat->GetRange();
+            aRange.Join( ScRange( nCol, nStartRow, nTab, nCol, nEndRow, nTab));
+            pCondFormat->SetRange(aRange);
+        }
+    }
+}
+
 void ScTable::ApplyStyle( SCCOL nCol, SCROW nRow, const ScStyleSheet* rStyle )
 {
     if (ValidColRow(nCol,nRow))
diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx
index 0fb45a287026..15e6cc719c9f 100644
--- a/sc/source/core/data/table4.cxx
+++ b/sc/source/core/data/table4.cxx
@@ -1534,6 +1534,92 @@ void ScTable::FillAutoSimple(
         pProgress->SetStateOnPercent( rProgress );
 }
 
+namespace
+{
+// Target value exceeded?
+inline bool isOverflow( const double& rVal, const double& rMax, const double& rStep,
+        const double& rStartVal, FillCmd eFillCmd )
+{
+    switch (eFillCmd)
+    {
+        case FILL_LINEAR:
+        case FILL_DATE:
+            if (rStep >= 0.0)
+                return rVal > rMax;
+            else
+                return rVal < rMax;
+        break;
+        case FILL_GROWTH:
+            if (rStep > 0.0)
+            {
+                if (rStep >= 1.0)
+                {
+                    // Growing away from zero, including zero growth (1.0).
+                    if (rVal >= 0.0)
+                        return rVal > rMax;
+                    else
+                        return rVal < rMax;
+                }
+                else
+                {
+                    // Shrinking towards zero.
+                    if (rVal >= 0.0)
+                        return rVal < rMax;
+                    else
+                        return rVal > rMax;
+                }
+            }
+            else if (rStep < 0.0)
+            {
+                // Alternating positive and negative values.
+                if (rStep <= -1.0)
+                {
+                    // Growing away from zero, including zero growth (-1.0).
+                    if (rVal >= 0.0)
+                    {
+                        if (rMax >= 0.0)
+                            return rVal > rMax;
+                        else
+                            // Regard negative rMax as lower limit, which will
+                            // be reached only by a negative rVal.
+                            return false;
+                    }
+                    else
+                    {
+                        if (rMax <= 0.0)
+                            return rVal < rMax;
+                        else
+                            // Regard positive rMax as upper limit, which will
+                            // be reached only by a positive rVal.
+                            return false;
+                    }
+                }
+                else
+                {
+                    // Shrinking towards zero.
+                    if (rVal >= 0.0)
+                        return rVal < rMax;
+                    else
+                        return rVal > rMax;
+                }
+            }
+            else // if (rStep == 0.0)
+            {
+                // All values become zero.
+                // Corresponds with bEntireArea in FillSeries().
+                if (rMax > 0.0)
+                    return rMax < rStartVal;
+                else if (rMax < 0.0)
+                    return rStartVal < rMax;
+            }
+        break;
+        default:
+            assert(!"eFillCmd");
+    }
+    return false;
+}
+}
+
 void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
                     sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
                     double nStepValue, double nMaxValue, sal_uInt16 nArgMinDigits,
@@ -1615,11 +1701,53 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
     SCCOLROW nIMin = nIStart;
     SCCOLROW nIMax = nIEnd;
     PutInOrder(nIMin,nIMax);
-    InsertDeleteFlags nDel = bAttribs ? InsertDeleteFlags::AUTOFILL : (InsertDeleteFlags::AUTOFILL & InsertDeleteFlags::CONTENTS);
 
-    bool bIsFiltered = IsDataFiltered(aFillRange);
-    if (!bIsFiltered)
+    const bool bIsFiltered = IsDataFiltered(aFillRange);
+    bool bEntireArea = (!bIsFiltered && eFillCmd == FILL_SIMPLE);
+    if (!bIsFiltered && !bEntireArea && (eFillCmd == FILL_LINEAR || eFillCmd == FILL_GROWTH)
+            && (nOEnd - nOStart == 0))
+    {
+        // For the usual case of one col/row determine if a numeric series is
+        // at least as long as the area to be filled and does not end earlier,
+        // so we can treat it as entire area for performance reasons at least
+        // in the vertical case.
+        ScCellValue aSrcCell;
+        if (bVertical)
+            aSrcCell = aCol[static_cast<SCCOL>(nOStart)].GetCellValue(static_cast<SCROW>(nISource));
+        else
+            aSrcCell = aCol[static_cast<SCCOL>(nISource)].GetCellValue(static_cast<SCROW>(nOStart));
+        // Same logic as for the actual series.
+        if (!aSrcCell.isEmpty() && (aSrcCell.meType == CELLTYPE_VALUE || aSrcCell.meType == CELLTYPE_FORMULA))
+        {
+            double nStartVal;
+            if (aSrcCell.meType == CELLTYPE_VALUE)
+                nStartVal = aSrcCell.mfValue;
+            else
+                nStartVal = aSrcCell.mpFormula->GetValue();
+            if (eFillCmd == FILL_LINEAR)
+            {
+                if (nStepValue == 0.0)
+                    bEntireArea = (nStartVal <= nMaxValue); // fill with same value
+                else if (((nMaxValue - nStartVal) / nStepValue) >= nFillCount)
+                    bEntireArea = true;
+            }
+            else if (eFillCmd == FILL_GROWTH)
+            {
+                if (nStepValue == 1.0)
+                    bEntireArea = (nStartVal <= nMaxValue); // fill with same value
+                else if (nStepValue == -1.0)
+                    bEntireArea = (fabs(nStartVal) <= fabs(nMaxValue)); // fill with alternating value
+                else if (nStepValue == 0.0)
+                    bEntireArea = (nStartVal == 0.0
+                            || (nStartVal < 0.0 && nMaxValue >= 0.0)
+                            || (nStartVal > 0.0 && nMaxValue <= 0.0));  // fill with 0.0
+            }
+        }
+    }
+    if (bEntireArea)
     {
+        InsertDeleteFlags nDel = (bAttribs ? InsertDeleteFlags::AUTOFILL :
+                (InsertDeleteFlags::AUTOFILL & InsertDeleteFlags::CONTENTS));
         if (bVertical)
             DeleteArea(nCol1, static_cast<SCROW>(nIMin), nCol2, static_cast<SCROW>(nIMax), nDel);
         else
@@ -1643,72 +1771,45 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
         // Source cell value. We need to clone the value since it may be inserted repeatedly.
         ScCellValue aSrcCell = aCol[nCol].GetCellValue(static_cast<SCROW>(nRow));
 
+        const ScPatternAttr* pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nRow));
+        const ScCondFormatItem& rCondFormatItem = pSrcPattern->GetItem(ATTR_CONDITIONAL);
+        const ScCondFormatIndexes& rCondFormatIndex = rCondFormatItem.GetCondFormatData();
+
         if (bAttribs)
         {
-            const ScPatternAttr* pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nRow));
-
-            const ScCondFormatItem& rCondFormatItem = pSrcPattern->GetItem(ATTR_CONDITIONAL);
-            const ScCondFormatIndexes& rCondFormatIndex = rCondFormatItem.GetCondFormatData();
-
             if (bVertical)
             {
-                // if not filtered use the faster method
-                // hidden cols/rows should be skipped
-                if(!bIsFiltered)
+                // If entire area (not filtered and simple fill) use the faster
+                // method, else hidden cols/rows should be skipped and series
+                // fill needs to determine the end row dynamically.
+                if (bEntireArea)
                 {
-                    aCol[nCol].SetPatternArea( static_cast<SCROW>(nIMin),
-                            static_cast<SCROW>(nIMax), *pSrcPattern );
-
-                    for(const auto& rIndex : rCondFormatIndex)
-                    {
-                        ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(rIndex);
-                        if (pCondFormat)
-                        {
-                            ScRangeList aRange = pCondFormat->GetRange();
-                            aRange.Join(ScRange(nCol, nIMin, nTab, nCol, nIMax, nTab));
-                            pCondFormat->SetRange(aRange);
-                        }
-                    }
+                    SetPatternAreaCondFormat( nCol, static_cast<SCROW>(nIMin),
+                            static_cast<SCROW>(nIMax), *pSrcPattern, rCondFormatIndex);
                 }
-                else
+                else if (eFillCmd == FILL_SIMPLE)
                 {
+                    assert(bIsFiltered);
                     for(SCROW nAtRow = static_cast<SCROW>(nIMin); nAtRow <= static_cast<SCROW>(nIMax); ++nAtRow)
                     {
                         if(!RowHidden(nAtRow))
                         {
-                            aCol[nCol].SetPatternArea( nAtRow,
-                                    nAtRow, *pSrcPattern);
-                            for(const auto& rIndex : rCondFormatIndex)
-                            {
-                                ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(rIndex);
-                                if (pCondFormat)
-                                {
-                                    ScRangeList aRange = pCondFormat->GetRange();
-                                    aRange.Join(ScRange(nCol, nAtRow, nTab, nCol, nAtRow, nTab));
-                                    pCondFormat->SetRange(aRange);
-                                }
-                            }
+                            SetPatternAreaCondFormat( nCol, nAtRow, nAtRow, *pSrcPattern, rCondFormatIndex);
                         }
                     }
 
                 }
             }
-            else
+            else if (bEntireArea || eFillCmd == FILL_SIMPLE)
+            {
                 for (SCCOL nAtCol = static_cast<SCCOL>(nIMin); nAtCol <= sal::static_int_cast<SCCOL>(nIMax); nAtCol++)
+                {
                     if(!ColHidden(nAtCol))
                     {
-                        aCol[nAtCol].SetPattern(static_cast<SCROW>(nRow), *pSrcPattern);
-                        for(const auto& rIndex : rCondFormatIndex)
-                        {
-                            ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(rIndex);
-                            if (pCondFormat)
-                            {
-                                ScRangeList aRange = pCondFormat->GetRange();
-                                aRange.Join(ScRange(nAtCol, static_cast<SCROW>(nRow), nTab, nAtCol, static_cast<SCROW>(nRow), nTab));
-                                pCondFormat->SetRange(aRange);
-                            }
-                        }
+                        SetPatternAreaCondFormat( nAtCol, nRow, nRow, *pSrcPattern, rCondFormatIndex);
                     }
+                }
+            }
         }
 
         if (!aSrcCell.isEmpty())
@@ -1721,11 +1822,8 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
             }
             else if (eCellType == CELLTYPE_VALUE || eCellType == CELLTYPE_FORMULA)
             {
-                double nStartVal;
-                if (eCellType == CELLTYPE_VALUE)
-                    nStartVal = aSrcCell.mfValue;
-                else
-                    nStartVal = aSrcCell.mpFormula->GetValue();
+                const double nStartVal = (eCellType == CELLTYPE_VALUE ? aSrcCell.mfValue :
+                        aSrcCell.mpFormula->GetValue());
                 double nVal = nStartVal;
                 long nIndex = 0;
 
@@ -1734,11 +1832,11 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
 
                 sal_uInt16 nDayOfMonth = 0;
                 rInner = nIStart;
-                while (true)        // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
+                while (true)
                 {
                     if(!ColHidden(nCol) && !RowHidden(nRow))
                     {
-                        if (!bError && !bOverflow)
+                        if (!bError)
                         {
                             switch (eFillCmd)
                             {
@@ -1769,33 +1867,20 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
                                     }
                             }
 
-                            if (nStepValue >= 0)
-                            {
-                                if (nVal > nMaxValue)           // target value reached ?
-                                {
-                                    nVal = nMaxValue;
-                                    bOverflow = true;
-                                }
-                            }
-                            else
-                            {
-                                if (nVal < nMaxValue)
-                                {
-                                    nVal = nMaxValue;
-                                    bOverflow = true;
-                                }
-                            }
+                            if (!bError)
+                                bOverflow = isOverflow( nVal, nMaxValue, nStepValue, nStartVal, eFillCmd);
                         }
 
                         if (bError)
                             aCol[nCol].SetError(static_cast<SCROW>(nRow), FormulaError::NoValue);
-                        else if (bOverflow)
-                            aCol[nCol].SetError(static_cast<SCROW>(nRow), FormulaError::IllegalFPOperation);
-                        else
+                        else if (!bOverflow)
                             aCol[nCol].SetValue(static_cast<SCROW>(nRow), nVal);
+
+                        if (bAttribs && !bEntireArea && !bOverflow)
+                            SetPatternAreaCondFormat( nCol, nRow, nRow, *pSrcPattern, rCondFormatIndex);
                     }
 
-                    if (rInner == nIEnd)
+                    if (rInner == nIEnd || bOverflow)
                         break;
                     if (bPositive)
                     {
@@ -1832,7 +1917,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
                 short nHeadNoneTail = lcl_DecompValueString( aValue, nStringValue, &nMinDigits );
                 if ( nHeadNoneTail )
                 {
-                    double nStartVal = static_cast<double>(nStringValue);
+                    const double nStartVal = static_cast<double>(nStringValue);
                     double nVal = nStartVal;
                     long nIndex = 0;
                     bool bError = false;
@@ -1842,11 +1927,11 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
                                 static_cast<sal_Int32>(nStartVal));
 
                     rInner = nIStart;
-                    while (true)        // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
+                    while (true)
                     {
                         if(!ColHidden(nCol) && !RowHidden(nRow))
                         {
-                            if (!bError && !bOverflow)
+                            if (!bError)
                             {
                                 switch (eFillCmd)
                                 {
@@ -1871,29 +1956,13 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
                                         }
                                 }
 
-                                if (nStepValue >= 0)
-                                {
-                                    if (nVal > nMaxValue)           // target value reached ?
-                                    {
-                                        nVal = nMaxValue;
-                                        bOverflow = true;
-                                    }
-                                }
-                                else
-                                {
-                                    if (nVal < nMaxValue)
-                                    {
-                                        nVal = nMaxValue;
-                                        bOverflow = true;
-                                    }
-                                }
+                                if (!bError)
+                                    bOverflow = isOverflow( nVal, nMaxValue, nStepValue, nStartVal, eFillCmd);
                             }
 
                             if (bError)
                                 aCol[nCol].SetError(static_cast<SCROW>(nRow), FormulaError::NoValue);
-                            else if (bOverflow)
-                                aCol[nCol].SetError(static_cast<SCROW>(nRow), FormulaError::IllegalFPOperation);
-                            else
+                            else if (!bOverflow)
                             {
                                 nStringValue = static_cast<sal_Int32>(nVal);
                                 OUString aStr;
@@ -1914,10 +1983,17 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
                                     aCol[nCol].SetRawString(static_cast<SCROW>(nRow), aStr);
                                 }
                             }
+
+                            if (bAttribs && !bEntireArea && !bOverflow)
+                                SetPatternAreaCondFormat( nCol, nRow, nRow, *pSrcPattern, rCondFormatIndex);
                         }
 
-                        if (rInner == nIEnd) break;
-                        if (bPositive) ++rInner; else --rInner;
+                        if (rInner == nIEnd || bOverflow)
+                            break;
+                        if (bPositive)
+                            ++rInner;
+                        else
+                            --rInner;
                     }
                 }
                 if(pProgress)


More information about the Libreoffice-commits mailing list