1#![deny(missing_docs)]
2
3use std::{collections::HashMap, fmt::Debug};
4
5use serde::{Deserialize, Serialize};
6
7use crate::{
8 cf_types::ExtendedStyle,
9 constants::{LAST_COLUMN, LAST_ROW},
10 expressions::{
11 parser::CompletionContext,
12 types::Area,
13 utils::{is_valid_column_number, is_valid_row},
14 },
15 model::{FmtSettings, Model},
16 types::{
17 Alignment, ArrayKind, BorderItem, Cell, CellType, Col, Color, HorizontalAlignment,
18 SheetProperties, SheetState, Style, Theme, VerticalAlignment,
19 },
20};
21
22use crate::user_model::history::{
23 ColumnData, Diff, DiffList, DiffType, History, QueueDiffs, RowData,
24};
25
26use super::border_utils::is_max_border;
27
28#[derive(Serialize, Deserialize)]
29pub enum CellArrayStructure {
30 SingleCell,
32 DynamicChild(i32, i32, i32, i32),
35 DynamicAnchor(i32, i32),
37 ArrayChild(i32, i32, i32, i32),
39 ArrayAnchor(i32, i32),
41}
42
43#[derive(Serialize, Deserialize, PartialEq)]
44pub enum BorderType {
45 All,
46 Inner,
47 Outer,
48 Top,
49 Right,
50 Bottom,
51 Left,
52 CenterH,
53 CenterV,
54 None,
55}
56
57#[derive(Serialize, Deserialize)]
59pub struct BorderArea {
60 pub(crate) item: BorderItem,
61 pub(crate) r#type: BorderType,
62}
63
64fn boolean(value: &str) -> Result<bool, String> {
65 match value {
66 "true" => Ok(true),
67 "false" => Ok(false),
68 _ => Err(format!("Invalid value for boolean: '{value}'.")),
69 }
70}
71
72fn horizontal(value: &str) -> Result<HorizontalAlignment, String> {
73 match value {
74 "center" => Ok(HorizontalAlignment::Center),
75 "centerContinuous" => Ok(HorizontalAlignment::CenterContinuous),
76 "distributed" => Ok(HorizontalAlignment::Distributed),
77 "fill" => Ok(HorizontalAlignment::Fill),
78 "general" => Ok(HorizontalAlignment::General),
79 "justify" => Ok(HorizontalAlignment::Justify),
80 "left" => Ok(HorizontalAlignment::Left),
81 "right" => Ok(HorizontalAlignment::Right),
82 _ => Err(format!(
83 "Invalid value for horizontal alignment: '{value}'."
84 )),
85 }
86}
87
88fn vertical(value: &str) -> Result<VerticalAlignment, String> {
89 match value {
90 "bottom" => Ok(VerticalAlignment::Bottom),
91 "center" => Ok(VerticalAlignment::Center),
92 "distributed" => Ok(VerticalAlignment::Distributed),
93 "justify" => Ok(VerticalAlignment::Justify),
94 "top" => Ok(VerticalAlignment::Top),
95 _ => Err(format!("Invalid value for vertical alignment: '{value}'.")),
96 }
97}
98
99fn update_style(old_value: &Style, style_path: &str, value: &str) -> Result<Style, String> {
100 let mut style = old_value.clone();
101 match style_path {
102 "font.b" => {
103 style.font.b = boolean(value)?;
104 }
105 "font.i" => {
106 style.font.i = boolean(value)?;
107 }
108 "font.u" => {
109 style.font.u = boolean(value)?;
110 }
111 "font.strike" => {
112 style.font.strike = boolean(value)?;
113 }
114 "font.color" => {
115 style.font.color = Color::from_param(value)?;
116 }
117 "font.size" => {
118 let new_size: i32 = value
119 .parse()
120 .map_err(|_| format!("Invalid value for font size: '{value}'."))?;
121 if new_size < 1 {
122 return Err(format!("Invalid value for font size: '{new_size}'."));
123 }
124 style.font.sz = new_size;
125 }
126 "font.size_delta" => {
127 let size_delta: i32 = value
129 .parse()
130 .map_err(|_| format!("Invalid value for font size: '{value}'."))?;
131 let new_size = style.font.sz + size_delta;
132 if new_size < 1 {
133 return Err(format!("Invalid value for font size: '{new_size}'."));
134 }
135 style.font.sz = new_size;
136 }
137 "fill.color" | "fill.bg_color" | "fill.fg_color" => {
138 style.fill.color = Color::from_param(value)?;
139 }
140 "num_fmt" => {
141 value.clone_into(&mut style.num_fmt);
142 }
143 "alignment" => {
144 if !value.is_empty() {
145 return Err(format!("Alignment must be empty, but found: '{value}'."));
146 }
147 style.alignment = None;
148 }
149 "alignment.horizontal" => match style.alignment {
150 Some(ref mut s) => s.horizontal = horizontal(value)?,
151 None => {
152 let alignment = Alignment {
153 horizontal: horizontal(value)?,
154 ..Default::default()
155 };
156 style.alignment = Some(alignment)
157 }
158 },
159 "alignment.vertical" => match style.alignment {
160 Some(ref mut s) => s.vertical = vertical(value)?,
161 None => {
162 let alignment = Alignment {
163 vertical: vertical(value)?,
164 ..Default::default()
165 };
166 style.alignment = Some(alignment)
167 }
168 },
169 "alignment.wrap_text" => match style.alignment {
170 Some(ref mut s) => s.wrap_text = boolean(value)?,
171 None => {
172 let alignment = Alignment {
173 wrap_text: boolean(value)?,
174 ..Default::default()
175 };
176 style.alignment = Some(alignment)
177 }
178 },
179 _ => {
180 return Err(format!("Invalid style path: '{style_path}'."));
181 }
182 }
183 Ok(style)
184}
185
186pub struct UserModel<'a> {
213 pub(crate) model: Model<'a>,
214 history: History,
215 send_queue: Vec<QueueDiffs>,
216 pause_evaluation: bool,
217}
218
219pub(crate) fn selected_sheet_after_move(selected: u32, from: u32, to: u32) -> u32 {
224 if selected == from {
225 return to;
226 }
227 let after_remove = if selected > from {
229 selected - 1
230 } else {
231 selected
232 };
233 if after_remove >= to {
234 after_remove + 1
235 } else {
236 after_remove
237 }
238}
239
240impl<'a> Debug for UserModel<'a> {
241 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
242 f.debug_struct("UserModel").finish()
243 }
244}
245
246impl<'a> UserModel<'a> {
247 pub fn from_model(model: Model) -> UserModel {
249 UserModel {
250 model,
251 history: History::default(),
252 send_queue: vec![],
253 pause_evaluation: false,
254 }
255 }
256
257 pub fn new_empty(
262 name: &'a str,
263 locale_id: &'a str,
264 timezone: &'a str,
265 language_id: &'a str,
266 ) -> Result<UserModel<'a>, String> {
267 let model = Model::new_empty(name, locale_id, timezone, language_id)?;
268 Ok(UserModel {
269 model,
270 history: History::default(),
271 send_queue: vec![],
272 pause_evaluation: false,
273 })
274 }
275
276 pub fn from_bytes(s: &[u8], language_id: &'a str) -> Result<UserModel<'a>, String> {
281 let model = Model::from_bytes(s, language_id)?;
282 Ok(UserModel {
283 model,
284 history: History::default(),
285 send_queue: vec![],
286 pause_evaluation: false,
287 })
288 }
289
290 pub fn to_bytes(&self) -> Vec<u8> {
295 self.model.to_bytes()
296 }
297
298 pub fn get_model(&self) -> &Model<'_> {
300 &self.model
301 }
302
303 pub fn get_name(&self) -> String {
305 self.model.workbook.name.clone()
306 }
307
308 pub fn set_name(&mut self, name: &str) {
310 let old_value = self.model.workbook.name.clone();
311 if old_value == name {
312 return;
313 }
314 self.push_diff_list(vec![Diff::SetWorkbookName {
315 old_value,
316 new_value: name.to_string(),
317 }]);
318 self.model.workbook.name = name.to_string();
319 }
320
321 pub fn undo(&mut self) -> Result<(), String> {
326 if let Some(diff_list) = self.history.undo() {
327 self.apply_undo_diff_list(&diff_list)?;
328 self.send_queue.push(QueueDiffs {
329 r#type: DiffType::Undo,
330 list: diff_list.clone(),
331 });
332 };
333 Ok(())
334 }
335
336 pub fn redo(&mut self) -> Result<(), String> {
341 if let Some(diff_list) = self.history.redo() {
342 self.apply_diff_list(&diff_list)?;
343 self.send_queue.push(QueueDiffs {
344 r#type: DiffType::Redo,
345 list: diff_list.clone(),
346 });
347 };
348 Ok(())
349 }
350
351 pub fn can_undo(&self) -> bool {
353 !self.history.undo_stack.is_empty()
354 }
355
356 pub fn can_redo(&self) -> bool {
358 !self.history.redo_stack.is_empty()
359 }
360
361 pub fn pause_evaluation(&mut self) {
367 self.pause_evaluation = true;
368 }
369
370 pub fn resume_evaluation(&mut self) {
376 self.pause_evaluation = false;
377 }
378
379 pub fn evaluate(&mut self) {
385 self.model.evaluate()
386 }
387
388 pub fn flush_send_queue(&mut self) -> Vec<u8> {
396 let q = bitcode::encode(&self.send_queue);
398 self.send_queue = vec![];
399 q
400 }
401
402 pub fn apply_external_diffs(&mut self, diff_list_str: &[u8]) -> Result<(), String> {
409 if let Ok(queue_diffs_list) = bitcode::decode::<Vec<QueueDiffs>>(diff_list_str) {
410 for queue_diff in queue_diffs_list {
411 if matches!(queue_diff.r#type, DiffType::Redo) {
412 self.apply_diff_list(&queue_diff.list)?;
413 } else {
414 self.apply_undo_diff_list(&queue_diff.list)?;
415 }
416 }
417 } else {
418 return Err("Error parsing diff list".to_string());
419 }
420 Ok(())
421 }
422
423 pub fn set_user_input(
428 &mut self,
429 sheet: u32,
430 row: i32,
431 column: i32,
432 value: &str,
433 ) -> Result<(), String> {
434 if !is_valid_column_number(column) {
435 return Err("Invalid column".to_string());
436 }
437 if !is_valid_row(row) {
438 return Err("Invalid row".to_string());
439 }
440 let old_value = self
441 .model
442 .workbook
443 .worksheet(sheet)?
444 .cell(row, column)
445 .cloned();
446 let old_value = if matches!(old_value, Some(Cell::SpillCell { .. })) {
448 None
449 } else {
450 old_value
451 };
452 self.model
453 .set_user_input(sheet, row, column, value.to_string())?;
454
455 self.evaluate_if_not_paused();
456
457 let mut diff_list = vec![Diff::SetCellValue {
458 sheet,
459 row,
460 column,
461 new_value: value.to_string(),
462 old_value: Box::new(old_value),
463 }];
464 let style = self.model.get_style_for_cell(sheet, row, column)?;
465
466 let line_count = value.split('\n').count() as f64;
467 let row_height = self.model.get_row_height(sheet, row)?;
468 let font_size = style.font.sz as f64;
470 let line_height = font_size * 1.5;
471 let cell_height = (line_count - 1.0) * line_height + 8.0 + font_size;
472 if cell_height > row_height {
473 diff_list.push(Diff::SetRowHeight {
474 sheet,
475 row,
476 new_value: cell_height,
477 old_value: row_height,
478 });
479 self.model.set_row_height(sheet, row, cell_height)?;
480 }
481
482 self.push_diff_list(diff_list);
483 Ok(())
484 }
485
486 #[inline]
491 pub fn get_cell_content(&self, sheet: u32, row: i32, column: i32) -> Result<String, String> {
492 self.model.get_localized_cell_content(sheet, row, column)
493 }
494
495 #[inline]
503 pub fn formula_completion(
504 &mut self,
505 sheet: u32,
506 row: i32,
507 column: i32,
508 formula: &str,
509 cursor: usize,
510 ) -> Result<CompletionContext, String> {
511 self.model
512 .formula_completion(sheet, row, column, formula, cursor)
513 }
514
515 #[inline]
522 pub fn cycle_reference(
523 &self,
524 value: &str,
525 start: usize,
526 end: usize,
527 ) -> Result<(String, i32, i32), String> {
528 self.model.cycle_reference(value, start, end)
529 }
530
531 #[inline]
536 pub fn get_formatted_cell_value(
537 &self,
538 sheet: u32,
539 row: i32,
540 column: i32,
541 ) -> Result<String, String> {
542 self.model.get_formatted_cell_value(sheet, row, column)
543 }
544
545 pub fn get_cell_type(&self, sheet: u32, row: i32, column: i32) -> Result<CellType, String> {
550 self.model.get_cell_type(sheet, row, column)
551 }
552
553 pub fn new_sheet(&mut self) -> Result<(), String> {
558 let (name, index) = self.model.new_sheet();
559 self.set_selected_sheet(index)?;
560 self.push_diff_list(vec![Diff::NewSheet { index, name }]);
561 Ok(())
562 }
563
564 pub fn duplicate_sheet(&mut self, sheet: u32) -> Result<(), String> {
570 let (_name, new_index) = self.model.duplicate_sheet(sheet)?;
571 self.set_selected_sheet(new_index)?;
572 self.push_diff_list(vec![Diff::DuplicateSheet {
573 source_index: sheet,
574 new_index,
575 }]);
576 Ok(())
577 }
578
579 pub fn delete_sheet(&mut self, sheet: u32) -> Result<(), String> {
584 let worksheet = self.model.workbook.worksheet(sheet)?;
585
586 self.push_diff_list(vec![Diff::DeleteSheet {
587 sheet,
588 old_data: Box::new(worksheet.clone()),
589 }]);
590
591 let sheet_count = self.model.workbook.worksheets.len() as u32;
592 if sheet == sheet_count - 1 && sheet_count > 1 {
594 if let Some(view) = self.model.workbook.views.get_mut(&self.model.view_id) {
595 view.sheet = sheet_count - 2;
596 };
597 }
598
599 self.model.delete_sheet(sheet)?;
600 Ok(())
601 }
602
603 pub fn rename_sheet(&mut self, sheet: u32, new_name: &str) -> Result<(), String> {
608 let old_value = self.model.workbook.worksheet(sheet)?.name.clone();
609 if old_value == new_name {
610 return Ok(());
611 }
612 self.model.rename_sheet_by_index(sheet, new_name)?;
613 self.push_diff_list(vec![Diff::RenameSheet {
614 index: sheet,
615 old_value,
616 new_value: new_name.to_string(),
617 }]);
618 Ok(())
619 }
620
621 pub fn move_sheet(&mut self, sheet_index: u32, new_index: u32) -> Result<(), String> {
636 let sheet_count = self.model.workbook.worksheets.len() as u32;
637 if sheet_index >= sheet_count {
638 return Err(format!("Invalid sheet index {sheet_index}"));
639 }
640 if new_index >= sheet_count {
641 return Err(format!("Invalid target index {new_index}"));
642 }
643 if sheet_index == new_index {
644 return Ok(());
645 }
646 let selected = self.get_selected_sheet();
647 self.model.move_sheet(sheet_index, new_index)?;
648 self.set_selected_sheet(selected_sheet_after_move(selected, sheet_index, new_index))?;
649 self.push_diff_list(vec![Diff::MoveSheet {
650 sheet_index,
651 new_index,
652 }]);
653 Ok(())
654 }
655
656 pub fn hide_sheet(&mut self, sheet: u32) -> Result<(), String> {
662 let sheet_count = self.model.workbook.worksheets.len() as u32;
663 for index in 1..sheet_count {
664 let sheet_index = (sheet + index) % sheet_count;
665 if self.model.workbook.worksheet(sheet_index)?.state == SheetState::Visible {
666 if let Some(view) = self.model.workbook.views.get_mut(&self.model.view_id) {
667 view.sheet = sheet_index;
668 };
669 break;
670 }
671 }
672 let old_value = self.model.workbook.worksheet(sheet)?.state.clone();
673 self.push_diff_list(vec![Diff::SetSheetState {
674 index: sheet,
675 new_value: SheetState::Hidden,
676 old_value,
677 }]);
678 self.model.set_sheet_state(sheet, SheetState::Hidden)?;
679 Ok(())
680 }
681
682 pub fn unhide_sheet(&mut self, sheet: u32) -> Result<(), String> {
688 let old_value = self.model.workbook.worksheet(sheet)?.state.clone();
689 self.push_diff_list(vec![Diff::SetSheetState {
690 index: sheet,
691 new_value: SheetState::Visible,
692 old_value,
693 }]);
694 self.model.set_sheet_state(sheet, SheetState::Visible)?;
695 Ok(())
696 }
697
698 pub fn set_sheet_color(&mut self, sheet: u32, color: &Color) -> Result<(), String> {
706 let old_value = self.model.workbook.worksheet(sheet)?.color.clone();
707 self.model.set_sheet_color(sheet, color)?;
708 self.push_diff_list(vec![Diff::SetSheetColor {
709 index: sheet,
710 old_value,
711 new_value: color.clone(),
712 }]);
713 Ok(())
714 }
715
716 pub fn range_clear_all(&mut self, range: &Area) -> Result<(), String> {
721 let sheet = range.sheet;
722 let mut old_value = Vec::new();
724 let mut old_style = Vec::new();
725
726 for row in range.row..range.row + range.height {
727 let mut data_row = Vec::new();
728 let mut style_row = Vec::new();
729 for column in range.column..range.column + range.width {
730 let old_value = self
731 .model
732 .workbook
733 .worksheet(sheet)?
734 .cell(row, column)
735 .cloned();
736 data_row.push(old_value);
737 let old_style = self.model.get_style_for_cell(sheet, row, column)?;
738 style_row.push(old_style);
739 }
740 old_value.push(data_row);
741 old_style.push(style_row);
742 }
743 self.model.range_clear_all(range)?;
744 let diff_list = vec![Diff::RangeClearAll {
745 sheet,
746 row: range.row,
747 column: range.column,
748 width: range.width,
749 height: range.height,
750 old_value,
751 old_style,
752 }];
753
754 self.push_diff_list(diff_list);
755 self.evaluate_if_not_paused();
756 Ok(())
757 }
758
759 pub fn range_clear_contents(&mut self, range: &Area) -> Result<(), String> {
764 let sheet = range.sheet;
765 let mut old_value = Vec::new();
767 for row in range.row..range.row + range.height {
768 let mut data_row = Vec::new();
769 for column in range.column..range.column + range.width {
770 let old_value = self
771 .model
772 .workbook
773 .worksheet(sheet)?
774 .cell(row, column)
775 .cloned();
776 data_row.push(old_value);
777 }
778 old_value.push(data_row);
779 }
780 self.model.range_clear_contents(range)?;
781 let diff_list = vec![Diff::RangeClearContents {
782 sheet,
783 row: range.row,
784 column: range.column,
785 width: range.width,
786 height: range.height,
787 old_value,
788 }];
789 self.push_diff_list(diff_list);
790 self.evaluate_if_not_paused();
791 Ok(())
792 }
793
794 fn clear_column_formatting(
795 &mut self,
796 sheet: u32,
797 column: i32,
798 diff_list: &mut Vec<Diff>,
799 ) -> Result<(), String> {
800 let old_value = self.model.get_column_style(sheet, column)?;
801 self.model.delete_column_style(sheet, column)?;
802 diff_list.push(Diff::DeleteColumnStyle {
803 sheet,
804 column,
805 old_value: Box::new(old_value),
806 });
807
808 let data_rows: Vec<i32> = self
809 .model
810 .workbook
811 .worksheet(sheet)?
812 .sheet_data
813 .keys()
814 .copied()
815 .collect();
816 let styled_rows = &self.model.workbook.worksheet(sheet)?.rows.clone();
817
818 for row in data_rows {
820 if let Some(old_style) = self.model.get_cell_style_or_none(sheet, row, column)? {
821 self.model
823 .workbook
824 .worksheet_mut(sheet)?
825 .set_cell_style(row, column, 0)?;
826 diff_list.push(Diff::CellClearFormatting {
827 sheet,
828 row,
829 column,
830 old_style: Box::new(Some(old_style)),
831 });
832 } else {
833 let old_style = self.model.get_style_for_cell(sheet, row, column)?;
834 if old_style != Style::default() {
835 self.model
836 .workbook
837 .worksheet_mut(sheet)?
838 .set_cell_style(row, column, 0)?;
839 diff_list.push(Diff::CellClearFormatting {
840 sheet,
841 row,
842 column,
843 old_style: Box::new(None),
844 });
845 }
846 }
847 }
848 for row in styled_rows {
850 if let Some(old_style) = self.model.get_cell_style_or_none(sheet, row.r, column)? {
851 self.model
853 .workbook
854 .worksheet_mut(sheet)?
855 .set_cell_style(row.r, column, 0)?;
856 diff_list.push(Diff::CellClearFormatting {
857 sheet,
858 row: row.r,
859 column,
860 old_style: Box::new(Some(old_style)),
861 });
862 } else {
863 let old_style = self.model.get_style_for_cell(sheet, row.r, column)?;
864 if old_style != Style::default() {
865 self.model
866 .workbook
867 .worksheet_mut(sheet)?
868 .set_cell_style(row.r, column, 0)?;
869 diff_list.push(Diff::CellClearFormatting {
870 sheet,
871 row: row.r,
872 column,
873 old_style: Box::new(None),
874 });
875 }
876 }
877 }
878 Ok(())
879 }
880
881 fn clear_row_formatting(
882 &mut self,
883 sheet: u32,
884 row: i32,
885 diff_list: &mut Vec<Diff>,
886 ) -> Result<(), String> {
887 let old_value = self.model.get_row_style(sheet, row)?;
888 self.model.delete_row_style(sheet, row)?;
889 diff_list.push(Diff::DeleteRowStyle {
890 sheet,
891 row,
892 old_value: Box::new(old_value),
893 });
894
895 let columns: Vec<i32> = self
897 .model
898 .workbook
899 .worksheet(sheet)?
900 .sheet_data
901 .get(&row)
902 .map(|row_data| row_data.keys().copied().collect())
903 .unwrap_or_default();
904 for column in columns {
905 if let Some(old_style) = self.model.get_cell_style_or_none(sheet, row, column)? {
906 self.model
908 .workbook
909 .worksheet_mut(sheet)?
910 .set_cell_style(row, column, 0)?;
911 diff_list.push(Diff::CellClearFormatting {
912 sheet,
913 row,
914 column,
915 old_style: Box::new(Some(old_style)),
916 });
917 } else {
918 let old_style = self.model.get_style_for_cell(sheet, row, column)?;
919 if old_style != Style::default() {
920 self.model
921 .workbook
922 .worksheet_mut(sheet)?
923 .set_cell_style(row, column, 0)?;
924 diff_list.push(Diff::CellClearFormatting {
925 sheet,
926 row,
927 column,
928 old_style: Box::new(None),
929 });
930 }
931 }
932 }
933 Ok(())
934 }
935
936 pub fn range_clear_formatting(&mut self, range: &Area) -> Result<(), String> {
942 let sheet = range.sheet;
943 let mut diff_list = Vec::new();
944 if range.row == 1 && range.height == LAST_ROW {
945 for column in range.column..range.column + range.width {
946 self.clear_column_formatting(sheet, column, &mut diff_list)?;
947 }
948 self.push_diff_list(diff_list);
949 return Ok(());
950 }
951 if range.column == 1 && range.width == LAST_COLUMN {
952 for row in range.row..range.row + range.height {
953 self.clear_row_formatting(sheet, row, &mut diff_list)?;
954 }
955 self.push_diff_list(diff_list);
956 return Ok(());
957 }
958 for row in range.row..range.row + range.height {
959 for column in range.column..range.column + range.width {
960 if let Some(old_style) = self.model.get_cell_style_or_none(sheet, row, column)? {
961 self.model
963 .workbook
964 .worksheet_mut(sheet)?
965 .set_cell_style(row, column, 0)?;
966 diff_list.push(Diff::CellClearFormatting {
967 sheet,
968 row,
969 column,
970 old_style: Box::new(Some(old_style)),
971 });
972 } else {
973 let old_style = self.model.get_style_for_cell(sheet, row, column)?;
974 if old_style != Style::default() {
975 self.model
976 .workbook
977 .worksheet_mut(sheet)?
978 .set_cell_style(row, column, 0)?;
979 diff_list.push(Diff::CellClearFormatting {
980 sheet,
981 row,
982 column,
983 old_style: Box::new(None),
984 });
985 }
986 }
987 }
988 }
989 self.push_diff_list(diff_list);
990 Ok(())
991 }
992
993 pub fn insert_rows(&mut self, sheet: u32, row: i32, row_count: i32) -> Result<(), String> {
1007 self.model.insert_rows(sheet, row, row_count)?;
1008
1009 let diff_list = vec![Diff::InsertRows {
1010 sheet,
1011 row,
1012 count: row_count,
1013 }];
1014 self.push_diff_list(diff_list);
1015 self.evaluate_if_not_paused();
1016 Ok(())
1017 }
1018
1019 pub fn insert_columns(
1032 &mut self,
1033 sheet: u32,
1034 column: i32,
1035 column_count: i32,
1036 ) -> Result<(), String> {
1037 self.model.insert_columns(sheet, column, column_count)?;
1038
1039 let diff_list = vec![Diff::InsertColumns {
1040 sheet,
1041 column,
1042 count: column_count,
1043 }];
1044 self.push_diff_list(diff_list);
1045 self.evaluate_if_not_paused();
1046 Ok(())
1047 }
1048
1049 pub fn delete_rows(&mut self, sheet: u32, row: i32, row_count: i32) -> Result<(), String> {
1057 let worksheet = self.model.workbook.worksheet(sheet)?;
1058 let mut old_data = Vec::new();
1059 for r in row..row + row_count {
1061 let mut row_data = None;
1062 for rd in &worksheet.rows {
1063 if rd.r == r {
1064 row_data = Some(rd.clone());
1065 break;
1066 }
1067 }
1068 let data = match worksheet.sheet_data.get(&r) {
1071 Some(s) => s
1072 .iter()
1073 .map(|(k, v)| {
1074 let cell = if let Cell::SpillCell { s, .. } = v {
1075 Cell::EmptyCell { s: *s }
1076 } else {
1077 v.clone()
1078 };
1079 (*k, cell)
1080 })
1081 .collect(),
1082 None => HashMap::new(),
1083 };
1084 old_data.push(RowData {
1085 row: row_data,
1086 data,
1087 });
1088 }
1089
1090 self.model.delete_rows(sheet, row, row_count)?;
1091
1092 let diff_list = vec![Diff::DeleteRows {
1093 sheet,
1094 row,
1095 count: row_count,
1096 old_data,
1097 }];
1098 self.push_diff_list(diff_list);
1099 self.evaluate_if_not_paused();
1100 Ok(())
1101 }
1102
1103 pub fn delete_columns(
1111 &mut self,
1112 sheet: u32,
1113 column: i32,
1114 column_count: i32,
1115 ) -> Result<(), String> {
1116 let worksheet = self.model.workbook.worksheet(sheet)?;
1117 let mut old_data = Vec::new();
1118 for c in column..column + column_count {
1120 let mut column_data = None;
1121 for col in &worksheet.cols {
1122 if c >= col.min && c <= col.max {
1123 column_data = Some(Col {
1124 min: c,
1125 max: c,
1126 width: col.width,
1127 custom_width: col.custom_width,
1128 style: col.style,
1129 hidden: col.hidden,
1130 });
1131 break;
1132 }
1133 }
1134
1135 let mut data = HashMap::new();
1138 for (row_idx, row_data) in &worksheet.sheet_data {
1139 if let Some(cell) = row_data.get(&c) {
1140 let saved = if let Cell::SpillCell { s, .. } = cell {
1141 Cell::EmptyCell { s: *s }
1142 } else {
1143 cell.clone()
1144 };
1145 data.insert(*row_idx, saved);
1146 }
1147 }
1148
1149 old_data.push(ColumnData {
1150 column: column_data,
1151 data,
1152 });
1153 }
1154
1155 self.model.delete_columns(sheet, column, column_count)?;
1156
1157 let diff_list = vec![Diff::DeleteColumns {
1158 sheet,
1159 column,
1160 count: column_count,
1161 old_data,
1162 }];
1163 self.push_diff_list(diff_list);
1164 self.evaluate_if_not_paused();
1165 Ok(())
1166 }
1167
1168 pub fn move_columns_action(
1170 &mut self,
1171 sheet: u32,
1172 column: i32,
1173 column_count: i32,
1174 delta: i32,
1175 ) -> Result<(), String> {
1176 if delta == 0 || column_count <= 0 {
1177 return Ok(());
1178 }
1179 let mut new_delta = delta;
1181 let worksheet = self.model.workbook.worksheet(sheet)?;
1182 if delta > 0 {
1183 for col in column + column_count..=column + column_count + delta {
1184 if worksheet.is_column_hidden(col)? {
1185 new_delta += 1;
1186 }
1187 }
1188 } else {
1189 for col in column + delta..column {
1190 if worksheet.is_column_hidden(col)? {
1191 new_delta -= 1;
1192 }
1193 }
1194 }
1195
1196 self.model
1197 .move_columns_action(sheet, column, column_count, new_delta)?;
1198
1199 self.push_diff_list(vec![Diff::MoveColumns {
1200 sheet,
1201 column,
1202 column_count,
1203 delta: new_delta,
1204 }]);
1205 self.evaluate_if_not_paused();
1206 Ok(())
1207 }
1208
1209 pub fn move_rows_action(
1211 &mut self,
1212 sheet: u32,
1213 row: i32,
1214 row_count: i32,
1215 delta: i32,
1216 ) -> Result<(), String> {
1217 if delta == 0 || row_count <= 0 {
1218 return Ok(());
1219 }
1220 let mut new_delta = delta;
1221 let worksheet = self.model.workbook.worksheet(sheet)?;
1222 if delta > 0 {
1223 for r in row + row_count..=row + row_count + delta {
1224 if worksheet.is_row_hidden(r)? {
1225 new_delta += 1;
1226 }
1227 }
1228 } else {
1229 for r in row + delta..row {
1230 if worksheet.is_row_hidden(r)? {
1231 new_delta -= 1;
1232 }
1233 }
1234 }
1235
1236 self.model
1237 .move_rows_action(sheet, row, row_count, new_delta)?;
1238
1239 self.push_diff_list(vec![Diff::MoveRows {
1240 sheet,
1241 row,
1242 row_count,
1243 delta: new_delta,
1244 }]);
1245 self.evaluate_if_not_paused();
1246 Ok(())
1247 }
1248
1249 pub fn set_columns_width(
1254 &mut self,
1255 sheet: u32,
1256 column_start: i32,
1257 column_end: i32,
1258 width: f64,
1259 ) -> Result<(), String> {
1260 let mut diff_list = Vec::new();
1261 for column in column_start..=column_end {
1262 let old_value = self.model.get_column_width(sheet, column)?;
1263 diff_list.push(Diff::SetColumnWidth {
1264 sheet,
1265 column,
1266 new_value: width,
1267 old_value,
1268 });
1269 self.model.set_column_width(sheet, column, width)?;
1270 }
1271 self.push_diff_list(diff_list);
1272 Ok(())
1273 }
1274
1275 pub fn set_columns_hidden(
1280 &mut self,
1281 sheet: u32,
1282 column_start: i32,
1283 column_end: i32,
1284 hidden: bool,
1285 ) -> Result<(), String> {
1286 let mut diff_list = Vec::new();
1287 for column in column_start..=column_end {
1288 let old_value = self
1289 .model
1290 .workbook
1291 .worksheet(sheet)?
1292 .is_column_hidden(column)?;
1293 diff_list.push(Diff::SetColumnHidden {
1294 sheet,
1295 column,
1296 new_value: hidden,
1297 old_value,
1298 });
1299 self.model.set_column_hidden(sheet, column, hidden)?;
1300 }
1301 if hidden {
1303 if let Some(view) = self.model.workbook.views.get_mut(&self.model.view_id) {
1304 if view.sheet == sheet {
1305 let mut column = column_end + 1;
1307 while self
1308 .model
1309 .workbook
1310 .worksheet(sheet)?
1311 .is_column_hidden(column)?
1312 {
1313 column += 1;
1314 if column > LAST_COLUMN {
1315 break;
1316 }
1317 }
1318 if column > LAST_COLUMN {
1319 column = column_start - 1;
1321 while self
1322 .model
1323 .workbook
1324 .worksheet(sheet)?
1325 .is_column_hidden(column)?
1326 {
1327 column -= 1;
1328 if column <= 0 {
1329 column = 1;
1331 break;
1332 }
1333 }
1334 }
1335 self.set_selected_cell(1, column)?;
1336 self.set_selected_range(1, column, LAST_ROW, column)?;
1337 }
1338 };
1339 }
1340 self.push_diff_list(diff_list);
1341 Ok(())
1342 }
1343
1344 pub fn set_rows_hidden(
1348 &mut self,
1349 sheet: u32,
1350 row_start: i32,
1351 row_end: i32,
1352 hidden: bool,
1353 ) -> Result<(), String> {
1354 let mut diff_list = Vec::new();
1355 for row in row_start..=row_end {
1356 let old_value = self.model.workbook.worksheet(sheet)?.is_row_hidden(row)?;
1357 diff_list.push(Diff::SetRowHidden {
1358 sheet,
1359 row,
1360 new_value: hidden,
1361 old_value,
1362 });
1363 self.model.set_row_hidden(sheet, row, hidden)?;
1364 }
1365 if hidden {
1367 if let Some(view) = self.model.workbook.views.get_mut(&self.model.view_id) {
1368 if view.sheet == sheet {
1369 let mut row = row_end + 1;
1371 while self.model.workbook.worksheet(sheet)?.is_row_hidden(row)? {
1372 row += 1;
1373 if row > LAST_ROW {
1374 break;
1375 }
1376 }
1377 if row > LAST_ROW {
1378 row = row_start - 1;
1380 while self.model.workbook.worksheet(sheet)?.is_row_hidden(row)? {
1381 row -= 1;
1382 if row <= 0 {
1383 row = 1;
1385 break;
1386 }
1387 }
1388 }
1389 self.set_selected_cell(row, 1)?;
1390 self.set_selected_range(row, 1, row, LAST_COLUMN)?;
1391 }
1392 };
1393 }
1394 self.push_diff_list(diff_list);
1395 Ok(())
1396 }
1397
1398 pub fn set_rows_height(
1403 &mut self,
1404 sheet: u32,
1405 row_start: i32,
1406 row_end: i32,
1407 height: f64,
1408 ) -> Result<(), String> {
1409 let mut diff_list = Vec::new();
1410 for row in row_start..=row_end {
1411 let old_value = self.model.get_row_height(sheet, row)?;
1412 diff_list.push(Diff::SetRowHeight {
1413 sheet,
1414 row,
1415 new_value: height,
1416 old_value,
1417 });
1418 self.model.set_row_height(sheet, row, height)?;
1419 }
1420 self.push_diff_list(diff_list);
1421 Ok(())
1422 }
1423
1424 #[inline]
1429 pub fn get_row_height(&self, sheet: u32, row: i32) -> Result<f64, String> {
1430 self.model.get_row_height(sheet, row)
1431 }
1432
1433 #[inline]
1438 pub fn get_column_width(&self, sheet: u32, column: i32) -> Result<f64, String> {
1439 self.model.get_column_width(sheet, column)
1440 }
1441
1442 #[inline]
1447 pub fn get_frozen_rows_count(&self, sheet: u32) -> Result<i32, String> {
1448 self.model.get_frozen_rows_count(sheet)
1449 }
1450
1451 #[inline]
1456 pub fn get_frozen_columns_count(&self, sheet: u32) -> Result<i32, String> {
1457 self.model.get_frozen_columns_count(sheet)
1458 }
1459
1460 pub fn set_frozen_rows_count(&mut self, sheet: u32, frozen_rows: i32) -> Result<(), String> {
1465 let old_value = self.model.get_frozen_rows_count(sheet)?;
1466 self.push_diff_list(vec![Diff::SetFrozenRowsCount {
1467 sheet,
1468 new_value: frozen_rows,
1469 old_value,
1470 }]);
1471 self.model.set_frozen_rows(sheet, frozen_rows)
1472 }
1473
1474 pub fn set_frozen_columns_count(
1479 &mut self,
1480 sheet: u32,
1481 frozen_columns: i32,
1482 ) -> Result<(), String> {
1483 let old_value = self.model.get_frozen_columns_count(sheet)?;
1484 self.push_diff_list(vec![Diff::SetFrozenColumnsCount {
1485 sheet,
1486 new_value: frozen_columns,
1487 old_value,
1488 }]);
1489 self.model.set_frozen_columns(sheet, frozen_columns)
1490 }
1491
1492 pub fn on_paste_styles(&mut self, styles: &[Vec<Style>]) -> Result<(), String> {
1494 let styles_height = styles.len() as i32;
1495 let styles_width = styles[0].len() as i32;
1496 let sheet = if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
1497 view.sheet
1498 } else {
1499 return Ok(());
1500 };
1501 let range = if let Ok(worksheet) = self.model.workbook.worksheet(sheet) {
1502 if let Some(view) = worksheet.views.get(&self.model.view_id) {
1503 view.range
1504 } else {
1505 return Ok(());
1506 }
1507 } else {
1508 return Ok(());
1509 };
1510
1511 let [row_start, column_start, row_end, column_end] = range;
1513 let last_row = row_end.max(row_start + styles_height - 1);
1514 let last_column = column_end.max(column_start + styles_width - 1);
1515
1516 let mut diff_list = Vec::new();
1517 for row in row_start..=last_row {
1518 for column in column_start..=last_column {
1519 let row_index = ((row - row_start) % styles_height) as usize;
1520 let column_index = ((column - column_start) % styles_width) as usize;
1521 let style = &styles[row_index][column_index];
1522 let old_value = self.model.get_cell_style_or_none(sheet, row, column)?;
1523 self.model.set_cell_style(sheet, row, column, style)?;
1524 diff_list.push(Diff::SetCellStyle {
1525 sheet,
1526 row,
1527 column,
1528 old_value: Box::new(old_value),
1529 new_value: Box::new(style.clone()),
1530 });
1531 }
1532 }
1533 self.push_diff_list(diff_list);
1534
1535 if let Ok(worksheet) = self.model.workbook.worksheet_mut(sheet) {
1537 if let Some(view) = worksheet.views.get_mut(&self.model.view_id) {
1538 view.range = [row_start, column_start, last_row, last_column];
1539 }
1540 }
1541 Ok(())
1542 }
1543
1544 fn update_single_cell_style(
1546 &mut self,
1547 sheet: u32,
1548 row: i32,
1549 column: i32,
1550 style_path: &str,
1551 value: &str,
1552 diff_list: &mut Vec<Diff>,
1553 ) -> Result<(), String> {
1554 let old_value = self.model.get_cell_style_or_none(sheet, row, column)?;
1556
1557 let old_style = self.model.get_style_for_cell(sheet, row, column)?;
1560 let new_style = update_style(&old_style, style_path, value)?;
1561 self.model.set_cell_style(sheet, row, column, &new_style)?;
1562 diff_list.push(Diff::SetCellStyle {
1563 sheet,
1564 row,
1565 column,
1566 old_value: Box::new(old_value),
1567 new_value: Box::new(new_style),
1568 });
1569 Ok(())
1570 }
1571
1572 pub fn update_range_style(
1576 &mut self,
1577 range: &Area,
1578 style_path: &str,
1579 value: &str,
1580 ) -> Result<(), String> {
1581 let sheet = range.sheet;
1582 let mut diff_list = Vec::new();
1583 if range.row == 1 && range.height == LAST_ROW {
1584 let styled_rows = &self.model.workbook.worksheet(sheet)?.rows.clone();
1586 let data_rows: Vec<i32> = self
1589 .model
1590 .workbook
1591 .worksheet(sheet)?
1592 .sheet_data
1593 .keys()
1594 .copied()
1595 .collect();
1596 for column in range.column..range.column + range.width {
1597 let old_style = self.model.get_column_style(sheet, column)?;
1599 let style = match old_style.as_ref() {
1600 Some(s) => s,
1601 None => &Style::default(),
1602 };
1603 let style = update_style(style, style_path, value)?;
1604 self.model.set_column_style(sheet, column, &style)?;
1605 diff_list.push(Diff::SetColumnStyle {
1606 sheet,
1607 column,
1608 old_value: Box::new(old_style),
1609 new_value: Box::new(style),
1610 });
1611
1612 for row_s in styled_rows.iter() {
1614 let row = row_s.r;
1615 self.update_single_cell_style(
1616 sheet,
1617 row,
1618 column,
1619 style_path,
1620 value,
1621 &mut diff_list,
1622 )?;
1623 }
1624
1625 for &row in &data_rows {
1628 if let Some(data_row) =
1629 self.model.workbook.worksheet(sheet)?.sheet_data.get(&row)
1630 {
1631 if data_row.get(&column).is_some() {
1632 self.update_single_cell_style(
1634 sheet,
1635 row,
1636 column,
1637 style_path,
1638 value,
1639 &mut diff_list,
1640 )?;
1641 }
1642 }
1643 }
1644 }
1645 } else if range.column == 1 && range.width == LAST_COLUMN {
1646 let styled_columns = &self.model.workbook.worksheet(sheet)?.cols.clone();
1648 for row in range.row..range.row + range.height {
1649 let columns: Vec<i32> = self
1651 .model
1652 .workbook
1653 .worksheet(sheet)?
1654 .sheet_data
1655 .get(&row)
1656 .map(|row_data| row_data.keys().copied().collect())
1657 .unwrap_or_default();
1658 for column in columns {
1659 self.update_single_cell_style(
1660 sheet,
1661 row,
1662 column,
1663 style_path,
1664 value,
1665 &mut diff_list,
1666 )?;
1667 }
1668
1669 for col in styled_columns.iter() {
1671 for column in col.min..col.max + 1 {
1672 self.update_single_cell_style(
1673 sheet,
1674 row,
1675 column,
1676 style_path,
1677 value,
1678 &mut diff_list,
1679 )?;
1680 }
1681 }
1682
1683 let old_style = self.model.get_row_style(sheet, row)?;
1685 let style = match old_style.as_ref() {
1686 Some(s) => s,
1687 None => &Style::default(),
1688 };
1689 let style = update_style(style, style_path, value)?;
1690 self.model.set_row_style(sheet, row, &style)?;
1691 diff_list.push(Diff::SetRowStyle {
1692 sheet,
1693 row,
1694 old_value: Box::new(old_style),
1695 new_value: Box::new(style),
1696 });
1697 }
1698 } else {
1699 for row in range.row..range.row + range.height {
1700 for column in range.column..range.column + range.width {
1701 self.update_single_cell_style(
1702 sheet,
1703 row,
1704 column,
1705 style_path,
1706 value,
1707 &mut diff_list,
1708 )?;
1709 }
1710 }
1711 }
1712 self.push_diff_list(diff_list);
1713 Ok(())
1714 }
1715
1716 pub fn get_cell_style(&self, sheet: u32, row: i32, column: i32) -> Result<Style, String> {
1725 let mut style = self.model.get_style_for_cell(sheet, row, column)?;
1726
1727 let border_top = if row > 1 {
1729 self.model
1730 .get_style_for_cell(sheet, row - 1, column)?
1731 .border
1732 .bottom
1733 } else {
1734 None
1735 };
1736
1737 let border_right = if column < LAST_COLUMN {
1738 self.model
1739 .get_style_for_cell(sheet, row, column + 1)?
1740 .border
1741 .left
1742 } else {
1743 None
1744 };
1745
1746 let border_bottom = if row < LAST_ROW {
1747 self.model
1748 .get_style_for_cell(sheet, row + 1, column)?
1749 .border
1750 .top
1751 } else {
1752 None
1753 };
1754
1755 let border_left = if column > 1 {
1756 self.model
1757 .get_style_for_cell(sheet, row, column - 1)?
1758 .border
1759 .right
1760 } else {
1761 None
1762 };
1763
1764 if is_max_border(style.border.top.as_ref(), border_top.as_ref()) {
1765 style.border.top = border_top;
1766 }
1767
1768 if is_max_border(style.border.right.as_ref(), border_right.as_ref()) {
1769 style.border.right = border_right;
1770 }
1771
1772 if is_max_border(style.border.bottom.as_ref(), border_bottom.as_ref()) {
1773 style.border.bottom = border_bottom;
1774 }
1775
1776 if is_max_border(style.border.left.as_ref(), border_left.as_ref()) {
1777 style.border.left = border_left;
1778 }
1779
1780 Ok(style)
1781 }
1782
1783 pub fn get_extended_cell_style(
1788 &self,
1789 sheet: u32,
1790 row: i32,
1791 column: i32,
1792 ) -> Result<ExtendedStyle, String> {
1793 let mut extended = self.model.get_extended_style_for_cell(sheet, row, column)?;
1794
1795 let border_top = if row > 1 {
1796 self.model
1797 .get_style_for_cell(sheet, row - 1, column)?
1798 .border
1799 .bottom
1800 } else {
1801 None
1802 };
1803
1804 let border_right = if column < LAST_COLUMN {
1805 self.model
1806 .get_style_for_cell(sheet, row, column + 1)?
1807 .border
1808 .left
1809 } else {
1810 None
1811 };
1812
1813 let border_bottom = if row < LAST_ROW {
1814 self.model
1815 .get_style_for_cell(sheet, row + 1, column)?
1816 .border
1817 .top
1818 } else {
1819 None
1820 };
1821
1822 let border_left = if column > 1 {
1823 self.model
1824 .get_style_for_cell(sheet, row, column - 1)?
1825 .border
1826 .right
1827 } else {
1828 None
1829 };
1830
1831 if is_max_border(extended.style.border.top.as_ref(), border_top.as_ref()) {
1832 extended.style.border.top = border_top;
1833 }
1834
1835 if is_max_border(extended.style.border.right.as_ref(), border_right.as_ref()) {
1836 extended.style.border.right = border_right;
1837 }
1838
1839 if is_max_border(
1840 extended.style.border.bottom.as_ref(),
1841 border_bottom.as_ref(),
1842 ) {
1843 extended.style.border.bottom = border_bottom;
1844 }
1845
1846 if is_max_border(extended.style.border.left.as_ref(), border_left.as_ref()) {
1847 extended.style.border.left = border_left;
1848 }
1849
1850 Ok(extended)
1851 }
1852
1853 #[inline]
1858 pub fn get_worksheets_properties(&self) -> Vec<SheetProperties> {
1859 self.model.get_worksheets_properties()
1860 }
1861
1862 pub fn set_theme(&mut self, theme: Theme) {
1864 let old_value = self.model.workbook.theme.clone();
1865 let new_value = theme.clone();
1866 self.model.set_theme(theme);
1867 self.push_diff_list(vec![Diff::SetTheme {
1868 old_value: Box::new(old_value),
1869 new_value: Box::new(new_value),
1870 }]);
1871 }
1872
1873 pub fn get_theme(&self) -> Theme {
1875 self.model.get_theme()
1876 }
1877
1878 pub fn resolve_color(&self, color: &Color) -> String {
1881 color.to_rgb(&self.model.workbook.theme)
1882 }
1883
1884 pub fn set_show_grid_lines(&mut self, sheet: u32, show_grid_lines: bool) -> Result<(), String> {
1886 let old_value = self.model.workbook.worksheet(sheet)?.show_grid_lines;
1887 self.model.set_show_grid_lines(sheet, show_grid_lines)?;
1888
1889 self.push_diff_list(vec![Diff::SetShowGridLines {
1890 sheet,
1891 new_value: show_grid_lines,
1892 old_value,
1893 }]);
1894 Ok(())
1895 }
1896
1897 pub fn get_show_grid_lines(&self, sheet: u32) -> Result<bool, String> {
1899 Ok(self.model.workbook.worksheet(sheet)?.show_grid_lines)
1900 }
1901
1902 pub fn get_last_non_empty_in_row_before_column(
1906 &self,
1907 sheet: u32,
1908 row: i32,
1909 column: i32,
1910 ) -> Result<Option<i32>, String> {
1911 let worksheet = self.model.workbook.worksheet(sheet)?;
1912 let data = worksheet.sheet_data.get(&row);
1913 if let Some(row_data) = data {
1914 let mut last_column = None;
1915 let mut columns: Vec<i32> = row_data.keys().copied().collect();
1916 columns.sort_unstable();
1917 for col in columns {
1918 if col < column {
1919 if let Some(cell) = worksheet.cell(row, col) {
1920 if matches!(cell, Cell::EmptyCell { .. }) {
1921 continue;
1922 }
1923 }
1924 last_column = Some(col);
1925 }
1926 }
1927 Ok(last_column)
1928 } else {
1929 Ok(None)
1930 }
1931 }
1932
1933 pub fn get_first_non_empty_in_row_after_column(
1937 &self,
1938 sheet: u32,
1939 row: i32,
1940 column: i32,
1941 ) -> Result<Option<i32>, String> {
1942 let worksheet = self.model.workbook.worksheet(sheet)?;
1943 let data = worksheet.sheet_data.get(&row);
1944 if let Some(row_data) = data {
1945 let mut columns: Vec<i32> = row_data.keys().copied().collect();
1946 columns.sort_unstable();
1948 for col in columns {
1949 if col > column {
1950 if let Some(cell) = worksheet.cell(row, col) {
1951 if matches!(cell, Cell::EmptyCell { .. }) {
1952 continue;
1953 }
1954 }
1955 return Ok(Some(col));
1956 }
1957 }
1958 }
1959 Ok(None)
1960 }
1961
1962 pub fn get_cell_array_structure(
1964 &self,
1965 sheet: u32,
1966 row: i32,
1967 column: i32,
1968 ) -> Result<CellArrayStructure, String> {
1969 let cell = self
1970 .model
1971 .workbook
1972 .worksheet(sheet)?
1973 .cell(row, column)
1974 .cloned()
1975 .unwrap_or_default();
1976 match cell {
1977 Cell::EmptyCell { .. }
1978 | Cell::BooleanCell { .. }
1979 | Cell::NumberCell { .. }
1980 | Cell::ErrorCell { .. }
1981 | Cell::SharedString { .. }
1982 | Cell::CellFormula { .. } => Ok(CellArrayStructure::SingleCell),
1983 Cell::SpillCell { a, .. } => {
1984 let (m_row, m_column) = a;
1985 let m_cell = self
1986 .model
1987 .workbook
1988 .worksheet(sheet)?
1989 .cell(m_row, m_column)
1990 .cloned()
1991 .unwrap_or_default();
1992 let (width, height, is_dynamic) = match m_cell {
1993 Cell::ArrayFormula {
1994 r,
1995 kind: ArrayKind::Dynamic,
1996 ..
1997 } => (r.0, r.1, true),
1998 Cell::ArrayFormula {
1999 r,
2000 kind: ArrayKind::Cse,
2001 ..
2002 } => (r.0, r.1, false),
2003 _ => return Err("Invalid structure".to_string()),
2004 };
2005 if is_dynamic {
2006 Ok(CellArrayStructure::DynamicChild(
2007 m_row, m_column, width, height,
2008 ))
2009 } else {
2010 Ok(CellArrayStructure::ArrayChild(
2011 m_row, m_column, width, height,
2012 ))
2013 }
2014 }
2015 Cell::ArrayFormula {
2016 r,
2017 kind: ArrayKind::Dynamic,
2018 ..
2019 } => Ok(CellArrayStructure::DynamicAnchor(r.0, r.1)),
2020 Cell::ArrayFormula {
2021 r,
2022 kind: ArrayKind::Cse,
2023 ..
2024 } => Ok(CellArrayStructure::ArrayAnchor(r.0, r.1)),
2025 }
2026 }
2027
2028 pub fn set_user_array_formula(
2030 &mut self,
2031 sheet: u32,
2032 row: i32,
2033 column: i32,
2034 width: i32,
2035 height: i32,
2036 formula: &str,
2037 ) -> Result<(), String> {
2038 let ws = self.model.workbook.worksheet(sheet)?;
2039 let mut old_values = Vec::new();
2040 for r in row..row + height {
2041 let mut row_vals = Vec::new();
2042 for c in column..column + width {
2043 let cell = ws.cell(r, c).cloned();
2044 let cell = if matches!(cell, Some(Cell::SpillCell { .. })) {
2046 None
2047 } else {
2048 cell
2049 };
2050 row_vals.push(cell);
2051 }
2052 old_values.push(row_vals);
2053 }
2054 self.model
2055 .set_user_array_formula(sheet, row, column, width, height, formula)?;
2056 self.push_diff_list(vec![Diff::SetArrayValue {
2057 sheet,
2058 row,
2059 column,
2060 width,
2061 height,
2062 new_value: formula.to_string(),
2063 old_values,
2064 }]);
2065 self.evaluate_if_not_paused();
2066 Ok(())
2067 }
2068
2069 pub fn get_defined_name_list(&self) -> Vec<(String, Option<u32>, String)> {
2071 self.model.get_defined_name_list()
2072 }
2073
2074 pub fn delete_defined_name(&mut self, name: &str, scope: Option<u32>) -> Result<(), String> {
2076 let old_value = self.model.get_defined_name_formula(name, scope)?;
2077 let diff_list = vec![Diff::DeleteDefinedName {
2078 name: name.to_string(),
2079 scope,
2080 old_value,
2081 }];
2082 self.push_diff_list(diff_list);
2083 self.model.delete_defined_name(name, scope)?;
2084 self.evaluate_if_not_paused();
2085 Ok(())
2086 }
2087
2088 pub fn new_defined_name(
2090 &mut self,
2091 name: &str,
2092 scope: Option<u32>,
2093 formula: &str,
2094 ) -> Result<(), String> {
2095 self.model.new_defined_name(name, scope, formula)?;
2096 let value = self.model.get_defined_name_formula(name, scope)?;
2101 let diff_list = vec![Diff::CreateDefinedName {
2102 name: name.to_string(),
2103 scope,
2104 value,
2105 }];
2106 self.push_diff_list(diff_list);
2107 self.evaluate_if_not_paused();
2108 Ok(())
2109 }
2110
2111 pub fn update_defined_name(
2113 &mut self,
2114 name: &str,
2115 scope: Option<u32>,
2116 new_name: &str,
2117 new_scope: Option<u32>,
2118 new_formula: &str,
2119 ) -> Result<(), String> {
2120 let old_formula = self
2123 .model
2124 .get_defined_name_formula(name, scope)
2125 .map_err(|_| "General: Failed to get old name")?;
2126 self.model
2127 .update_defined_name(name, scope, new_name, new_scope, new_formula)?;
2128 let new_formula_internal = self.model.get_defined_name_formula(new_name, new_scope)?;
2131 let diff_list = vec![Diff::UpdateDefinedName {
2132 name: name.to_string(),
2133 scope,
2134 old_formula,
2135 new_name: new_name.to_string(),
2136 new_scope,
2137 new_formula: new_formula_internal,
2138 }];
2139 self.push_diff_list(diff_list);
2140 self.evaluate_if_not_paused();
2141 Ok(())
2142 }
2143
2144 pub fn is_valid_defined_name(
2146 &mut self,
2147 name: &str,
2148 scope: Option<u32>,
2149 formula: &str,
2150 ) -> Result<Option<u32>, String> {
2151 self.model.is_valid_defined_name(name, scope, formula)
2152 }
2153
2154 pub fn set_timezone(&mut self, timezone: &str) -> Result<(), String> {
2156 let diff_list = vec![Diff::SetTimezone {
2157 old_value: self.get_timezone(),
2158 new_value: timezone.to_string(),
2159 }];
2160 self.push_diff_list(diff_list);
2161 self.model.set_timezone(timezone)
2162 }
2163
2164 pub fn set_locale(&mut self, locale: &str) -> Result<(), String> {
2166 let diff_list = vec![Diff::SetLocale {
2167 old_value: self.get_locale(),
2168 new_value: locale.to_string(),
2169 }];
2170 self.push_diff_list(diff_list);
2171 self.model.set_locale(locale)
2172 }
2173
2174 pub fn get_timezone(&self) -> String {
2176 self.model.get_timezone()
2177 }
2178
2179 pub fn get_locale(&self) -> String {
2181 self.model.get_locale()
2182 }
2183
2184 pub fn get_language(&self) -> String {
2186 self.model.get_language()
2187 }
2188
2189 pub fn set_language(&mut self, language: &str) -> Result<(), String> {
2191 self.model.set_language(language)
2192 }
2193
2194 pub fn get_fmt_settings(&self) -> FmtSettings {
2196 self.model.get_fmt_settings()
2197 }
2198
2199 pub(crate) fn push_diff_list(&mut self, diff_list: DiffList) {
2202 self.send_queue.push(QueueDiffs {
2203 r#type: DiffType::Redo,
2204 list: diff_list.clone(),
2205 });
2206 self.history.push(diff_list);
2207 }
2208
2209 pub(super) fn evaluate_if_not_paused(&mut self) {
2210 if !self.pause_evaluation {
2211 self.model.evaluate();
2212 }
2213 }
2214}
2215
2216#[cfg(test)]
2217mod tests {
2218 use crate::{
2219 types::{HorizontalAlignment, VerticalAlignment},
2220 user_model::common::{horizontal, selected_sheet_after_move, vertical},
2221 };
2222
2223 #[test]
2224 fn test_selected_sheet_after_move() {
2225 assert_eq!(selected_sheet_after_move(0, 0, 2), 2);
2227 assert_eq!(selected_sheet_after_move(3, 3, 0), 0);
2228
2229 assert_eq!(selected_sheet_after_move(2, 0, 2), 1);
2232 assert_eq!(selected_sheet_after_move(0, 2, 0), 1);
2234
2235 assert_eq!(selected_sheet_after_move(3, 1, 2), 3);
2238 }
2239
2240 #[test]
2241 fn test_vertical() {
2242 let all = vec![
2243 VerticalAlignment::Bottom,
2244 VerticalAlignment::Center,
2245 VerticalAlignment::Distributed,
2246 VerticalAlignment::Justify,
2247 VerticalAlignment::Top,
2248 ];
2249 for a in all {
2250 assert_eq!(vertical(&format!("{a}")), Ok(a));
2251 }
2252 }
2253
2254 #[test]
2255 fn test_horizontal() {
2256 let all = vec![
2257 HorizontalAlignment::Center,
2258 HorizontalAlignment::CenterContinuous,
2259 HorizontalAlignment::Distributed,
2260 HorizontalAlignment::Fill,
2261 HorizontalAlignment::General,
2262 HorizontalAlignment::Justify,
2263 HorizontalAlignment::Left,
2264 HorizontalAlignment::Right,
2265 ];
2266 for a in all {
2267 assert_eq!(horizontal(&format!("{a}")), Ok(a));
2268 }
2269 }
2270}