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 let mut diff_list = vec![Diff::SetCellValue {
453 sheet,
454 row,
455 column,
456 new_value: value.to_string(),
457 old_value: Box::new(old_value),
458 }];
459 self.set_user_input_with_link_diffs(sheet, row, column, value.to_string(), &mut diff_list)?;
460
461 self.evaluate_if_not_paused();
462
463 let style = self.model.get_style_for_cell(sheet, row, column)?;
464
465 let line_count = value.split('\n').count() as f64;
466 let row_height = self.model.get_row_height(sheet, row)?;
467 let font_size = style.font.sz as f64;
469 let line_height = font_size * 1.5;
470 let cell_height = (line_count - 1.0) * line_height + 8.0 + font_size;
471 if cell_height > row_height {
472 diff_list.push(Diff::SetRowHeight {
473 sheet,
474 row,
475 new_value: cell_height,
476 old_value: row_height,
477 });
478 self.model.set_row_height(sheet, row, cell_height)?;
479 }
480
481 self.push_diff_list(diff_list);
482 Ok(())
483 }
484
485 pub(super) fn set_user_input_with_link_diffs(
491 &mut self,
492 sheet: u32,
493 row: i32,
494 column: i32,
495 value: String,
496 diff_list: &mut Vec<Diff>,
497 ) -> Result<(), String> {
498 let old_link = self.model.get_cell_link(sheet, row, column)?;
499 let old_style = self.model.get_cell_style_or_none(sheet, row, column)?;
500 self.model.set_user_input(sheet, row, column, value)?;
501 let new_link = self.model.get_cell_link(sheet, row, column)?;
502 if new_link == old_link {
503 return Ok(());
504 }
505 if old_link.is_none() {
506 let new_style = self.model.get_style_for_cell(sheet, row, column)?;
508 diff_list.push(Diff::SetCellStyle {
509 sheet,
510 row,
511 column,
512 old_value: Box::new(old_style),
513 new_value: Box::new(new_style),
514 });
515 }
516 diff_list.push(Diff::SetCellLink {
517 sheet,
518 row,
519 column,
520 old_value: Box::new(old_link),
521 new_value: Box::new(new_link),
522 });
523 Ok(())
524 }
525
526 #[inline]
531 pub fn get_cell_content(&self, sheet: u32, row: i32, column: i32) -> Result<String, String> {
532 self.model.get_localized_cell_content(sheet, row, column)
533 }
534
535 #[inline]
543 pub fn formula_completion(
544 &mut self,
545 sheet: u32,
546 row: i32,
547 column: i32,
548 formula: &str,
549 cursor: usize,
550 ) -> Result<CompletionContext, String> {
551 self.model
552 .formula_completion(sheet, row, column, formula, cursor)
553 }
554
555 #[inline]
562 pub fn cycle_reference(
563 &self,
564 value: &str,
565 start: usize,
566 end: usize,
567 ) -> Result<(String, i32, i32), String> {
568 self.model.cycle_reference(value, start, end)
569 }
570
571 #[inline]
576 pub fn get_formatted_cell_value(
577 &self,
578 sheet: u32,
579 row: i32,
580 column: i32,
581 ) -> Result<String, String> {
582 self.model.get_formatted_cell_value(sheet, row, column)
583 }
584
585 pub fn get_cell_type(&self, sheet: u32, row: i32, column: i32) -> Result<CellType, String> {
590 self.model.get_cell_type(sheet, row, column)
591 }
592
593 pub fn new_sheet(&mut self) -> Result<(), String> {
598 let (name, index) = self.model.new_sheet();
599 self.set_selected_sheet(index)?;
600 self.push_diff_list(vec![Diff::NewSheet { index, name }]);
601 Ok(())
602 }
603
604 pub fn duplicate_sheet(&mut self, sheet: u32) -> Result<(), String> {
610 let (_name, new_index) = self.model.duplicate_sheet(sheet)?;
611 self.set_selected_sheet(new_index)?;
612 self.push_diff_list(vec![Diff::DuplicateSheet {
613 source_index: sheet,
614 new_index,
615 }]);
616 Ok(())
617 }
618
619 pub fn delete_sheet(&mut self, sheet: u32) -> Result<(), String> {
624 let worksheet = self.model.workbook.worksheet(sheet)?;
625
626 self.push_diff_list(vec![Diff::DeleteSheet {
627 sheet,
628 old_data: Box::new(worksheet.clone()),
629 }]);
630
631 let sheet_count = self.model.workbook.worksheets.len() as u32;
632 if sheet == sheet_count - 1 && sheet_count > 1 {
634 if let Some(view) = self.model.workbook.views.get_mut(&self.model.view_id) {
635 view.sheet = sheet_count - 2;
636 };
637 }
638
639 self.model.delete_sheet(sheet)?;
640 Ok(())
641 }
642
643 pub fn rename_sheet(&mut self, sheet: u32, new_name: &str) -> Result<(), String> {
648 let old_value = self.model.workbook.worksheet(sheet)?.name.clone();
649 if old_value == new_name {
650 return Ok(());
651 }
652 self.model.rename_sheet_by_index(sheet, new_name)?;
653 self.push_diff_list(vec![Diff::RenameSheet {
654 index: sheet,
655 old_value,
656 new_value: new_name.to_string(),
657 }]);
658 Ok(())
659 }
660
661 pub fn move_sheet(&mut self, sheet_index: u32, new_index: u32) -> Result<(), String> {
676 let sheet_count = self.model.workbook.worksheets.len() as u32;
677 if sheet_index >= sheet_count {
678 return Err(format!("Invalid sheet index {sheet_index}"));
679 }
680 if new_index >= sheet_count {
681 return Err(format!("Invalid target index {new_index}"));
682 }
683 if sheet_index == new_index {
684 return Ok(());
685 }
686 let selected = self.get_selected_sheet();
687 self.model.move_sheet(sheet_index, new_index)?;
688 self.set_selected_sheet(selected_sheet_after_move(selected, sheet_index, new_index))?;
689 self.push_diff_list(vec![Diff::MoveSheet {
690 sheet_index,
691 new_index,
692 }]);
693 Ok(())
694 }
695
696 pub fn hide_sheet(&mut self, sheet: u32) -> Result<(), String> {
702 let sheet_count = self.model.workbook.worksheets.len() as u32;
703 for index in 1..sheet_count {
704 let sheet_index = (sheet + index) % sheet_count;
705 if self.model.workbook.worksheet(sheet_index)?.state == SheetState::Visible {
706 if let Some(view) = self.model.workbook.views.get_mut(&self.model.view_id) {
707 view.sheet = sheet_index;
708 };
709 break;
710 }
711 }
712 let old_value = self.model.workbook.worksheet(sheet)?.state.clone();
713 self.push_diff_list(vec![Diff::SetSheetState {
714 index: sheet,
715 new_value: SheetState::Hidden,
716 old_value,
717 }]);
718 self.model.set_sheet_state(sheet, SheetState::Hidden)?;
719 Ok(())
720 }
721
722 pub fn unhide_sheet(&mut self, sheet: u32) -> Result<(), String> {
728 let old_value = self.model.workbook.worksheet(sheet)?.state.clone();
729 self.push_diff_list(vec![Diff::SetSheetState {
730 index: sheet,
731 new_value: SheetState::Visible,
732 old_value,
733 }]);
734 self.model.set_sheet_state(sheet, SheetState::Visible)?;
735 Ok(())
736 }
737
738 pub fn set_sheet_color(&mut self, sheet: u32, color: &Color) -> Result<(), String> {
746 let old_value = self.model.workbook.worksheet(sheet)?.color.clone();
747 self.model.set_sheet_color(sheet, color)?;
748 self.push_diff_list(vec![Diff::SetSheetColor {
749 index: sheet,
750 old_value,
751 new_value: color.clone(),
752 }]);
753 Ok(())
754 }
755
756 pub fn range_clear_all(&mut self, range: &Area) -> Result<(), String> {
761 let sheet = range.sheet;
762 let mut old_value = Vec::new();
764 let mut old_style = Vec::new();
765
766 for row in range.row..range.row + range.height {
767 let mut data_row = Vec::new();
768 let mut style_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 let old_style = self.model.get_style_for_cell(sheet, row, column)?;
778 style_row.push(old_style);
779 }
780 old_value.push(data_row);
781 old_style.push(style_row);
782 }
783 let link_diffs = self.range_link_diffs(range)?;
785 self.model.range_clear_all(range)?;
786 let mut diff_list = vec![Diff::RangeClearAll {
787 sheet,
788 row: range.row,
789 column: range.column,
790 width: range.width,
791 height: range.height,
792 old_value,
793 old_style,
794 }];
795 diff_list.extend(link_diffs);
796
797 self.push_diff_list(diff_list);
798 self.evaluate_if_not_paused();
799 Ok(())
800 }
801
802 pub fn range_clear_contents(&mut self, range: &Area) -> Result<(), String> {
807 let sheet = range.sheet;
808 let mut old_value = Vec::new();
810 for row in range.row..range.row + range.height {
811 let mut data_row = Vec::new();
812 for column in range.column..range.column + range.width {
813 let old_value = self
814 .model
815 .workbook
816 .worksheet(sheet)?
817 .cell(row, column)
818 .cloned();
819 data_row.push(old_value);
820 }
821 old_value.push(data_row);
822 }
823 let link_diffs = self.range_link_diffs(range)?;
825 self.model.range_clear_contents(range)?;
826 let mut diff_list = vec![Diff::RangeClearContents {
827 sheet,
828 row: range.row,
829 column: range.column,
830 width: range.width,
831 height: range.height,
832 old_value,
833 }];
834 diff_list.extend(link_diffs);
835 self.push_diff_list(diff_list);
836 self.evaluate_if_not_paused();
837 Ok(())
838 }
839
840 pub(super) fn range_link_diffs(&self, range: &Area) -> Result<Vec<Diff>, String> {
843 let mut diffs = Vec::new();
844 for (&(row, column), link) in &self.model.workbook.worksheet(range.sheet)?.links {
845 if row >= range.row
846 && row < range.row + range.height
847 && column >= range.column
848 && column < range.column + range.width
849 {
850 diffs.push(Diff::SetCellLink {
851 sheet: range.sheet,
852 row,
853 column,
854 old_value: Box::new(Some(link.clone())),
855 new_value: Box::new(None),
856 });
857 }
858 }
859 Ok(diffs)
860 }
861
862 fn clear_column_formatting(
863 &mut self,
864 sheet: u32,
865 column: i32,
866 diff_list: &mut Vec<Diff>,
867 ) -> Result<(), String> {
868 let old_value = self.model.get_column_style(sheet, column)?;
869 self.model.delete_column_style(sheet, column)?;
870 diff_list.push(Diff::DeleteColumnStyle {
871 sheet,
872 column,
873 old_value: Box::new(old_value),
874 });
875
876 let data_rows: Vec<i32> = self
877 .model
878 .workbook
879 .worksheet(sheet)?
880 .sheet_data
881 .keys()
882 .copied()
883 .collect();
884 let styled_rows = &self.model.workbook.worksheet(sheet)?.rows.clone();
885
886 for row in data_rows {
888 if let Some(old_style) = self.model.get_cell_style_or_none(sheet, row, column)? {
889 self.model
891 .workbook
892 .worksheet_mut(sheet)?
893 .set_cell_style(row, column, 0)?;
894 diff_list.push(Diff::CellClearFormatting {
895 sheet,
896 row,
897 column,
898 old_style: Box::new(Some(old_style)),
899 });
900 } else {
901 let old_style = self.model.get_style_for_cell(sheet, row, column)?;
902 if old_style != Style::default() {
903 self.model
904 .workbook
905 .worksheet_mut(sheet)?
906 .set_cell_style(row, column, 0)?;
907 diff_list.push(Diff::CellClearFormatting {
908 sheet,
909 row,
910 column,
911 old_style: Box::new(None),
912 });
913 }
914 }
915 }
916 for row in styled_rows {
918 if let Some(old_style) = self.model.get_cell_style_or_none(sheet, row.r, column)? {
919 self.model
921 .workbook
922 .worksheet_mut(sheet)?
923 .set_cell_style(row.r, column, 0)?;
924 diff_list.push(Diff::CellClearFormatting {
925 sheet,
926 row: row.r,
927 column,
928 old_style: Box::new(Some(old_style)),
929 });
930 } else {
931 let old_style = self.model.get_style_for_cell(sheet, row.r, column)?;
932 if old_style != Style::default() {
933 self.model
934 .workbook
935 .worksheet_mut(sheet)?
936 .set_cell_style(row.r, column, 0)?;
937 diff_list.push(Diff::CellClearFormatting {
938 sheet,
939 row: row.r,
940 column,
941 old_style: Box::new(None),
942 });
943 }
944 }
945 }
946 Ok(())
947 }
948
949 fn clear_row_formatting(
950 &mut self,
951 sheet: u32,
952 row: i32,
953 diff_list: &mut Vec<Diff>,
954 ) -> Result<(), String> {
955 let old_value = self.model.get_row_style(sheet, row)?;
956 self.model.delete_row_style(sheet, row)?;
957 diff_list.push(Diff::DeleteRowStyle {
958 sheet,
959 row,
960 old_value: Box::new(old_value),
961 });
962
963 let columns: Vec<i32> = self
965 .model
966 .workbook
967 .worksheet(sheet)?
968 .sheet_data
969 .get(&row)
970 .map(|row_data| row_data.keys().copied().collect())
971 .unwrap_or_default();
972 for column in columns {
973 if let Some(old_style) = self.model.get_cell_style_or_none(sheet, row, column)? {
974 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(Some(old_style)),
984 });
985 } else {
986 let old_style = self.model.get_style_for_cell(sheet, row, column)?;
987 if old_style != Style::default() {
988 self.model
989 .workbook
990 .worksheet_mut(sheet)?
991 .set_cell_style(row, column, 0)?;
992 diff_list.push(Diff::CellClearFormatting {
993 sheet,
994 row,
995 column,
996 old_style: Box::new(None),
997 });
998 }
999 }
1000 }
1001 Ok(())
1002 }
1003
1004 pub fn range_clear_formatting(&mut self, range: &Area) -> Result<(), String> {
1010 let sheet = range.sheet;
1011 let mut diff_list = Vec::new();
1012 if range.row == 1 && range.height == LAST_ROW {
1013 for column in range.column..range.column + range.width {
1014 self.clear_column_formatting(sheet, column, &mut diff_list)?;
1015 }
1016 self.push_diff_list(diff_list);
1017 return Ok(());
1018 }
1019 if range.column == 1 && range.width == LAST_COLUMN {
1020 for row in range.row..range.row + range.height {
1021 self.clear_row_formatting(sheet, row, &mut diff_list)?;
1022 }
1023 self.push_diff_list(diff_list);
1024 return Ok(());
1025 }
1026 for row in range.row..range.row + range.height {
1027 for column in range.column..range.column + range.width {
1028 if let Some(old_style) = self.model.get_cell_style_or_none(sheet, row, column)? {
1029 self.model
1031 .workbook
1032 .worksheet_mut(sheet)?
1033 .set_cell_style(row, column, 0)?;
1034 diff_list.push(Diff::CellClearFormatting {
1035 sheet,
1036 row,
1037 column,
1038 old_style: Box::new(Some(old_style)),
1039 });
1040 } else {
1041 let old_style = self.model.get_style_for_cell(sheet, row, column)?;
1042 if old_style != Style::default() {
1043 self.model
1044 .workbook
1045 .worksheet_mut(sheet)?
1046 .set_cell_style(row, column, 0)?;
1047 diff_list.push(Diff::CellClearFormatting {
1048 sheet,
1049 row,
1050 column,
1051 old_style: Box::new(None),
1052 });
1053 }
1054 }
1055 }
1056 }
1057 self.push_diff_list(diff_list);
1058 Ok(())
1059 }
1060
1061 pub fn insert_rows(&mut self, sheet: u32, row: i32, row_count: i32) -> Result<(), String> {
1075 self.model.insert_rows(sheet, row, row_count)?;
1076
1077 let diff_list = vec![Diff::InsertRows {
1078 sheet,
1079 row,
1080 count: row_count,
1081 }];
1082 self.push_diff_list(diff_list);
1083 self.evaluate_if_not_paused();
1084 Ok(())
1085 }
1086
1087 pub fn insert_columns(
1100 &mut self,
1101 sheet: u32,
1102 column: i32,
1103 column_count: i32,
1104 ) -> Result<(), String> {
1105 self.model.insert_columns(sheet, column, column_count)?;
1106
1107 let diff_list = vec![Diff::InsertColumns {
1108 sheet,
1109 column,
1110 count: column_count,
1111 }];
1112 self.push_diff_list(diff_list);
1113 self.evaluate_if_not_paused();
1114 Ok(())
1115 }
1116
1117 pub fn delete_rows(&mut self, sheet: u32, row: i32, row_count: i32) -> Result<(), String> {
1125 let worksheet = self.model.workbook.worksheet(sheet)?;
1126 let mut old_data = Vec::new();
1127 for r in row..row + row_count {
1129 let mut row_data = None;
1130 for rd in &worksheet.rows {
1131 if rd.r == r {
1132 row_data = Some(rd.clone());
1133 break;
1134 }
1135 }
1136 let data = match worksheet.sheet_data.get(&r) {
1139 Some(s) => s
1140 .iter()
1141 .map(|(k, v)| {
1142 let cell = if let Cell::SpillCell { s, .. } = v {
1143 Cell::EmptyCell { s: *s }
1144 } else {
1145 v.clone()
1146 };
1147 (*k, cell)
1148 })
1149 .collect(),
1150 None => HashMap::new(),
1151 };
1152 old_data.push(RowData {
1153 row: row_data,
1154 data,
1155 });
1156 }
1157
1158 let mut diff_list = self.range_link_diffs(&Area {
1162 sheet,
1163 row,
1164 column: 1,
1165 width: LAST_COLUMN,
1166 height: row_count,
1167 })?;
1168
1169 self.model.delete_rows(sheet, row, row_count)?;
1170
1171 diff_list.push(Diff::DeleteRows {
1172 sheet,
1173 row,
1174 count: row_count,
1175 old_data,
1176 });
1177 self.push_diff_list(diff_list);
1178 self.evaluate_if_not_paused();
1179 Ok(())
1180 }
1181
1182 pub fn delete_columns(
1190 &mut self,
1191 sheet: u32,
1192 column: i32,
1193 column_count: i32,
1194 ) -> Result<(), String> {
1195 let worksheet = self.model.workbook.worksheet(sheet)?;
1196 let mut old_data = Vec::new();
1197 for c in column..column + column_count {
1199 let mut column_data = None;
1200 for col in &worksheet.cols {
1201 if c >= col.min && c <= col.max {
1202 column_data = Some(Col {
1203 min: c,
1204 max: c,
1205 width: col.width,
1206 custom_width: col.custom_width,
1207 style: col.style,
1208 hidden: col.hidden,
1209 });
1210 break;
1211 }
1212 }
1213
1214 let mut data = HashMap::new();
1217 for (row_idx, row_data) in &worksheet.sheet_data {
1218 if let Some(cell) = row_data.get(&c) {
1219 let saved = if let Cell::SpillCell { s, .. } = cell {
1220 Cell::EmptyCell { s: *s }
1221 } else {
1222 cell.clone()
1223 };
1224 data.insert(*row_idx, saved);
1225 }
1226 }
1227
1228 old_data.push(ColumnData {
1229 column: column_data,
1230 data,
1231 });
1232 }
1233
1234 let mut diff_list = self.range_link_diffs(&Area {
1239 sheet,
1240 row: 1,
1241 column,
1242 width: column_count,
1243 height: LAST_ROW,
1244 })?;
1245
1246 self.model.delete_columns(sheet, column, column_count)?;
1247
1248 diff_list.push(Diff::DeleteColumns {
1249 sheet,
1250 column,
1251 count: column_count,
1252 old_data,
1253 });
1254 self.push_diff_list(diff_list);
1255 self.evaluate_if_not_paused();
1256 Ok(())
1257 }
1258
1259 pub fn move_columns_action(
1261 &mut self,
1262 sheet: u32,
1263 column: i32,
1264 column_count: i32,
1265 delta: i32,
1266 ) -> Result<(), String> {
1267 if delta == 0 || column_count <= 0 {
1268 return Ok(());
1269 }
1270 let mut new_delta = delta;
1272 let worksheet = self.model.workbook.worksheet(sheet)?;
1273 if delta > 0 {
1274 for col in column + column_count..=column + column_count + delta {
1275 if worksheet.is_column_hidden(col)? {
1276 new_delta += 1;
1277 }
1278 }
1279 } else {
1280 for col in column + delta..column {
1281 if worksheet.is_column_hidden(col)? {
1282 new_delta -= 1;
1283 }
1284 }
1285 }
1286
1287 self.model
1288 .move_columns_action(sheet, column, column_count, new_delta)?;
1289
1290 self.push_diff_list(vec![Diff::MoveColumns {
1291 sheet,
1292 column,
1293 column_count,
1294 delta: new_delta,
1295 }]);
1296 self.evaluate_if_not_paused();
1297 Ok(())
1298 }
1299
1300 pub fn move_rows_action(
1302 &mut self,
1303 sheet: u32,
1304 row: i32,
1305 row_count: i32,
1306 delta: i32,
1307 ) -> Result<(), String> {
1308 if delta == 0 || row_count <= 0 {
1309 return Ok(());
1310 }
1311 let mut new_delta = delta;
1312 let worksheet = self.model.workbook.worksheet(sheet)?;
1313 if delta > 0 {
1314 for r in row + row_count..=row + row_count + delta {
1315 if worksheet.is_row_hidden(r)? {
1316 new_delta += 1;
1317 }
1318 }
1319 } else {
1320 for r in row + delta..row {
1321 if worksheet.is_row_hidden(r)? {
1322 new_delta -= 1;
1323 }
1324 }
1325 }
1326
1327 self.model
1328 .move_rows_action(sheet, row, row_count, new_delta)?;
1329
1330 self.push_diff_list(vec![Diff::MoveRows {
1331 sheet,
1332 row,
1333 row_count,
1334 delta: new_delta,
1335 }]);
1336 self.evaluate_if_not_paused();
1337 Ok(())
1338 }
1339
1340 pub fn set_columns_width(
1345 &mut self,
1346 sheet: u32,
1347 column_start: i32,
1348 column_end: i32,
1349 width: f64,
1350 ) -> Result<(), String> {
1351 let mut diff_list = Vec::new();
1352 for column in column_start..=column_end {
1353 let old_value = self.model.get_column_width(sheet, column)?;
1354 diff_list.push(Diff::SetColumnWidth {
1355 sheet,
1356 column,
1357 new_value: width,
1358 old_value,
1359 });
1360 self.model.set_column_width(sheet, column, width)?;
1361 }
1362 self.push_diff_list(diff_list);
1363 Ok(())
1364 }
1365
1366 pub fn set_columns_hidden(
1371 &mut self,
1372 sheet: u32,
1373 column_start: i32,
1374 column_end: i32,
1375 hidden: bool,
1376 ) -> Result<(), String> {
1377 let mut diff_list = Vec::new();
1378 for column in column_start..=column_end {
1379 let old_value = self
1380 .model
1381 .workbook
1382 .worksheet(sheet)?
1383 .is_column_hidden(column)?;
1384 diff_list.push(Diff::SetColumnHidden {
1385 sheet,
1386 column,
1387 new_value: hidden,
1388 old_value,
1389 });
1390 self.model.set_column_hidden(sheet, column, hidden)?;
1391 }
1392 if hidden {
1394 if let Some(view) = self.model.workbook.views.get_mut(&self.model.view_id) {
1395 if view.sheet == sheet {
1396 let mut column = column_end + 1;
1398 while self
1399 .model
1400 .workbook
1401 .worksheet(sheet)?
1402 .is_column_hidden(column)?
1403 {
1404 column += 1;
1405 if column > LAST_COLUMN {
1406 break;
1407 }
1408 }
1409 if column > LAST_COLUMN {
1410 column = column_start - 1;
1412 while self
1413 .model
1414 .workbook
1415 .worksheet(sheet)?
1416 .is_column_hidden(column)?
1417 {
1418 column -= 1;
1419 if column <= 0 {
1420 column = 1;
1422 break;
1423 }
1424 }
1425 }
1426 self.set_selected_cell(1, column)?;
1427 self.set_selected_range(1, column, LAST_ROW, column)?;
1428 }
1429 };
1430 }
1431 self.push_diff_list(diff_list);
1432 Ok(())
1433 }
1434
1435 pub fn set_rows_hidden(
1439 &mut self,
1440 sheet: u32,
1441 row_start: i32,
1442 row_end: i32,
1443 hidden: bool,
1444 ) -> Result<(), String> {
1445 let mut diff_list = Vec::new();
1446 for row in row_start..=row_end {
1447 let old_value = self.model.workbook.worksheet(sheet)?.is_row_hidden(row)?;
1448 diff_list.push(Diff::SetRowHidden {
1449 sheet,
1450 row,
1451 new_value: hidden,
1452 old_value,
1453 });
1454 self.model.set_row_hidden(sheet, row, hidden)?;
1455 }
1456 if hidden {
1458 if let Some(view) = self.model.workbook.views.get_mut(&self.model.view_id) {
1459 if view.sheet == sheet {
1460 let mut row = row_end + 1;
1462 while self.model.workbook.worksheet(sheet)?.is_row_hidden(row)? {
1463 row += 1;
1464 if row > LAST_ROW {
1465 break;
1466 }
1467 }
1468 if row > LAST_ROW {
1469 row = row_start - 1;
1471 while self.model.workbook.worksheet(sheet)?.is_row_hidden(row)? {
1472 row -= 1;
1473 if row <= 0 {
1474 row = 1;
1476 break;
1477 }
1478 }
1479 }
1480 self.set_selected_cell(row, 1)?;
1481 self.set_selected_range(row, 1, row, LAST_COLUMN)?;
1482 }
1483 };
1484 }
1485 self.push_diff_list(diff_list);
1486 Ok(())
1487 }
1488
1489 pub fn set_rows_height(
1494 &mut self,
1495 sheet: u32,
1496 row_start: i32,
1497 row_end: i32,
1498 height: f64,
1499 ) -> Result<(), String> {
1500 let mut diff_list = Vec::new();
1501 for row in row_start..=row_end {
1502 let old_value = self.model.get_row_height(sheet, row)?;
1503 diff_list.push(Diff::SetRowHeight {
1504 sheet,
1505 row,
1506 new_value: height,
1507 old_value,
1508 });
1509 self.model.set_row_height(sheet, row, height)?;
1510 }
1511 self.push_diff_list(diff_list);
1512 Ok(())
1513 }
1514
1515 #[inline]
1520 pub fn get_row_height(&self, sheet: u32, row: i32) -> Result<f64, String> {
1521 self.model.get_row_height(sheet, row)
1522 }
1523
1524 #[inline]
1529 pub fn get_column_width(&self, sheet: u32, column: i32) -> Result<f64, String> {
1530 self.model.get_column_width(sheet, column)
1531 }
1532
1533 #[inline]
1538 pub fn get_frozen_rows_count(&self, sheet: u32) -> Result<i32, String> {
1539 self.model.get_frozen_rows_count(sheet)
1540 }
1541
1542 #[inline]
1547 pub fn get_frozen_columns_count(&self, sheet: u32) -> Result<i32, String> {
1548 self.model.get_frozen_columns_count(sheet)
1549 }
1550
1551 pub fn set_frozen_rows_count(&mut self, sheet: u32, frozen_rows: i32) -> Result<(), String> {
1556 let old_value = self.model.get_frozen_rows_count(sheet)?;
1557 self.push_diff_list(vec![Diff::SetFrozenRowsCount {
1558 sheet,
1559 new_value: frozen_rows,
1560 old_value,
1561 }]);
1562 self.model.set_frozen_rows(sheet, frozen_rows)
1563 }
1564
1565 pub fn set_frozen_columns_count(
1570 &mut self,
1571 sheet: u32,
1572 frozen_columns: i32,
1573 ) -> Result<(), String> {
1574 let old_value = self.model.get_frozen_columns_count(sheet)?;
1575 self.push_diff_list(vec![Diff::SetFrozenColumnsCount {
1576 sheet,
1577 new_value: frozen_columns,
1578 old_value,
1579 }]);
1580 self.model.set_frozen_columns(sheet, frozen_columns)
1581 }
1582
1583 pub fn on_paste_styles(&mut self, styles: &[Vec<Style>]) -> Result<(), String> {
1585 let styles_height = styles.len() as i32;
1586 let styles_width = styles[0].len() as i32;
1587 let sheet = if let Some(view) = self.model.workbook.views.get(&self.model.view_id) {
1588 view.sheet
1589 } else {
1590 return Ok(());
1591 };
1592 let range = if let Ok(worksheet) = self.model.workbook.worksheet(sheet) {
1593 if let Some(view) = worksheet.views.get(&self.model.view_id) {
1594 view.range
1595 } else {
1596 return Ok(());
1597 }
1598 } else {
1599 return Ok(());
1600 };
1601
1602 let [row_start, column_start, row_end, column_end] = range;
1604 let last_row = row_end.max(row_start + styles_height - 1);
1605 let last_column = column_end.max(column_start + styles_width - 1);
1606
1607 let mut diff_list = Vec::new();
1608 for row in row_start..=last_row {
1609 for column in column_start..=last_column {
1610 let row_index = ((row - row_start) % styles_height) as usize;
1611 let column_index = ((column - column_start) % styles_width) as usize;
1612 let style = &styles[row_index][column_index];
1613 let old_value = self.model.get_cell_style_or_none(sheet, row, column)?;
1614 self.model.set_cell_style(sheet, row, column, style)?;
1615 diff_list.push(Diff::SetCellStyle {
1616 sheet,
1617 row,
1618 column,
1619 old_value: Box::new(old_value),
1620 new_value: Box::new(style.clone()),
1621 });
1622 }
1623 }
1624 self.push_diff_list(diff_list);
1625
1626 if let Ok(worksheet) = self.model.workbook.worksheet_mut(sheet) {
1628 if let Some(view) = worksheet.views.get_mut(&self.model.view_id) {
1629 view.range = [row_start, column_start, last_row, last_column];
1630 }
1631 }
1632 Ok(())
1633 }
1634
1635 fn update_single_cell_style(
1637 &mut self,
1638 sheet: u32,
1639 row: i32,
1640 column: i32,
1641 style_path: &str,
1642 value: &str,
1643 diff_list: &mut Vec<Diff>,
1644 ) -> Result<(), String> {
1645 let old_value = self.model.get_cell_style_or_none(sheet, row, column)?;
1647
1648 let old_style = self.model.get_style_for_cell(sheet, row, column)?;
1651 let new_style = update_style(&old_style, style_path, value)?;
1652 self.model.set_cell_style(sheet, row, column, &new_style)?;
1653 diff_list.push(Diff::SetCellStyle {
1654 sheet,
1655 row,
1656 column,
1657 old_value: Box::new(old_value),
1658 new_value: Box::new(new_style),
1659 });
1660 Ok(())
1661 }
1662
1663 pub fn update_range_style(
1667 &mut self,
1668 range: &Area,
1669 style_path: &str,
1670 value: &str,
1671 ) -> Result<(), String> {
1672 let sheet = range.sheet;
1673 let mut diff_list = Vec::new();
1674 if range.row == 1 && range.height == LAST_ROW {
1675 let styled_rows = &self.model.workbook.worksheet(sheet)?.rows.clone();
1677 let data_rows: Vec<i32> = self
1680 .model
1681 .workbook
1682 .worksheet(sheet)?
1683 .sheet_data
1684 .keys()
1685 .copied()
1686 .collect();
1687 for column in range.column..range.column + range.width {
1688 let old_style = self.model.get_column_style(sheet, column)?;
1690 let style = match old_style.as_ref() {
1691 Some(s) => s,
1692 None => &Style::default(),
1693 };
1694 let style = update_style(style, style_path, value)?;
1695 self.model.set_column_style(sheet, column, &style)?;
1696 diff_list.push(Diff::SetColumnStyle {
1697 sheet,
1698 column,
1699 old_value: Box::new(old_style),
1700 new_value: Box::new(style),
1701 });
1702
1703 for row_s in styled_rows.iter() {
1705 let row = row_s.r;
1706 self.update_single_cell_style(
1707 sheet,
1708 row,
1709 column,
1710 style_path,
1711 value,
1712 &mut diff_list,
1713 )?;
1714 }
1715
1716 for &row in &data_rows {
1719 if let Some(data_row) =
1720 self.model.workbook.worksheet(sheet)?.sheet_data.get(&row)
1721 {
1722 if data_row.get(&column).is_some() {
1723 self.update_single_cell_style(
1725 sheet,
1726 row,
1727 column,
1728 style_path,
1729 value,
1730 &mut diff_list,
1731 )?;
1732 }
1733 }
1734 }
1735 }
1736 } else if range.column == 1 && range.width == LAST_COLUMN {
1737 let styled_columns = &self.model.workbook.worksheet(sheet)?.cols.clone();
1739 for row in range.row..range.row + range.height {
1740 let columns: Vec<i32> = self
1742 .model
1743 .workbook
1744 .worksheet(sheet)?
1745 .sheet_data
1746 .get(&row)
1747 .map(|row_data| row_data.keys().copied().collect())
1748 .unwrap_or_default();
1749 for column in columns {
1750 self.update_single_cell_style(
1751 sheet,
1752 row,
1753 column,
1754 style_path,
1755 value,
1756 &mut diff_list,
1757 )?;
1758 }
1759
1760 for col in styled_columns.iter() {
1762 for column in col.min..col.max + 1 {
1763 self.update_single_cell_style(
1764 sheet,
1765 row,
1766 column,
1767 style_path,
1768 value,
1769 &mut diff_list,
1770 )?;
1771 }
1772 }
1773
1774 let old_style = self.model.get_row_style(sheet, row)?;
1776 let style = match old_style.as_ref() {
1777 Some(s) => s,
1778 None => &Style::default(),
1779 };
1780 let style = update_style(style, style_path, value)?;
1781 self.model.set_row_style(sheet, row, &style)?;
1782 diff_list.push(Diff::SetRowStyle {
1783 sheet,
1784 row,
1785 old_value: Box::new(old_style),
1786 new_value: Box::new(style),
1787 });
1788 }
1789 } else {
1790 for row in range.row..range.row + range.height {
1791 for column in range.column..range.column + range.width {
1792 self.update_single_cell_style(
1793 sheet,
1794 row,
1795 column,
1796 style_path,
1797 value,
1798 &mut diff_list,
1799 )?;
1800 }
1801 }
1802 }
1803 self.push_diff_list(diff_list);
1804 Ok(())
1805 }
1806
1807 pub fn get_cell_style(&self, sheet: u32, row: i32, column: i32) -> Result<Style, String> {
1816 let mut style = self.model.get_style_for_cell(sheet, row, column)?;
1817
1818 let border_top = if row > 1 {
1820 self.model
1821 .get_style_for_cell(sheet, row - 1, column)?
1822 .border
1823 .bottom
1824 } else {
1825 None
1826 };
1827
1828 let border_right = if column < LAST_COLUMN {
1829 self.model
1830 .get_style_for_cell(sheet, row, column + 1)?
1831 .border
1832 .left
1833 } else {
1834 None
1835 };
1836
1837 let border_bottom = if row < LAST_ROW {
1838 self.model
1839 .get_style_for_cell(sheet, row + 1, column)?
1840 .border
1841 .top
1842 } else {
1843 None
1844 };
1845
1846 let border_left = if column > 1 {
1847 self.model
1848 .get_style_for_cell(sheet, row, column - 1)?
1849 .border
1850 .right
1851 } else {
1852 None
1853 };
1854
1855 if is_max_border(style.border.top.as_ref(), border_top.as_ref()) {
1856 style.border.top = border_top;
1857 }
1858
1859 if is_max_border(style.border.right.as_ref(), border_right.as_ref()) {
1860 style.border.right = border_right;
1861 }
1862
1863 if is_max_border(style.border.bottom.as_ref(), border_bottom.as_ref()) {
1864 style.border.bottom = border_bottom;
1865 }
1866
1867 if is_max_border(style.border.left.as_ref(), border_left.as_ref()) {
1868 style.border.left = border_left;
1869 }
1870
1871 Ok(style)
1872 }
1873
1874 pub fn get_extended_cell_style(
1879 &self,
1880 sheet: u32,
1881 row: i32,
1882 column: i32,
1883 ) -> Result<ExtendedStyle, String> {
1884 let mut extended = self.model.get_extended_style_for_cell(sheet, row, column)?;
1885
1886 let border_top = if row > 1 {
1887 self.model
1888 .get_style_for_cell(sheet, row - 1, column)?
1889 .border
1890 .bottom
1891 } else {
1892 None
1893 };
1894
1895 let border_right = if column < LAST_COLUMN {
1896 self.model
1897 .get_style_for_cell(sheet, row, column + 1)?
1898 .border
1899 .left
1900 } else {
1901 None
1902 };
1903
1904 let border_bottom = if row < LAST_ROW {
1905 self.model
1906 .get_style_for_cell(sheet, row + 1, column)?
1907 .border
1908 .top
1909 } else {
1910 None
1911 };
1912
1913 let border_left = if column > 1 {
1914 self.model
1915 .get_style_for_cell(sheet, row, column - 1)?
1916 .border
1917 .right
1918 } else {
1919 None
1920 };
1921
1922 if is_max_border(extended.style.border.top.as_ref(), border_top.as_ref()) {
1923 extended.style.border.top = border_top;
1924 }
1925
1926 if is_max_border(extended.style.border.right.as_ref(), border_right.as_ref()) {
1927 extended.style.border.right = border_right;
1928 }
1929
1930 if is_max_border(
1931 extended.style.border.bottom.as_ref(),
1932 border_bottom.as_ref(),
1933 ) {
1934 extended.style.border.bottom = border_bottom;
1935 }
1936
1937 if is_max_border(extended.style.border.left.as_ref(), border_left.as_ref()) {
1938 extended.style.border.left = border_left;
1939 }
1940
1941 Ok(extended)
1942 }
1943
1944 #[inline]
1949 pub fn get_worksheets_properties(&self) -> Vec<SheetProperties> {
1950 self.model.get_worksheets_properties()
1951 }
1952
1953 pub fn set_theme(&mut self, theme: Theme) {
1955 let old_value = self.model.workbook.theme.clone();
1956 let new_value = theme.clone();
1957 self.model.set_theme(theme);
1958 self.push_diff_list(vec![Diff::SetTheme {
1959 old_value: Box::new(old_value),
1960 new_value: Box::new(new_value),
1961 }]);
1962 }
1963
1964 pub fn get_theme(&self) -> Theme {
1966 self.model.get_theme()
1967 }
1968
1969 pub fn resolve_color(&self, color: &Color) -> String {
1972 color.to_rgb(&self.model.workbook.theme)
1973 }
1974
1975 pub fn set_show_grid_lines(&mut self, sheet: u32, show_grid_lines: bool) -> Result<(), String> {
1977 let old_value = self.model.workbook.worksheet(sheet)?.show_grid_lines;
1978 self.model.set_show_grid_lines(sheet, show_grid_lines)?;
1979
1980 self.push_diff_list(vec![Diff::SetShowGridLines {
1981 sheet,
1982 new_value: show_grid_lines,
1983 old_value,
1984 }]);
1985 Ok(())
1986 }
1987
1988 pub fn get_show_grid_lines(&self, sheet: u32) -> Result<bool, String> {
1990 Ok(self.model.workbook.worksheet(sheet)?.show_grid_lines)
1991 }
1992
1993 pub fn get_last_non_empty_in_row_before_column(
1997 &self,
1998 sheet: u32,
1999 row: i32,
2000 column: i32,
2001 ) -> Result<Option<i32>, String> {
2002 let worksheet = self.model.workbook.worksheet(sheet)?;
2003 let data = worksheet.sheet_data.get(&row);
2004 if let Some(row_data) = data {
2005 let mut last_column = None;
2006 let mut columns: Vec<i32> = row_data.keys().copied().collect();
2007 columns.sort_unstable();
2008 for col in columns {
2009 if col < column {
2010 if let Some(cell) = worksheet.cell(row, col) {
2011 if matches!(cell, Cell::EmptyCell { .. }) {
2012 continue;
2013 }
2014 }
2015 last_column = Some(col);
2016 }
2017 }
2018 Ok(last_column)
2019 } else {
2020 Ok(None)
2021 }
2022 }
2023
2024 pub fn get_first_non_empty_in_row_after_column(
2028 &self,
2029 sheet: u32,
2030 row: i32,
2031 column: i32,
2032 ) -> Result<Option<i32>, String> {
2033 let worksheet = self.model.workbook.worksheet(sheet)?;
2034 let data = worksheet.sheet_data.get(&row);
2035 if let Some(row_data) = data {
2036 let mut columns: Vec<i32> = row_data.keys().copied().collect();
2037 columns.sort_unstable();
2039 for col in columns {
2040 if col > column {
2041 if let Some(cell) = worksheet.cell(row, col) {
2042 if matches!(cell, Cell::EmptyCell { .. }) {
2043 continue;
2044 }
2045 }
2046 return Ok(Some(col));
2047 }
2048 }
2049 }
2050 Ok(None)
2051 }
2052
2053 pub fn get_cell_array_structure(
2055 &self,
2056 sheet: u32,
2057 row: i32,
2058 column: i32,
2059 ) -> Result<CellArrayStructure, String> {
2060 let cell = self
2061 .model
2062 .workbook
2063 .worksheet(sheet)?
2064 .cell(row, column)
2065 .cloned()
2066 .unwrap_or_default();
2067 match cell {
2068 Cell::EmptyCell { .. }
2069 | Cell::BooleanCell { .. }
2070 | Cell::NumberCell { .. }
2071 | Cell::ErrorCell { .. }
2072 | Cell::SharedString { .. }
2073 | Cell::CellFormula { .. } => Ok(CellArrayStructure::SingleCell),
2074 Cell::SpillCell { a, .. } => {
2075 let (m_row, m_column) = a;
2076 let m_cell = self
2077 .model
2078 .workbook
2079 .worksheet(sheet)?
2080 .cell(m_row, m_column)
2081 .cloned()
2082 .unwrap_or_default();
2083 let (width, height, is_dynamic) = match m_cell {
2084 Cell::ArrayFormula {
2085 r,
2086 kind: ArrayKind::Dynamic,
2087 ..
2088 } => (r.0, r.1, true),
2089 Cell::ArrayFormula {
2090 r,
2091 kind: ArrayKind::Cse,
2092 ..
2093 } => (r.0, r.1, false),
2094 _ => return Err("Invalid structure".to_string()),
2095 };
2096 if is_dynamic {
2097 Ok(CellArrayStructure::DynamicChild(
2098 m_row, m_column, width, height,
2099 ))
2100 } else {
2101 Ok(CellArrayStructure::ArrayChild(
2102 m_row, m_column, width, height,
2103 ))
2104 }
2105 }
2106 Cell::ArrayFormula {
2107 r,
2108 kind: ArrayKind::Dynamic,
2109 ..
2110 } => Ok(CellArrayStructure::DynamicAnchor(r.0, r.1)),
2111 Cell::ArrayFormula {
2112 r,
2113 kind: ArrayKind::Cse,
2114 ..
2115 } => Ok(CellArrayStructure::ArrayAnchor(r.0, r.1)),
2116 }
2117 }
2118
2119 pub fn set_user_array_formula(
2121 &mut self,
2122 sheet: u32,
2123 row: i32,
2124 column: i32,
2125 width: i32,
2126 height: i32,
2127 formula: &str,
2128 ) -> Result<(), String> {
2129 let ws = self.model.workbook.worksheet(sheet)?;
2130 let mut old_values = Vec::new();
2131 for r in row..row + height {
2132 let mut row_vals = Vec::new();
2133 for c in column..column + width {
2134 let cell = ws.cell(r, c).cloned();
2135 let cell = if matches!(cell, Some(Cell::SpillCell { .. })) {
2137 None
2138 } else {
2139 cell
2140 };
2141 row_vals.push(cell);
2142 }
2143 old_values.push(row_vals);
2144 }
2145 self.model
2146 .set_user_array_formula(sheet, row, column, width, height, formula)?;
2147 self.push_diff_list(vec![Diff::SetArrayValue {
2148 sheet,
2149 row,
2150 column,
2151 width,
2152 height,
2153 new_value: formula.to_string(),
2154 old_values,
2155 }]);
2156 self.evaluate_if_not_paused();
2157 Ok(())
2158 }
2159
2160 pub fn get_defined_name_list(&self) -> Vec<(String, Option<u32>, String)> {
2162 self.model.get_defined_name_list()
2163 }
2164
2165 pub fn delete_defined_name(&mut self, name: &str, scope: Option<u32>) -> Result<(), String> {
2167 let old_value = self.model.get_defined_name_formula(name, scope)?;
2168 let diff_list = vec![Diff::DeleteDefinedName {
2169 name: name.to_string(),
2170 scope,
2171 old_value,
2172 }];
2173 self.push_diff_list(diff_list);
2174 self.model.delete_defined_name(name, scope)?;
2175 self.evaluate_if_not_paused();
2176 Ok(())
2177 }
2178
2179 pub fn new_defined_name(
2181 &mut self,
2182 name: &str,
2183 scope: Option<u32>,
2184 formula: &str,
2185 ) -> Result<(), String> {
2186 self.model.new_defined_name(name, scope, formula)?;
2187 let value = self.model.get_defined_name_formula(name, scope)?;
2192 let diff_list = vec![Diff::CreateDefinedName {
2193 name: name.to_string(),
2194 scope,
2195 value,
2196 }];
2197 self.push_diff_list(diff_list);
2198 self.evaluate_if_not_paused();
2199 Ok(())
2200 }
2201
2202 pub fn update_defined_name(
2204 &mut self,
2205 name: &str,
2206 scope: Option<u32>,
2207 new_name: &str,
2208 new_scope: Option<u32>,
2209 new_formula: &str,
2210 ) -> Result<(), String> {
2211 let old_formula = self
2214 .model
2215 .get_defined_name_formula(name, scope)
2216 .map_err(|_| "General: Failed to get old name")?;
2217 self.model
2218 .update_defined_name(name, scope, new_name, new_scope, new_formula)?;
2219 let new_formula_internal = self.model.get_defined_name_formula(new_name, new_scope)?;
2222 let diff_list = vec![Diff::UpdateDefinedName {
2223 name: name.to_string(),
2224 scope,
2225 old_formula,
2226 new_name: new_name.to_string(),
2227 new_scope,
2228 new_formula: new_formula_internal,
2229 }];
2230 self.push_diff_list(diff_list);
2231 self.evaluate_if_not_paused();
2232 Ok(())
2233 }
2234
2235 pub fn is_valid_defined_name(
2237 &mut self,
2238 name: &str,
2239 scope: Option<u32>,
2240 formula: &str,
2241 ) -> Result<Option<u32>, String> {
2242 self.model.is_valid_defined_name(name, scope, formula)
2243 }
2244
2245 pub fn set_timezone(&mut self, timezone: &str) -> Result<(), String> {
2247 let diff_list = vec![Diff::SetTimezone {
2248 old_value: self.get_timezone(),
2249 new_value: timezone.to_string(),
2250 }];
2251 self.push_diff_list(diff_list);
2252 self.model.set_timezone(timezone)
2253 }
2254
2255 pub fn set_locale(&mut self, locale: &str) -> Result<(), String> {
2257 let diff_list = vec![Diff::SetLocale {
2258 old_value: self.get_locale(),
2259 new_value: locale.to_string(),
2260 }];
2261 self.push_diff_list(diff_list);
2262 self.model.set_locale(locale)
2263 }
2264
2265 pub fn get_timezone(&self) -> String {
2267 self.model.get_timezone()
2268 }
2269
2270 pub fn get_locale(&self) -> String {
2272 self.model.get_locale()
2273 }
2274
2275 pub fn get_language(&self) -> String {
2277 self.model.get_language()
2278 }
2279
2280 pub fn set_language(&mut self, language: &str) -> Result<(), String> {
2282 self.model.set_language(language)
2283 }
2284
2285 pub fn get_fmt_settings(&self) -> FmtSettings {
2287 self.model.get_fmt_settings()
2288 }
2289
2290 pub(crate) fn push_diff_list(&mut self, diff_list: DiffList) {
2293 self.send_queue.push(QueueDiffs {
2294 r#type: DiffType::Redo,
2295 list: diff_list.clone(),
2296 });
2297 self.history.push(diff_list);
2298 }
2299
2300 pub(super) fn evaluate_if_not_paused(&mut self) {
2301 if !self.pause_evaluation {
2302 self.model.evaluate();
2303 }
2304 }
2305}
2306
2307#[cfg(test)]
2308mod tests {
2309 use crate::{
2310 types::{HorizontalAlignment, VerticalAlignment},
2311 user_model::common::{horizontal, selected_sheet_after_move, vertical},
2312 };
2313
2314 #[test]
2315 fn test_selected_sheet_after_move() {
2316 assert_eq!(selected_sheet_after_move(0, 0, 2), 2);
2318 assert_eq!(selected_sheet_after_move(3, 3, 0), 0);
2319
2320 assert_eq!(selected_sheet_after_move(2, 0, 2), 1);
2323 assert_eq!(selected_sheet_after_move(0, 2, 0), 1);
2325
2326 assert_eq!(selected_sheet_after_move(3, 1, 2), 3);
2329 }
2330
2331 #[test]
2332 fn test_vertical() {
2333 let all = vec![
2334 VerticalAlignment::Bottom,
2335 VerticalAlignment::Center,
2336 VerticalAlignment::Distributed,
2337 VerticalAlignment::Justify,
2338 VerticalAlignment::Top,
2339 ];
2340 for a in all {
2341 assert_eq!(vertical(&format!("{a}")), Ok(a));
2342 }
2343 }
2344
2345 #[test]
2346 fn test_horizontal() {
2347 let all = vec![
2348 HorizontalAlignment::Center,
2349 HorizontalAlignment::CenterContinuous,
2350 HorizontalAlignment::Distributed,
2351 HorizontalAlignment::Fill,
2352 HorizontalAlignment::General,
2353 HorizontalAlignment::Justify,
2354 HorizontalAlignment::Left,
2355 HorizontalAlignment::Right,
2356 ];
2357 for a in all {
2358 assert_eq!(horizontal(&format!("{a}")), Ok(a));
2359 }
2360 }
2361}