1use logisheets_base::{CellValue, SheetId};
2use logisheets_parser::unparse::Stringify;
3
4use crate::connectors::NameFetcher;
5use crate::controller::display::{
6 SheetColInfo, SheetComments, SheetMergeCells, SheetRowInfo, SheetStyles, SheetValues, Value,
7};
8use crate::id_manager::TextIdManager;
9use crate::version_manager::diff::{Diff, SheetDiff};
10use crate::Worksheet;
11
12use super::display::{
13 BlockInfo, CellFormulaValue, CellStyle, ColInfo, Comment, DisplayPatch, DisplayResponse,
14 MergeCell, RowInfo, SheetBlocks,
15};
16use super::style::StyleConverter;
17use super::Controller;
18
19#[derive(Debug, Default)]
20pub struct SheetViewer {
21 pub values: Vec<CellFormulaValue>,
22 pub styles: Vec<CellStyle>,
23 pub row_infos: Vec<RowInfo>,
24 pub col_infos: Vec<ColInfo>,
25 pub comments: Vec<Comment>,
26 pub merge_cells: Vec<MergeCell>,
27 pub blocks: Vec<BlockInfo>,
28}
29
30impl SheetViewer {
31 pub fn display_with_diff(
32 mut self,
33 controller: &Controller,
34 sheet_id: SheetId,
35 diff: SheetDiff,
36 ) -> DisplayResponse {
37 if diff.diff_unavailable() {
38 self.load_sheet(controller, sheet_id);
39 } else {
40 let ws = Worksheet::from(sheet_id, controller);
41 diff.data.into_iter().for_each(|diff| match diff {
42 Diff::CellValue(cell_id) => {
43 let formula = ws.get_formula_by_id(cell_id).unwrap_or_default();
44 let value = ws.get_value_by_id(cell_id).unwrap_or_default();
45 if let Ok((row, col)) = ws.get_cell_idx(cell_id) {
46 self.values.push(CellFormulaValue {
47 row,
48 col,
49 formula,
50 value,
51 });
52 }
53 }
54 Diff::CellStyle(cell_id) => {
55 let style = ws.get_style_by_id(cell_id).unwrap();
56 if let Ok((row, col)) = ws.get_cell_idx(cell_id) {
57 self.styles.push(CellStyle { row, col, style })
58 }
59 }
60 Diff::RowInfo(row_id) => {
61 if let Some(info) = ws.get_row_info_by_id(row_id) {
62 self.row_infos.push(info);
63 }
64 }
65 Diff::ColInfo(col_id) => {
66 if let Some(info) = ws.get_col_info_by_id(col_id) {
67 self.col_infos.push(info);
68 }
69 }
70 Diff::BlockUpdate {
71 id,
72 cnt,
73 is_row: row,
74 } => {
75 let (mut row_cnt, mut col_cnt) = ws.get_block_size(id).unwrap();
76 if row {
77 row_cnt += cnt;
78 } else {
79 col_cnt += cnt;
80 }
81 let (master_row, master_col) = ws.get_block_master_cell(id).unwrap();
82 for r in master_row..=row_cnt {
83 for c in master_col..=col_cnt {
84 let style = ws.get_style(r, c);
85 let formula = ws.get_formula(r, c);
86 let value = ws.get_value(r, c);
87 match (style, formula, value) {
88 (Ok(s), Ok(f), Ok(v)) => {
89 self.values.push(CellFormulaValue {
90 row: r,
91 col: c,
92 formula: f,
93 value: v,
94 });
95 self.styles.push(CellStyle {
96 row: r,
97 col: c,
98 style: s,
99 });
100 }
101 _ => continue,
102 }
103 }
104 }
105 }
106 Diff::SheetProperty => todo!(),
107 Diff::Unavailable => unreachable!(),
108 });
109 }
110
111 let idx = controller
112 .status
113 .sheet_pos_manager
114 .get_sheet_idx(&sheet_id)
115 .unwrap();
116 let patches = self.to_patches(idx);
117 DisplayResponse {
118 patches,
119 incremental: true,
120 }
121 }
122
123 pub fn display_with_idx(self, controller: &Controller, sheet_idx: usize) -> DisplayResponse {
124 let sheet_id = controller
125 .status
126 .sheet_pos_manager
127 .get_sheet_id(sheet_idx)
128 .unwrap();
129 let mut viewer = self;
130 viewer.load_sheet(controller, sheet_id);
131 let patches = viewer.to_patches(sheet_idx);
132 DisplayResponse {
133 patches,
134 incremental: false,
135 }
136 }
137
138 fn load_sheet(&mut self, controller: &Controller, sheet_id: SheetId) {
139 let s = &controller.status.container;
140 let navigator = &controller.status.navigator;
141 let style_manager = &controller.status.style_manager;
142 let formula_manager = &controller.status.formula_manager;
143 let range_manager = &controller.status.range_manager;
144 let cube_manager = &controller.status.cube_manager;
145 let ext_ref_manager = &controller.status.ext_ref_manager;
146 let func_manager = &controller.status.func_id_manager;
147 let sheet_id_manager = &controller.status.sheet_id_manager;
148 let external_links_manager = &controller.status.external_links_manager;
149 let text_id_manager = &controller.status.text_id_manager;
150 let name_id_manager = &controller.status.name_id_manager;
151 let sheet_data = s.data.get(&sheet_id);
152 if let Some(sheet_data) = sheet_data {
153 sheet_data
154 .col_info
155 .get_all_col_info()
156 .into_iter()
157 .for_each(|(col_id, info)| {
158 if let Ok(idx) = navigator.fetch_col_idx(&sheet_id, &col_id) {
160 let info = ColInfo {
161 idx,
162 width: info.width.unwrap_or(get_default_col_width()),
163 hidden: info.hidden,
164 };
165 self.col_infos.push(info);
166 }
167 });
168 sheet_data
169 .row_info
170 .get_all_row_info()
171 .into_iter()
172 .for_each(|(row_id, info)| {
173 if let Ok(idx) = navigator.fetch_row_idx(&sheet_id, &row_id) {
175 let info = RowInfo {
176 idx,
177 height: info.ht.unwrap_or(get_default_row_height()),
178 hidden: info.hidden,
179 };
180 self.row_infos.push(info)
181 }
182 });
183 let style_converter = StyleConverter {
184 theme_manager: &controller.settings.theme,
185 };
186 sheet_data.cells.iter().for_each(|(cell_id, cell)| {
187 let coord = navigator.fetch_cell_idx(&sheet_id, cell_id);
188 if coord.is_err() {
189 panic!()
190 }
191 let (row, col) = coord.unwrap();
192 let raw_style = style_manager.get_cell_style(cell.style);
193 self.styles.push(CellStyle {
194 row,
195 col,
196 style: style_converter.convert_style(raw_style),
197 });
198 let mut name_fetcher = NameFetcher {
199 func_manager,
200 sheet_id_manager,
201 external_links_manager,
202 text_id_manager,
203 name_id_manager,
204 navigator,
205 formula_manager,
206 range_manager,
207 cube_manager,
208 ext_ref_manager,
209 };
210
211 let (formula, has_formula) =
212 match formula_manager.formulas.get(&(sheet_id, cell_id.clone())) {
213 Some(n) => (n.unparse(&mut name_fetcher, sheet_id).unwrap(), true),
214 None => (String::from(""), false),
215 };
216 let v = convert_value(row, col, &cell.value, formula, has_formula, text_id_manager);
217 self.values.push(v);
218 });
219 }
220 let cell_attachments = &controller.status.cell_attachment_manager;
221 let comments = &cell_attachments.comments;
222 if let Some(sheet_comments) = comments.data.get(&sheet_id) {
223 sheet_comments.comments.iter().for_each(|(cell_id, c)| {
224 if let Ok((row, col)) = navigator.fetch_cell_idx(&sheet_id, cell_id) {
226 let author = comments
227 .get_author_name(&c.author)
228 .unwrap_or(String::from("unknown author"));
229 self.comments.push(Comment {
230 row,
231 col,
232 author,
233 content: c.text.clone(),
234 })
235 }
236 });
237 }
238 let merge_cells_manager = &cell_attachments.merge_cells;
239 if let Some(merge_cells) = merge_cells_manager.data.get(&sheet_id) {
240 merge_cells.iter().for_each(|(start, end)| {
241 if let Ok((row_start, col_start)) =
242 navigator.fetch_normal_cell_idx(&sheet_id, &start)
243 {
244 let (row_end, col_end) =
245 navigator.fetch_normal_cell_idx(&sheet_id, &end).unwrap();
246 let mc = MergeCell {
247 row_start,
248 col_start,
249 row_end,
250 col_end,
251 };
252 self.merge_cells.push(mc);
253 }
254 });
255 }
256 if let Some(sn) = navigator.sheet_navs.clone().get(&sheet_id) {
257 sn.data.blocks.iter().for_each(|(block_id, block_place)| {
258 let (row_cnt, col_cnt) = block_place.get_block_size();
259 let master = &block_place.master;
260 let (master_row, master_col) =
261 navigator.fetch_normal_cell_idx(&sheet_id, &master).unwrap();
262 let block_info = BlockInfo {
263 block_id: *block_id,
264 row_start: master_row,
265 row_cnt,
266 col_start: master_col,
267 col_cnt,
268 };
269 self.blocks.push(block_info)
270 });
271 }
272 }
273
274 fn to_patches(self, sheet_idx: usize) -> Vec<DisplayPatch> {
275 let mut res = vec![];
276 if self.values.len() > 0 {
277 let values = SheetValues {
278 sheet_idx,
279 values: self.values,
280 };
281 res.push(DisplayPatch::Values(values))
282 }
283 if self.styles.len() > 0 {
284 let styles = SheetStyles {
285 sheet_idx,
286 styles: self.styles,
287 };
288 res.push(DisplayPatch::Styles(styles))
289 }
290 if self.row_infos.len() > 0 {
291 let row_info = SheetRowInfo {
292 sheet_idx,
293 info: self.row_infos,
294 default_height: get_default_row_height(), };
296 res.push(DisplayPatch::RowInfo(row_info))
297 }
298 if self.col_infos.len() > 0 {
299 let col_info = SheetColInfo {
300 sheet_idx,
301 info: self.col_infos,
302 default_width: get_default_col_width(), };
304 res.push(DisplayPatch::ColInfo(col_info))
305 }
306 if self.comments.len() > 0 {
307 let comments = SheetComments {
308 sheet_idx,
309 comments: self.comments,
310 };
311 res.push(DisplayPatch::Comments(comments))
312 }
313 if self.merge_cells.len() > 0 {
314 let merge_cells = SheetMergeCells {
315 sheet_idx,
316 merge_cells: self.merge_cells,
317 };
318 res.push(DisplayPatch::MergeCells(merge_cells))
319 }
320 if self.blocks.len() > 0 {
321 let blocks = SheetBlocks {
322 sheet_idx,
323 blocks: self.blocks,
324 };
325 res.push(DisplayPatch::Blocks(blocks))
326 }
327 res
328 }
329}
330
331fn get_default_col_width() -> f64 {
332 8.38
333}
334
335fn get_default_row_height() -> f64 {
336 14.25
337}
338
339fn convert_value(
340 row: usize,
341 col: usize,
342 cv: &CellValue,
343 formula: String,
344 has_formula: bool,
345 text_id_manager: &TextIdManager,
346) -> CellFormulaValue {
347 let value = match cv {
348 CellValue::Blank => {
349 if has_formula {
350 Value::Number(0_f64)
351 } else {
352 Value::Str(String::from(""))
353 }
354 }
355 CellValue::Boolean(b) => Value::Bool(*b),
356 CellValue::Error(e) => Value::Error(e.to_string()),
357 CellValue::String(s) => Value::Str(
358 text_id_manager
359 .get_string(s)
360 .unwrap_or(String::from("Error")),
361 ),
362 CellValue::Number(n) => Value::Number(*n),
363 CellValue::InlineStr(_) => todo!(),
364 CellValue::FormulaStr(s) => Value::Str(s.clone()),
365 };
366 CellFormulaValue {
367 row,
368 col,
369 formula,
370 value,
371 }
372}