From 1c8c6a48af625e901ef9658298becbf99db3336e Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Sun, 12 Jun 2022 17:19:28 +0800 Subject: [PATCH] Spreadsheet: fix range selection --- src/Mod/Spreadsheet/App/PropertySheet.cpp | 5 +++ src/Mod/Spreadsheet/App/PropertySheet.h | 2 + src/Mod/Spreadsheet/Gui/SheetTableView.cpp | 51 +++++++++++++++++++++- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/Mod/Spreadsheet/App/PropertySheet.cpp b/src/Mod/Spreadsheet/App/PropertySheet.cpp index 7a793cfbd7..3be4fe1c65 100644 --- a/src/Mod/Spreadsheet/App/PropertySheet.cpp +++ b/src/Mod/Spreadsheet/App/PropertySheet.cpp @@ -1975,3 +1975,8 @@ const boost::any PropertySheet::getPathValue(const App::ObjectIdentifier & path) return boost::any(); return path.getValue(); } + +bool PropertySheet::hasSpan() const +{ + return !mergedCells.empty(); +} diff --git a/src/Mod/Spreadsheet/App/PropertySheet.h b/src/Mod/Spreadsheet/App/PropertySheet.h index 6138d8753e..c1f2f1eed6 100644 --- a/src/Mod/Spreadsheet/App/PropertySheet.h +++ b/src/Mod/Spreadsheet/App/PropertySheet.h @@ -153,6 +153,8 @@ public: void getSpans(App::CellAddress address, int &rows, int &cols) const; + bool hasSpan() const; + App::CellAddress getAnchor(App::CellAddress address) const; bool isMergedCell(App::CellAddress address) const; diff --git a/src/Mod/Spreadsheet/Gui/SheetTableView.cpp b/src/Mod/Spreadsheet/Gui/SheetTableView.cpp index ca1d6bdf7a..a6b3d73baa 100644 --- a/src/Mod/Spreadsheet/Gui/SheetTableView.cpp +++ b/src/Mod/Spreadsheet/Gui/SheetTableView.cpp @@ -250,8 +250,55 @@ void SheetTableView::cellProperties() std::vector SheetTableView::selectedRanges() const { std::vector result; - for (const auto &sel : selectionModel()->selection()) - result.emplace_back(sel.top(), sel.left(), sel.bottom(), sel.right()); + + if (!sheet->getCells()->hasSpan()) { + for (const auto &sel : selectionModel()->selection()) + result.emplace_back(sel.top(), sel.left(), sel.bottom(), sel.right()); + } else { + // If there is spanning cell, QItemSelection returned by + // QTableView::selection() does not merge selected indices into ranges. + // So we have to do it by ourselves. Qt records selection in the order + // of column first and then row. + // + // Note that there will always be ambiguous cases with the available + // information, where multiple user selected ranges are merged + // together. For example, consecutive single column selections that + // form a rectangle will be merged together, but single row selections + // will not be merged. + for (const auto &sel : selectionModel()->selection()) { + if (!result.empty() && sel.bottom() == sel.top() && sel.right() == sel.left()) { + auto &last = result.back(); + if (last.colCount() == 1 + && last.from().col() == sel.left() + && sel.top() == last.to().row() + 1) + { + // This is the case of rectangle selection. We keep + // accumulating the last column, and try to merge the + // column to previous range whenever possible. + last = Range(last.from(), CellAddress(sel.top(), sel.left())); + if (result.size() > 1) { + auto &secondLast = result[result.size()-2]; + if (secondLast.to().col() + 1 == last.to().col() + && secondLast.from().row() == last.from().row() + && secondLast.rowCount() == last.rowCount()) { + secondLast = Range(secondLast.from(), last.to()); + result.pop_back(); + } + } + continue; + } + else if (last.rowCount() == 1 + && last.from().row() == sel.top() + && last.to().col() + 1 == sel.left()) + { + // This is the case of single row selection + last = Range(last.from(), CellAddress(sel.top(), sel.left())); + continue; + } + } + result.emplace_back(sel.top(), sel.left(), sel.bottom(), sel.right()); + } + } return result; }