[Libreoffice-commits] core.git: Branch 'libreoffice-5-3' - sc/source

Jean-Sebastien Bevilacqua realitix at gmail.com
Tue Mar 7 23:07:42 UTC 2017


 sc/source/core/data/column3.cxx |   69 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 65 insertions(+), 4 deletions(-)

New commits:
commit 3e4db9f12046255dbcd968b28c670cb83cf83418
Author: Jean-Sebastien Bevilacqua <realitix at gmail.com>
Date:   Thu Feb 9 09:30:56 2017 +0100

    tdf#101904 Fix Date deleting in SCalc
    
    Introduction
    ------------
    
    In SCalc, when you want to clear contents, a dialog box asks you the
    data type you want to delete. For example, if you select `Date & time`,
    only cells of type `Datetime` should be deleted in the selected area.
    
    Currently, this feature is not working for datetime type. To delete
    datetime cells, you must select `Numbers` type. Datetime type is seen
    as number.
    
    Context of this fix
    -------------------
    
    First, `DeleteAreaHandler::operator` function is called for each area
    to delete. In this context, area has a special meaning. An area is a
    group of consecutive cells (on column) of the same datatype (numeric,
    formula...).
    
    To locate area in the column, we use the `node.position` attribute which
    contains the row index of the cell (remember area can be only on one column)
    and `nDataSize` which contains the number of rows.
    
    How this fix works
    ------------------
    
    In `deleteNumeric` function, we loop through area rows to detect if cell
    contains a numeric value or a datetime value. To optimize performance,
    we don't delete cells one by one but we get a range of the same datatype.
    As long as datatype stays the same, we add current cell to a "sub-area"
    but as soon as datatype switches (datetime -> number or number -> datetime),
    we delete this sub-area. Finally, at the end of `deleteNumeric` function,
    we delete the last "sub-area".
    
    Note
    ----
    
    `deleteNumberOrDateTime` function deletes rows only if the corresponding
    flag in the dialog box is setted: `mbNumeric` for `Numbers` and
    `mbDateTime` for `Date & time`.
    
    Change-Id: I24c0b3c0a6195211af71aa18d867df82109fa941
    Reviewed-on: https://gerrit.libreoffice.org/34068
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Eike Rathke <erack at redhat.com>
    (cherry picked from commit 4575d7cf657ae291c427c2318eb4600cec2f12b7)
    Reviewed-on: https://gerrit.libreoffice.org/34956

diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 3af350d..73da282 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -541,21 +541,33 @@ class DeleteAreaHandler
     bool mbNumeric:1;
     bool mbString:1;
     bool mbFormula:1;
+    bool mbDateTime:1;
+    ScColumn& mrCol;
 
 public:
-    DeleteAreaHandler(ScDocument& rDoc, InsertDeleteFlags nDelFlag) :
+    DeleteAreaHandler(ScDocument& rDoc, InsertDeleteFlags nDelFlag, ScColumn& rCol) :
         mrDoc(rDoc),
         mbNumeric(nDelFlag & InsertDeleteFlags::VALUE),
         mbString(nDelFlag & InsertDeleteFlags::STRING),
-        mbFormula(nDelFlag & InsertDeleteFlags::FORMULA) {}
+        mbFormula(nDelFlag & InsertDeleteFlags::FORMULA),
+        mbDateTime(nDelFlag & InsertDeleteFlags::DATETIME),
+        mrCol(rCol) {}
 
     void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
     {
         switch (node.type)
         {
             case sc::element_type_numeric:
-                if (!mbNumeric)
+                // Numeric type target datetime and number, thus we have a dedicated function
+                if (!mbNumeric && !mbDateTime)
                     return;
+
+                // If numeric and datetime selected, delete full range
+                if (mbNumeric && mbDateTime)
+                    break;
+
+                deleteNumeric(node, nOffset, nDataSize);
+                return;
             break;
             case sc::element_type_string:
             case sc::element_type_edittext:
@@ -587,6 +599,55 @@ public:
         maDeleteRanges.set(nRow1, nRow2, true);
     }
 
+    void deleteNumeric(const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
+    {
+        size_t nStart = node.position + nOffset;
+        size_t nElements = 1;
+        bool bLastTypeDateTime = isDateTime(nStart); // true = datetime, false = numeric
+        size_t nCount = nStart + nDataSize;
+
+        for (size_t i = nStart + 1; i < nCount; i++)
+        {
+            bool bIsDateTime = isDateTime(i);
+
+            // same type as previous
+            if (bIsDateTime == bLastTypeDateTime)
+            {
+                nElements++;
+            }
+            // type switching
+            else
+            {
+                deleteNumberOrDateTime(nStart, nStart + nElements - 1, bLastTypeDateTime);
+                nStart += nElements;
+                nElements = 1;
+            }
+
+            bLastTypeDateTime = bIsDateTime;
+        }
+
+        // delete last cells
+        deleteNumberOrDateTime(nStart, nStart + nElements - 1, bLastTypeDateTime);
+    }
+
+    void deleteNumberOrDateTime(SCROW nRow1, SCROW nRow2, bool dateTime)
+    {
+        if (!dateTime && !mbNumeric) // numeric flag must be selected
+            return;
+        if (dateTime && !mbDateTime) // datetime flag must be selected
+            return;
+        maDeleteRanges.set(nRow1, nRow2, true);
+    }
+
+    bool isDateTime(size_t position)
+    {
+        short nType = mrDoc.GetFormatTable()->GetType(static_cast<const SfxUInt32Item&>(
+                          mrCol.GetAttr(position, ATTR_VALUE_FORMAT)).GetValue());
+
+        return (nType == css::util::NumberFormat::DATE) || (nType == css::util::NumberFormat::TIME) ||
+               (nType == css::util::NumberFormat::DATETIME);
+    }
+
     void endFormulas()
     {
         mrDoc.EndListeningFormulaCells(maFormulaCells);
@@ -639,7 +700,7 @@ void ScColumn::DeleteCells(
     sc::SingleColumnSpanSet& rDeleted )
 {
     // Determine which cells to delete based on the deletion flags.
-    DeleteAreaHandler aFunc(*pDocument, nDelFlag);
+    DeleteAreaHandler aFunc(*pDocument, nDelFlag, *this);
     sc::CellStoreType::iterator itPos = maCells.position(rBlockPos.miCellPos, nRow1).first;
     sc::ProcessBlock(itPos, maCells, aFunc, nRow1, nRow2);
     aFunc.endFormulas(); // Have the formula cells stop listening.


More information about the Libreoffice-commits mailing list