logisheets_controller/controller/
viewer.rs

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                    // TODO: Optimize here.
159                    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                    // TODO: Optimize here.
174                    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                // TODO: Optimize here.
225                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(), // TODO: use settings
295            };
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(), // TODO: use settings
303            };
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}