From 4095b7db6e0a63d50682b78417ba63086c85b490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Hatcher?= Date: Sun, 16 Feb 2025 09:06:18 +0100 Subject: [PATCH] UPDATE[API rename]: set_column_with => set_columns_with Similarly set_row_height => set_rows_height --- .../test/user_model/test_add_delete_sheets.rs | 2 +- base/src/test/user_model/test_column_style.rs | 8 +-- .../test_delete_row_column_formatting.rs | 6 +- base/src/test/user_model/test_diff_queue.rs | 8 +-- base/src/test/user_model/test_general.rs | 4 +- base/src/test/user_model/test_row_column.rs | 4 +- .../src/test/user_model/test_to_from_bytes.rs | 2 +- base/src/user_model/common.rs | 62 +++++++++++++------ bindings/nodejs/src/user_model.rs | 24 +++++-- bindings/wasm/src/lib.rs | 46 ++++++++++++-- bindings/wasm/tests/test.mjs | 10 +-- webapp/IronCalc/src/components/worksheet.tsx | 30 ++++----- xlsx/tests/test.rs | 2 +- 13 files changed, 134 insertions(+), 74 deletions(-) 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 c35a430..21fa929 100644 --- a/base/src/test/user_model/test_add_delete_sheets.rs +++ b/base/src/test/user_model/test_add_delete_sheets.rs @@ -9,7 +9,7 @@ fn add_undo_redo() { model.set_user_input(1, 1, 1, "=1 + 1").unwrap(); model.set_user_input(1, 1, 2, "=A1*3").unwrap(); model - .set_column_width(1, 5, 5.0 * DEFAULT_COLUMN_WIDTH) + .set_columns_width(1, 5, 5, 5.0 * DEFAULT_COLUMN_WIDTH) .unwrap(); model.new_sheet().unwrap(); model.set_user_input(2, 1, 1, "=Sheet2!B1").unwrap(); diff --git a/base/src/test/user_model/test_column_style.rs b/base/src/test/user_model/test_column_style.rs index 51aaad4..69d1b3f 100644 --- a/base/src/test/user_model/test_column_style.rs +++ b/base/src/test/user_model/test_column_style.rs @@ -39,7 +39,7 @@ fn column_width() { // change the column width and check it does not affect the style model - .set_column_width(0, 7, DEFAULT_COLUMN_WIDTH * 2.0) + .set_columns_width(0, 7, 7, DEFAULT_COLUMN_WIDTH * 2.0) .unwrap(); let style = model.get_cell_style(0, 109, 7).unwrap(); assert!(style.font.b); @@ -241,7 +241,7 @@ fn width_column_undo() { let mut model = UserModel::new_empty("model", "en", "UTC").unwrap(); model - .set_column_width(0, 7, DEFAULT_COLUMN_WIDTH * 2.0) + .set_columns_width(0, 7, 7, DEFAULT_COLUMN_WIDTH * 2.0) .unwrap(); let column_g_range = Area { @@ -267,7 +267,7 @@ fn width_column_undo() { fn height_row_undo() { let mut model = UserModel::new_empty("model", "en", "UTC").unwrap(); model - .set_row_height(0, 10, DEFAULT_ROW_HEIGHT * 2.0) + .set_rows_height(0, 10, 10, DEFAULT_ROW_HEIGHT * 2.0) .unwrap(); let row_10_range = Area { @@ -446,7 +446,7 @@ fn column_style_then_width() { .update_range_style(&column_g_range, "fill.bg_color", "#555666") .unwrap(); model - .set_column_width(0, 7, DEFAULT_COLUMN_WIDTH * 2.0) + .set_columns_width(0, 7, 7, DEFAULT_COLUMN_WIDTH * 2.0) .unwrap(); // Check column width worked: diff --git a/base/src/test/user_model/test_delete_row_column_formatting.rs b/base/src/test/user_model/test_delete_row_column_formatting.rs index fc6248a..658356b 100644 --- a/base/src/test/user_model/test_delete_row_column_formatting.rs +++ b/base/src/test/user_model/test_delete_row_column_formatting.rs @@ -105,7 +105,7 @@ fn delete_column_formatting() { fn column_width() { let mut model = UserModel::new_empty("model", "en", "UTC").unwrap(); model - .set_column_width(0, 7, DEFAULT_COLUMN_WIDTH * 2.0) + .set_columns_width(0, 7, 7, DEFAULT_COLUMN_WIDTH * 2.0) .unwrap(); let column_g_range = Area { @@ -145,7 +145,7 @@ fn column_width() { fn column_row_style_undo() { let mut model = UserModel::new_empty("model", "en", "UTC").unwrap(); model - .set_column_width(0, 7, DEFAULT_COLUMN_WIDTH * 2.0) + .set_columns_width(0, 7, 7, DEFAULT_COLUMN_WIDTH * 2.0) .unwrap(); let column_g_range = Area { @@ -228,7 +228,7 @@ fn column_row_row_height_undo() { .unwrap(); model - .set_row_height(0, 3, DEFAULT_ROW_HEIGHT * 2.0) + .set_rows_height(0, 3, 3, DEFAULT_ROW_HEIGHT * 2.0) .unwrap(); model diff --git a/base/src/test/user_model/test_diff_queue.rs b/base/src/test/user_model/test_diff_queue.rs index 32e489c..8449cad 100644 --- a/base/src/test/user_model/test_diff_queue.rs +++ b/base/src/test/user_model/test_diff_queue.rs @@ -10,7 +10,7 @@ use crate::{ fn send_queue() { let mut model1 = UserModel::from_model(new_empty_model()); let width = model1.get_column_width(0, 3).unwrap() * 3.0; - model1.set_column_width(0, 3, width).unwrap(); + model1.set_columns_width(0, 3, 3, width).unwrap(); model1.set_user_input(0, 1, 2, "Hello IronCalc!").unwrap(); let send_queue = model1.flush_send_queue(); @@ -34,7 +34,7 @@ fn apply_external_diffs_wrong_str() { fn queue_undo_redo() { let mut model1 = UserModel::from_model(new_empty_model()); let width = model1.get_column_width(0, 3).unwrap() * 3.0; - model1.set_column_width(0, 3, width).unwrap(); + model1.set_columns_width(0, 3, 3, width).unwrap(); model1.set_user_input(0, 1, 2, "Hello IronCalc!").unwrap(); assert!(model1.undo().is_ok()); assert!(model1.redo().is_ok()); @@ -57,8 +57,8 @@ fn queue_undo_redo_multiple() { // do a bunch of things model1.set_frozen_columns_count(0, 5).unwrap(); model1.set_frozen_rows_count(0, 6).unwrap(); - model1.set_column_width(0, 7, 300.0).unwrap(); - model1.set_row_height(0, 23, 123.0).unwrap(); + model1.set_columns_width(0, 7, 7, 300.0).unwrap(); + model1.set_rows_height(0, 23, 23, 123.0).unwrap(); model1.set_user_input(0, 55, 55, "=42+8").unwrap(); for row in 1..5 { diff --git a/base/src/test/user_model/test_general.rs b/base/src/test/user_model/test_general.rs index 3882f2c..dc4e60b 100644 --- a/base/src/test/user_model/test_general.rs +++ b/base/src/test/user_model/test_general.rs @@ -59,7 +59,7 @@ fn insert_remove_rows() { // Insert some data in row 5 (and change the style) assert!(model.set_user_input(0, 5, 1, "100$").is_ok()); // Change the height of the column - assert!(model.set_row_height(0, 5, 3.0 * height).is_ok()); + assert!(model.set_rows_height(0, 5, 5, 3.0 * height).is_ok()); // remove the row assert!(model.delete_row(0, 5).is_ok()); @@ -95,7 +95,7 @@ fn insert_remove_columns() { // Insert some data in row 5 (and change the style) in E1 assert!(model.set_user_input(0, 1, 5, "100$").is_ok()); // Change the width of the column - assert!(model.set_column_width(0, 5, 3.0 * column_width).is_ok()); + assert!(model.set_columns_width(0, 5, 5, 3.0 * column_width).is_ok()); assert_eq!(model.get_column_width(0, 5).unwrap(), 3.0 * column_width); // remove the column diff --git a/base/src/test/user_model/test_row_column.rs b/base/src/test/user_model/test_row_column.rs index e138345..4125a2e 100644 --- a/base/src/test/user_model/test_row_column.rs +++ b/base/src/test/user_model/test_row_column.rs @@ -59,7 +59,7 @@ fn simple_delete_column() { model.set_user_input(0, 1, 5, "3").unwrap(); model.set_user_input(0, 2, 5, "=E1*2").unwrap(); model - .set_column_width(0, 5, DEFAULT_COLUMN_WIDTH * 3.0) + .set_columns_width(0, 5, 5, DEFAULT_COLUMN_WIDTH * 3.0) .unwrap(); model.delete_column(0, 5).unwrap(); @@ -116,7 +116,7 @@ fn simple_delete_row() { model.set_user_input(0, 15, 6, "=D15*2").unwrap(); model - .set_row_height(0, 15, DEFAULT_ROW_HEIGHT * 3.0) + .set_rows_height(0, 15, 15, DEFAULT_ROW_HEIGHT * 3.0) .unwrap(); model.delete_row(0, 15).unwrap(); diff --git a/base/src/test/user_model/test_to_from_bytes.rs b/base/src/test/user_model/test_to_from_bytes.rs index af4b7bf..324b76c 100644 --- a/base/src/test/user_model/test_to_from_bytes.rs +++ b/base/src/test/user_model/test_to_from_bytes.rs @@ -6,7 +6,7 @@ use crate::{test::util::new_empty_model, UserModel}; fn basic() { let mut model1 = UserModel::from_model(new_empty_model()); let width = model1.get_column_width(0, 3).unwrap() * 3.0; - model1.set_column_width(0, 3, width).unwrap(); + model1.set_columns_width(0, 3, 3, width).unwrap(); model1.set_user_input(0, 1, 2, "Hello IronCalc!").unwrap(); let model_bytes = model1.to_bytes(); diff --git a/base/src/user_model/common.rs b/base/src/user_model/common.rs index 2a116e5..d085465 100644 --- a/base/src/user_model/common.rs +++ b/base/src/user_model/common.rs @@ -939,34 +939,56 @@ impl UserModel { Ok(()) } - /// Sets the width of a column + /// Sets the width of a group of columns in a single diff list /// /// See also: /// * [Model::set_column_width] - pub fn set_column_width(&mut self, sheet: u32, column: i32, width: f64) -> Result<(), String> { - let old_value = self.model.get_column_width(sheet, column)?; - self.push_diff_list(vec![Diff::SetColumnWidth { - sheet, - column, - new_value: width, - old_value, - }]); - self.model.set_column_width(sheet, column, width) + pub fn set_columns_width( + &mut self, + sheet: u32, + column_start: i32, + column_end: i32, + width: f64, + ) -> Result<(), String> { + let mut diff_list = Vec::new(); + for column in column_start..=column_end { + let old_value = self.model.get_column_width(sheet, column)?; + diff_list.push(Diff::SetColumnWidth { + sheet, + column, + new_value: width, + old_value, + }); + self.model.set_column_width(sheet, column, width)?; + } + self.push_diff_list(diff_list); + Ok(()) } - /// Sets the height of a row + /// Sets the height of a range of rows in a single diff list /// /// See also: /// * [Model::set_row_height] - pub fn set_row_height(&mut self, sheet: u32, row: i32, height: f64) -> Result<(), String> { - let old_value = self.model.get_row_height(sheet, row)?; - self.push_diff_list(vec![Diff::SetRowHeight { - sheet, - row, - new_value: height, - old_value, - }]); - self.model.set_row_height(sheet, row, height) + pub fn set_rows_height( + &mut self, + sheet: u32, + row_start: i32, + row_end: i32, + height: f64, + ) -> Result<(), String> { + let mut diff_list = Vec::new(); + for row in row_start..=row_end { + let old_value = self.model.get_row_height(sheet, row)?; + diff_list.push(Diff::SetRowHeight { + sheet, + row, + new_value: height, + old_value, + }); + self.model.set_row_height(sheet, row, height)?; + } + self.push_diff_list(diff_list); + Ok(()) } /// Gets the height of a row diff --git a/bindings/nodejs/src/user_model.rs b/bindings/nodejs/src/user_model.rs index 0950afc..b1ebcb9 100644 --- a/bindings/nodejs/src/user_model.rs +++ b/bindings/nodejs/src/user_model.rs @@ -203,19 +203,31 @@ impl UserModel { self.model.delete_column(sheet, column).map_err(to_js_error) } - #[napi(js_name = "setRowHeight")] - pub fn set_row_height(&mut self, sheet: u32, row: i32, height: f64) -> Result<()> { + #[napi(js_name = "setRowsHeight")] + pub fn set_rows_height( + &mut self, + sheet: u32, + row_start: i32, + row_end: i32, + height: f64, + ) -> Result<()> { self .model - .set_row_height(sheet, row, height) + .set_rows_height(sheet, row_start, row_end, height) .map_err(to_js_error) } - #[napi(js_name = "setColumnWidth")] - pub fn set_column_width(&mut self, sheet: u32, column: i32, width: f64) -> Result<()> { + #[napi(js_name = "setColumnsWidth")] + pub fn set_columns_width( + &mut self, + sheet: u32, + column_start: i32, + column_end: i32, + width: f64, + ) -> Result<()> { self .model - .set_column_width(sheet, column, width) + .set_columns_width(sheet, column_start, column_end, width) .map_err(to_js_error) } diff --git a/bindings/wasm/src/lib.rs b/bindings/wasm/src/lib.rs index a954a02..e55d950 100644 --- a/bindings/wasm/src/lib.rs +++ b/bindings/wasm/src/lib.rs @@ -215,17 +215,29 @@ impl Model { self.model.delete_column(sheet, column).map_err(to_js_error) } - #[wasm_bindgen(js_name = "setRowHeight")] - pub fn set_row_height(&mut self, sheet: u32, row: i32, height: f64) -> Result<(), JsError> { + #[wasm_bindgen(js_name = "setRowsHeight")] + pub fn set_rows_height( + &mut self, + sheet: u32, + row_start: i32, + row_end: i32, + height: f64, + ) -> Result<(), JsError> { self.model - .set_row_height(sheet, row, height) + .set_rows_height(sheet, row_start, row_end, height) .map_err(to_js_error) } - #[wasm_bindgen(js_name = "setColumnWidth")] - pub fn set_column_width(&mut self, sheet: u32, column: i32, width: f64) -> Result<(), JsError> { + #[wasm_bindgen(js_name = "setColumnsWidth")] + pub fn set_columns_width( + &mut self, + sheet: u32, + column_start: i32, + column_end: i32, + width: f64, + ) -> Result<(), JsError> { self.model - .set_column_width(sheet, column, width) + .set_columns_width(sheet, column_start, column_end, width) .map_err(to_js_error) } @@ -292,6 +304,28 @@ impl Model { .map_err(to_js_error) } + // This two are only used when we want to compute the automatic width of a column or height of a row + #[wasm_bindgen(js_name = "getRowsWithData")] + pub fn get_rows_with_data(&self, sheet: u32, column: i32) -> Result, JsError> { + let sheet_data = &self.model.get_model().workbook.worksheet(sheet).map_err(to_js_error)?.sheet_data; + Ok(sheet_data + .iter() + .filter(|(_, data)| data.contains_key(&column)) + .map(|(row, _)| *row) + .collect()) + } + + #[wasm_bindgen(js_name = "getColumnsWithData")] + pub fn get_columns_with_data(&self, sheet: u32, row: i32) -> Result, JsError> { + Ok(self.model.get_model() + .workbook + .worksheet(sheet).map_err(to_js_error)? + .sheet_data + .get(&row) + .map(|row_data| row_data.keys().copied().collect()) + .unwrap_or_default()) + } + #[wasm_bindgen(js_name = "updateRangeStyle")] pub fn update_range_style( &mut self, diff --git a/bindings/wasm/tests/test.mjs b/bindings/wasm/tests/test.mjs index aed7d59..468322e 100644 --- a/bindings/wasm/tests/test.mjs +++ b/bindings/wasm/tests/test.mjs @@ -20,7 +20,7 @@ test('Row height', () => { let model = new Model('Workbook1', 'en', 'UTC'); assert.strictEqual(model.getRowHeight(0, 3), DEFAULT_ROW_HEIGHT); - model.setRowHeight(0, 3, 32); + model.setRowsHeight(0, 3, 3, 32); assert.strictEqual(model.getRowHeight(0, 3), 32); model.undo(); @@ -29,7 +29,7 @@ test('Row height', () => { model.redo(); assert.strictEqual(model.getRowHeight(0, 3), 32); - model.setRowHeight(0, 3, 320); + model.setRowsHeight(0, 3, 3, 320); assert.strictEqual(model.getRowHeight(0, 3), 320); }); @@ -96,7 +96,7 @@ test("Add sheets", (t) => { test("invalid sheet index throws an exception", () => { const model = new Model('Workbook1', 'en', 'UTC'); assert.throws(() => { - model.setRowHeight(1, 1, 100); + model.setRowsHeight(1, 1, 1, 100); }, { name: 'Error', message: 'Invalid sheet index', @@ -106,7 +106,7 @@ test("invalid sheet index throws an exception", () => { test("invalid column throws an exception", () => { const model = new Model('Workbook1', 'en', 'UTC'); assert.throws(() => { - model.setRowHeight(0, -1, 100); + model.setRowsHeight(0, -1, 0, 100); }, { name: 'Error', message: "Row number '-1' is not valid.", @@ -115,7 +115,7 @@ test("invalid column throws an exception", () => { test("floating column numbers get truncated", () => { const model = new Model('Workbook1', 'en', 'UTC'); - model.setRowHeight(0.8, 5.2, 100.5); + model.setRowsHeight(0.8, 5.2, 5.5, 100.5); assert.strictEqual(model.getRowHeight(0.11, 5.99), 100.5); assert.strictEqual(model.getRowHeight(0, 5), 100.5); diff --git a/webapp/IronCalc/src/components/worksheet.tsx b/webapp/IronCalc/src/components/worksheet.tsx index 592b37a..20c5f38 100644 --- a/webapp/IronCalc/src/components/worksheet.tsx +++ b/webapp/IronCalc/src/components/worksheet.tsx @@ -112,19 +112,14 @@ function Worksheet(props: { if (width < 0) { return; } - // if the column is one of the selected columns, we need to update the width of all selected columns - // FIXME: This is a bit of a hack, we should probably have a separate function for this const { range } = model.getSelectedView(); + let columnStart = column; + let columnEnd = column; if (column >= range[1] && column <= range[3]) { - model.setColumnWidth(sheet, column, width); - for (let i = range[1]; i <= range[3]; i++) { - if (i !== column) { - model.setColumnWidth(sheet, i, width); - } - } - } else { - model.setColumnWidth(sheet, column, width); + columnStart = Math.min(range[1], column, range[3]); + columnEnd = Math.max(range[1], column, range[3]); } + model.setColumnsWidth(sheet, columnStart, columnEnd, width); worksheetCanvas.current?.renderSheet(); }, onRowHeightChanges(sheet, row, height) { @@ -132,16 +127,13 @@ function Worksheet(props: { return; } const { range } = model.getSelectedView(); + let rowStart = row; + let rowEnd = row; if (row >= range[0] && row <= range[2]) { - model.setRowHeight(sheet, row, height); - for (let i = range[0]; i <= range[2]; i++) { - if (i !== row) { - model.setRowHeight(sheet, i, height); - } - } - } else { - model.setRowHeight(sheet, row, height); + rowStart = Math.min(range[0], row, range[2]); + rowEnd = Math.max(range[0], row, range[2]); } + model.setRowsHeight(sheet, rowStart, rowEnd, height); worksheetCanvas.current?.renderSheet(); }, }); @@ -362,7 +354,7 @@ function Worksheet(props: { Math.min(rowStart, extendedArea.rowStart), Math.min(columnStart, extendedArea.columnStart), Math.max(rowStart + height - 1, extendedArea.rowEnd), - Math.max(columnStart + width - 1, extendedArea.columnEnd) + Math.max(columnStart + width - 1, extendedArea.columnEnd), ); workbookState.clearExtendToArea(); canvas.renderSheet(); diff --git a/xlsx/tests/test.rs b/xlsx/tests/test.rs index 34cb487..5b34de6 100644 --- a/xlsx/tests/test.rs +++ b/xlsx/tests/test.rs @@ -508,5 +508,5 @@ fn test_user_model() { fs::remove_file(temp_file_name).unwrap(); // we can still use the model afterwards - model.set_row_height(0, 1, 100.0).unwrap(); + model.set_rows_height(0, 1, 1, 100.0).unwrap(); }