summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Sebastien Bevilacqua <realitix@gmail.com>2017-02-09 09:30:56 +0100
committerEike Rathke <erack@redhat.com>2017-03-07 23:07:11 +0000
commit3e4db9f12046255dbcd968b28c670cb83cf83418 (patch)
treec90f6877d4ee4d907ac43ee128bc6c1d8746111b
parentdb5060fcff010694e362674c87038d4abfae838e (diff)
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@libreoffice.org> Reviewed-by: Eike Rathke <erack@redhat.com> Tested-by: Eike Rathke <erack@redhat.com> (cherry picked from commit 4575d7cf657ae291c427c2318eb4600cec2f12b7) Reviewed-on: https://gerrit.libreoffice.org/34956
-rw-r--r--sc/source/core/data/column3.cxx69
1 files changed, 65 insertions, 4 deletions
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 3af350d2aaf9..73da282cc1f2 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.