sc/source/core/data/column3.cxx | 69 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 4 deletions(-)
New commits: commit 4575d7cf657ae291c427c2318eb4600cec2f12b7 Author: Jean-Sebastien Bevilacqua <reali...@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 <c...@libreoffice.org> Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Eike Rathke <er...@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. _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits