[Libreoffice-commits] core.git: sc/source
Jean-Sebastien Bevilacqua
realitix at gmail.com
Tue Mar 7 17:41:36 UTC 2017
sc/source/core/data/column3.cxx | 69 +++++++++++++++++++++++++++++++++++++---
1 file changed, 65 insertions(+), 4 deletions(-)
New commits:
commit 4575d7cf657ae291c427c2318eb4600cec2f12b7
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>
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 9bd32c0..a143f88 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -539,21 +539,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:
@@ -585,6 +597,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);
@@ -637,7 +698,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