From 356eca7e339f87177fc0b3bb5f0066bd120f3753 Mon Sep 17 00:00:00 2001 From: martinfalisse Date: Mon, 11 Apr 2022 17:05:23 +0200 Subject: [PATCH] Spreadsheet: Implement undo functionality where missing Implement undo/redo functionality in the Spreadsheet application for the "extend" function, the drag-and-drop function, and when copying and pasting. --- .../Applications/Spreadsheet/Spreadsheet.cpp | 17 ++++++++++++----- Userland/Applications/Spreadsheet/Spreadsheet.h | 2 +- .../Applications/Spreadsheet/SpreadsheetModel.h | 1 + .../Spreadsheet/SpreadsheetView.cpp | 10 ++++++++-- .../Spreadsheet/SpreadsheetWidget.cpp | 7 ++++++- 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/Userland/Applications/Spreadsheet/Spreadsheet.cpp b/Userland/Applications/Spreadsheet/Spreadsheet.cpp index bf474d370f..995a1be233 100644 --- a/Userland/Applications/Spreadsheet/Spreadsheet.cpp +++ b/Userland/Applications/Spreadsheet/Spreadsheet.cpp @@ -292,12 +292,13 @@ Position Sheet::offset_relative_to(Position const& base, Position const& offset, return { new_column, new_row }; } -void Sheet::copy_cells(Vector from, Vector to, Optional resolve_relative_to, CopyOperation copy_operation) +Vector Sheet::copy_cells(Vector from, Vector to, Optional resolve_relative_to, CopyOperation copy_operation) { + Vector cell_changes; // Disallow misaligned copies. if (to.size() > 1 && from.size() != to.size()) { dbgln("Cannot copy {} cells to {} cells", from.size(), to.size()); - return; + return cell_changes; } Vector target_cells; @@ -307,16 +308,20 @@ void Sheet::copy_cells(Vector from, Vector to, Optionalset_data(""); + cell_changes.append(CellChange(target_cell, previous_data)); + if (copy_operation == CopyOperation::Cut && !target_cells.contains_slow(source_position)) { + cell_changes.append(CellChange(*source_cell, source_cell->data())); + source_cell->set_data(""); + } }; // Resolve each index as relative to the first index offset from the selection. @@ -359,6 +364,8 @@ void Sheet::copy_cells(Vector from, Vector to, Optional Sheet::from_json(JsonObject const& object, Workbook& workbook) diff --git a/Userland/Applications/Spreadsheet/Spreadsheet.h b/Userland/Applications/Spreadsheet/Spreadsheet.h index 9bab004df0..1e17886582 100644 --- a/Userland/Applications/Spreadsheet/Spreadsheet.h +++ b/Userland/Applications/Spreadsheet/Spreadsheet.h @@ -135,7 +135,7 @@ public: Cut }; - void copy_cells(Vector from, Vector to, Optional resolve_relative_to = {}, CopyOperation copy_operation = CopyOperation::Copy); + Vector copy_cells(Vector from, Vector to, Optional resolve_relative_to = {}, CopyOperation copy_operation = CopyOperation::Copy); /// Gives the bottom-right corner of the smallest bounding box containing all the written data, optionally limited to the given column. Position written_data_bounds(Optional column_index = {}) const; diff --git a/Userland/Applications/Spreadsheet/SpreadsheetModel.h b/Userland/Applications/Spreadsheet/SpreadsheetModel.h index 708097e5df..1177e480b2 100644 --- a/Userland/Applications/Spreadsheet/SpreadsheetModel.h +++ b/Userland/Applications/Spreadsheet/SpreadsheetModel.h @@ -30,6 +30,7 @@ public: void update(); Function on_cell_data_change; + Function)> on_cells_data_change; private: explicit SheetModel(Sheet& sheet) diff --git a/Userland/Applications/Spreadsheet/SpreadsheetView.cpp b/Userland/Applications/Spreadsheet/SpreadsheetView.cpp index 0f2ce5765e..105fdf0036 100644 --- a/Userland/Applications/Spreadsheet/SpreadsheetView.cpp +++ b/Userland/Applications/Spreadsheet/SpreadsheetView.cpp @@ -220,6 +220,7 @@ void InfinitelyScrollableTableView::mouseup_event(GUI::MouseEvent& event) Vector from; Position position { (size_t)m_target_cell.column(), (size_t)m_target_cell.row() }; from.append(position); + Vector cell_changes; selection().for_each_index([&](auto& index) { if (index == m_starting_selection_index) return; @@ -227,8 +228,11 @@ void InfinitelyScrollableTableView::mouseup_event(GUI::MouseEvent& event) Vector to; Position position { (size_t)index.column(), (size_t)index.row() }; to.append(position); - sheet.copy_cells(from, to); + auto cell_change = sheet.copy_cells(from, to); + cell_changes.extend(cell_change); }); + if (static_cast(*this->model()).on_cells_data_change) + static_cast(*this->model()).on_cells_data_change(cell_changes); update(); } @@ -425,7 +429,9 @@ SpreadsheetView::SpreadsheetView(Sheet& sheet) return; auto first_position = source_positions.take_first(); - m_sheet->copy_cells(move(source_positions), move(target_positions), first_position, Spreadsheet::Sheet::CopyOperation::Cut); + auto cell_changes = m_sheet->copy_cells(move(source_positions), move(target_positions), first_position, Spreadsheet::Sheet::CopyOperation::Cut); + if (model()->on_cells_data_change) + model()->on_cells_data_change(cell_changes); return; } diff --git a/Userland/Applications/Spreadsheet/SpreadsheetWidget.cpp b/Userland/Applications/Spreadsheet/SpreadsheetWidget.cpp index bf99c09810..d67897ef0d 100644 --- a/Userland/Applications/Spreadsheet/SpreadsheetWidget.cpp +++ b/Userland/Applications/Spreadsheet/SpreadsheetWidget.cpp @@ -193,7 +193,8 @@ SpreadsheetWidget::SpreadsheetWidget(GUI::Window& parent_window, NonnullRefPtrVe return; auto first_position = source_positions.take_first(); - sheet.copy_cells(move(source_positions), move(target_positions), first_position, action == "cut" ? Spreadsheet::Sheet::CopyOperation::Cut : Spreadsheet::Sheet::CopyOperation::Copy); + auto cell_changes = sheet.copy_cells(move(source_positions), move(target_positions), first_position, action == "cut" ? Spreadsheet::Sheet::CopyOperation::Cut : Spreadsheet::Sheet::CopyOperation::Copy); + undo_stack().push(make(cell_changes)); } else { for (auto& cell : sheet.selected_cells()) sheet.ensure(cell).set_data(StringView { data.data.data(), data.data.size() }); @@ -284,6 +285,10 @@ void SpreadsheetWidget::setup_tabs(NonnullRefPtrVector new_sheets) undo_stack().push(make(cell, previous_data)); window()->set_modified(true); }; + new_view.model()->on_cells_data_change = [&](Vector cell_changes) { + undo_stack().push(make(cell_changes)); + window()->set_modified(true); + }; new_view.on_selection_changed = [&](Vector&& selection) { auto* sheet_ptr = current_worksheet_if_available(); // How did this even happen?