diff options
author | Jean-Sebastien Bevilacqua <realitix@gmail.com> | 2017-02-09 09:30:56 +0100 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2017-03-07 17:41:00 +0000 |
commit | 4575d7cf657ae291c427c2318eb4600cec2f12b7 (patch) | |
tree | c400149909586e2680a0c76cf100111ae5e30830 | |
parent | 27f89f08cf4086802ce67f12389414bef6ab64ca (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>
-rw-r--r-- | sc/source/core/data/column3.cxx | 69 |
1 files changed, 65 insertions, 4 deletions
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index 9bd32c0aec8c..a143f88bd0b4 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. |