diff --git a/base/src/test/user_model/mod.rs b/base/src/test/user_model/mod.rs index 77d649b..e9912bb 100644 --- a/base/src/test/user_model/mod.rs +++ b/base/src/test/user_model/mod.rs @@ -16,6 +16,7 @@ mod test_paste_csv; mod test_rename_sheet; mod test_row_column; mod test_sheet_state; +mod test_sheets_undo_redo; mod test_styles; mod test_to_from_bytes; mod test_undo_redo; diff --git a/base/src/test/user_model/test_add_delete_sheets.rs b/base/src/test/user_model/test_add_delete_sheets.rs index c227316..c35a430 100644 --- a/base/src/test/user_model/test_add_delete_sheets.rs +++ b/base/src/test/user_model/test_add_delete_sheets.rs @@ -25,9 +25,6 @@ fn add_undo_redo() { assert_eq!(model.get_formatted_cell_value(2, 1, 1), Ok("6".to_string())); model.delete_sheet(1).unwrap(); - - assert!(!model.can_undo()); - assert!(!model.can_redo()); } #[test] diff --git a/base/src/test/user_model/test_sheets_undo_redo.rs b/base/src/test/user_model/test_sheets_undo_redo.rs new file mode 100644 index 0000000..a2720de --- /dev/null +++ b/base/src/test/user_model/test_sheets_undo_redo.rs @@ -0,0 +1,52 @@ +#![allow(clippy::unwrap_used)] + +use crate::test::util::new_empty_model; +use crate::UserModel; + +#[test] +fn basic_undo_redo() { + let model = new_empty_model(); + let mut model = UserModel::from_model(model); + assert_eq!(model.get_selected_sheet(), 0); + + model.new_sheet().unwrap(); + assert_eq!(model.get_selected_sheet(), 1); + model.undo().unwrap(); + assert_eq!(model.get_selected_sheet(), 0); + { + let props = model.get_worksheets_properties(); + assert_eq!(props.len(), 1); + let view = model.get_selected_view(); + assert_eq!(view.sheet, 0); + } + + model.redo().unwrap(); + assert_eq!(model.get_selected_sheet(), 1); + { + let props = model.get_worksheets_properties(); + assert_eq!(props.len(), 2); + let view = model.get_selected_view(); + + assert_eq!(view.sheet, 1); + } +} + +#[test] +fn delete_undo() { + let model = new_empty_model(); + let mut model = UserModel::from_model(model); + assert_eq!(model.get_selected_sheet(), 0); + + model.new_sheet().unwrap(); + assert_eq!(model.get_selected_sheet(), 1); + model.set_user_input(1, 1, 1, "42").unwrap(); + model.set_user_input(1, 1, 2, "=A1*2").unwrap(); + model.delete_sheet(1).unwrap(); + + assert_eq!(model.get_selected_sheet(), 0); + + model.undo().unwrap(); + assert_eq!(model.get_selected_sheet(), 1); + model.redo().unwrap(); + assert_eq!(model.get_selected_sheet(), 0); +} diff --git a/base/src/user_model/common.rs b/base/src/user_model/common.rs index 8a2eebe..e3b339e 100644 --- a/base/src/user_model/common.rs +++ b/base/src/user_model/common.rs @@ -412,9 +412,13 @@ impl UserModel { /// See also: /// * [Model::delete_sheet] pub fn delete_sheet(&mut self, sheet: u32) -> Result<(), String> { - self.push_diff_list(vec![Diff::DeleteSheet { sheet }]); - // There is no coming back - self.history.clear(); + let worksheet = self.model.workbook.worksheet(sheet)?; + + self.push_diff_list(vec![Diff::DeleteSheet { + sheet, + old_data: Box::new(worksheet.clone()), + }]); + let sheet_count = self.model.workbook.worksheets.len() as u32; // If we are deleting the last sheet we need to change the selected sheet if sheet == sheet_count - 1 && sheet_count > 1 { @@ -1972,11 +1976,11 @@ impl UserModel { new_value: _, old_value, } => self.model.set_frozen_columns(*sheet, *old_value)?, - Diff::DeleteSheet { sheet: _ } => { - // do nothing - } Diff::NewSheet { index, name: _ } => { self.model.delete_sheet(*index)?; + if *index > 0 { + self.set_selected_sheet(*index - 1)?; + } } Diff::RenameSheet { index, @@ -2043,6 +2047,32 @@ impl UserModel { self.model .set_cell_style(*sheet, *row, *column, old_style)?; } + Diff::DeleteSheet { sheet, old_data } => { + needs_evaluation = true; + let sheet_name = &old_data.name.clone(); + let sheet_index = *sheet; + let sheet_id = old_data.sheet_id; + self.model + .insert_sheet(sheet_name, sheet_index, Some(sheet_id))?; + let worksheet = self.model.workbook.worksheet_mut(*sheet)?; + for (row, row_data) in &old_data.sheet_data { + for (column, cell) in row_data { + worksheet.update_cell(*row, *column, cell.clone())?; + } + } + worksheet.rows = old_data.rows.clone(); + worksheet.cols = old_data.cols.clone(); + worksheet.show_grid_lines = old_data.show_grid_lines; + worksheet.frozen_columns = old_data.frozen_columns; + worksheet.frozen_rows = old_data.frozen_rows; + worksheet.state = old_data.state.clone(); + worksheet.color = old_data.color.clone(); + worksheet.merge_cells = old_data.merge_cells.clone(); + worksheet.shared_formulas = old_data.shared_formulas.clone(); + self.model.reset_parsed_structures(); + + self.set_selected_sheet(sheet_index)?; + } } } if needs_evaluation { @@ -2145,9 +2175,15 @@ impl UserModel { new_value, old_value: _, } => self.model.set_frozen_columns(*sheet, *new_value)?, - Diff::DeleteSheet { sheet } => self.model.delete_sheet(*sheet)?, + Diff::DeleteSheet { sheet, old_data: _ } => { + self.model.delete_sheet(*sheet)?; + if *sheet > 0 { + self.set_selected_sheet(*sheet - 1)?; + } + } Diff::NewSheet { index, name } => { self.model.insert_sheet(name, *index, None)?; + self.set_selected_sheet(*index)?; } Diff::RenameSheet { index, diff --git a/base/src/user_model/history.rs b/base/src/user_model/history.rs index 7516e30..c6f7c6b 100644 --- a/base/src/user_model/history.rs +++ b/base/src/user_model/history.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use bitcode::{Decode, Encode}; -use crate::types::{Cell, Col, Row, SheetState, Style}; +use crate::types::{Cell, Col, Row, SheetState, Style, Worksheet}; #[derive(Clone, Encode, Decode)] pub(crate) struct RowData { @@ -83,6 +83,10 @@ pub(crate) enum Diff { column: i32, old_data: Box, }, + DeleteSheet { + sheet: u32, + old_data: Box, + }, SetFrozenRowsCount { sheet: u32, new_value: i32, @@ -93,9 +97,6 @@ pub(crate) enum Diff { new_value: i32, old_value: i32, }, - DeleteSheet { - sheet: u32, - }, NewSheet { index: u32, name: String, @@ -174,11 +175,6 @@ impl History { None => None, } } - - pub fn clear(&mut self) { - self.redo_stack = vec![]; - self.undo_stack = vec![]; - } } #[derive(Clone, Encode, Decode)] diff --git a/webapp/IronCalc/src/locale/en_us.json b/webapp/IronCalc/src/locale/en_us.json index 0a45b81..336e02b 100644 --- a/webapp/IronCalc/src/locale/en_us.json +++ b/webapp/IronCalc/src/locale/en_us.json @@ -71,7 +71,7 @@ }, "sheet_delete": { "title": "Are you sure?", - "message": "The sheet '{{sheetName}}' will be permanently deleted. This action cannot be undone.", + "message": "The sheet '{{sheetName}}' will be deleted.", "confirm": "Yes, delete sheet", "cancel": "Cancel" },