From 2d23f5d4e44be745e20a749321af9173d04e6666 Mon Sep 17 00:00:00 2001 From: BrianHung Date: Fri, 11 Jul 2025 09:09:44 -0700 Subject: [PATCH] feat: insert delete rows cols --- base/src/user_model/common.rs | 122 ++++++++++++++++++++++++++++++++++ bindings/wasm/src/lib.rs | 38 +++++++++++ bindings/wasm/tests/test.mjs | 42 ++++++++++++ 3 files changed, 202 insertions(+) diff --git a/base/src/user_model/common.rs b/base/src/user_model/common.rs index dcb4269..ea1ee9e 100644 --- a/base/src/user_model/common.rs +++ b/base/src/user_model/common.rs @@ -961,6 +961,128 @@ impl UserModel { Ok(()) } + /// Inserts several rows at once + pub fn insert_rows(&mut self, sheet: u32, row: i32, row_count: i32) -> Result<(), String> { + let mut diff_list = Vec::new(); + for r in 0..row_count { + diff_list.push(Diff::InsertRow { + sheet, + row: row + r, + }); + } + self.push_diff_list(diff_list); + self.model.insert_rows(sheet, row, row_count)?; + self.evaluate_if_not_paused(); + Ok(()) + } + + /// Inserts several columns at once + pub fn insert_columns( + &mut self, + sheet: u32, + column: i32, + column_count: i32, + ) -> Result<(), String> { + let mut diff_list = Vec::new(); + for c in 0..column_count { + diff_list.push(Diff::InsertColumn { + sheet, + column: column + c, + }); + } + self.push_diff_list(diff_list); + self.model.insert_columns(sheet, column, column_count)?; + self.evaluate_if_not_paused(); + Ok(()) + } + + /// Deletes several rows at once + pub fn delete_rows(&mut self, sheet: u32, row: i32, row_count: i32) -> Result<(), String> { + let diff_list = { + let worksheet = self.model.workbook.worksheet(sheet)?; + let mut diff_list = Vec::new(); + for r in row..row + row_count { + let mut row_data = None; + for rd in &worksheet.rows { + if rd.r == r { + row_data = Some(rd.clone()); + break; + } + } + let data = match worksheet.sheet_data.get(&r) { + Some(s) => s.clone(), + None => return Err(format!("Row number '{r}' is not valid.")), + }; + diff_list.push(Diff::DeleteRow { + sheet, + row: r, + old_data: Box::new(RowData { + row: row_data, + data, + }), + }); + } + diff_list + }; + self.push_diff_list(diff_list); + self.model.delete_rows(sheet, row, row_count)?; + self.evaluate_if_not_paused(); + Ok(()) + } + + /// Deletes several columns at once + pub fn delete_columns( + &mut self, + sheet: u32, + column: i32, + column_count: i32, + ) -> Result<(), String> { + let diff_list = { + let worksheet = self.model.workbook.worksheet(sheet)?; + let mut diff_list = Vec::new(); + for c in column..column + column_count { + if !is_valid_column_number(c) { + return Err(format!("Column number '{c}' is not valid.")); + } + + let mut column_data = None; + for col in &worksheet.cols { + if c >= col.min && c <= col.max { + column_data = Some(Col { + min: c, + max: c, + width: col.width, + custom_width: col.custom_width, + style: col.style, + }); + break; + } + } + + let mut data = HashMap::new(); + for (row_idx, row_data) in &worksheet.sheet_data { + if let Some(cell) = row_data.get(&c) { + data.insert(*row_idx, cell.clone()); + } + } + + diff_list.push(Diff::DeleteColumn { + sheet, + column: c, + old_data: Box::new(ColumnData { + column: column_data, + data, + }), + }); + } + diff_list + }; + self.push_diff_list(diff_list); + self.model.delete_columns(sheet, column, column_count)?; + self.evaluate_if_not_paused(); + Ok(()) + } + /// Sets the width of a group of columns in a single diff list /// /// See also: diff --git a/bindings/wasm/src/lib.rs b/bindings/wasm/src/lib.rs index a67e59f..e67324c 100644 --- a/bindings/wasm/src/lib.rs +++ b/bindings/wasm/src/lib.rs @@ -216,6 +216,44 @@ impl Model { self.model.delete_column(sheet, column).map_err(to_js_error) } + #[wasm_bindgen(js_name = "insertRows")] + pub fn insert_rows(&mut self, sheet: u32, row: i32, row_count: i32) -> Result<(), JsError> { + self.model + .insert_rows(sheet, row, row_count) + .map_err(to_js_error) + } + + #[wasm_bindgen(js_name = "insertColumns")] + pub fn insert_columns( + &mut self, + sheet: u32, + column: i32, + column_count: i32, + ) -> Result<(), JsError> { + self.model + .insert_columns(sheet, column, column_count) + .map_err(to_js_error) + } + + #[wasm_bindgen(js_name = "deleteRows")] + pub fn delete_rows(&mut self, sheet: u32, row: i32, row_count: i32) -> Result<(), JsError> { + self.model + .delete_rows(sheet, row, row_count) + .map_err(to_js_error) + } + + #[wasm_bindgen(js_name = "deleteColumns")] + pub fn delete_columns( + &mut self, + sheet: u32, + column: i32, + column_count: i32, + ) -> Result<(), JsError> { + self.model + .delete_columns(sheet, column, column_count) + .map_err(to_js_error) + } + #[wasm_bindgen(js_name = "setRowsHeight")] pub fn set_rows_height( &mut self, diff --git a/bindings/wasm/tests/test.mjs b/bindings/wasm/tests/test.mjs index 3746699..99dd0f6 100644 --- a/bindings/wasm/tests/test.mjs +++ b/bindings/wasm/tests/test.mjs @@ -130,5 +130,47 @@ test("autofill", () => { assert.strictEqual(result, "23"); }); +test('insertRows shifts cells', () => { + const model = new Model('Workbook1', 'en', 'UTC'); + model.setUserInput(0, 1, 1, '42'); + model.insertRows(0, 1, 1); + + assert.strictEqual(model.getCellContent(0, 1, 1), ''); + assert.strictEqual(model.getCellContent(0, 2, 1), '42'); +}); + +test('insertColumns shifts cells', () => { + const model = new Model('Workbook1', 'en', 'UTC'); + model.setUserInput(0, 1, 1, 'A'); + model.setUserInput(0, 1, 2, 'B'); + + model.insertColumns(0, 2, 1); + + assert.strictEqual(model.getCellContent(0, 1, 2), ''); + assert.strictEqual(model.getCellContent(0, 1, 3), 'B'); +}); + +test('deleteRows removes cells', () => { + const model = new Model('Workbook1', 'en', 'UTC'); + model.setUserInput(0, 1, 1, '1'); + model.setUserInput(0, 2, 1, '2'); + + model.deleteRows(0, 1, 1); + + assert.strictEqual(model.getCellContent(0, 1, 1), '2'); + assert.strictEqual(model.getCellContent(0, 2, 1), ''); +}); + +test('deleteColumns removes cells', () => { + const model = new Model('Workbook1', 'en', 'UTC'); + model.setUserInput(0, 1, 1, 'A'); + model.setUserInput(0, 1, 2, 'B'); + + model.deleteColumns(0, 1, 1); + + assert.strictEqual(model.getCellContent(0, 1, 1), 'B'); + assert.strictEqual(model.getCellContent(0, 1, 2), ''); +}); +