umya_spreadsheet/structs/
cell.rs

1use crate::helper::coordinate::*;
2use crate::helper::formula::*;
3use crate::helper::number_format::*;
4use crate::reader::driver::*;
5use crate::structs::CellFormula;
6use crate::structs::CellFormulaValues;
7use crate::structs::CellRawValue;
8use crate::structs::CellValue;
9use crate::structs::Coordinate;
10use crate::structs::Hyperlink;
11use crate::structs::NumberingFormat;
12use crate::structs::RichText;
13use crate::structs::SharedStringItem;
14use crate::structs::SharedStringTable;
15use crate::structs::Style;
16use crate::structs::Stylesheet;
17use crate::structs::UInt32Value;
18use crate::traits::AdjustmentCoordinate;
19use crate::traits::AdjustmentCoordinateWith2Sheet;
20use crate::writer::driver::*;
21use quick_xml::events::{BytesStart, Event};
22use quick_xml::Reader;
23use quick_xml::Writer;
24use std::borrow::Cow;
25use std::collections::HashMap;
26use std::io::Cursor;
27use std::sync::{Arc, RwLock};
28
29#[derive(Clone, Default, Debug, PartialEq, PartialOrd)]
30pub struct Cell {
31    coordinate: Coordinate,
32    pub(crate) cell_value: Box<CellValue>,
33    style: Box<Style>,
34    hyperlink: Option<Box<Hyperlink>>,
35    cell_meta_index: UInt32Value,
36}
37impl Cell {
38    #[inline]
39    pub fn get_cell_value(&self) -> &CellValue {
40        &self.cell_value
41    }
42
43    #[inline]
44    pub fn get_cell_value_mut(&mut self) -> &mut CellValue {
45        &mut self.cell_value
46    }
47
48    #[inline]
49    pub fn set_cell_value(&mut self, value: CellValue) -> &mut Self {
50        self.cell_value = Box::new(value);
51        self
52    }
53
54    #[inline]
55    pub fn get_style(&self) -> &Style {
56        &self.style
57    }
58
59    #[inline]
60    pub fn get_style_mut(&mut self) -> &mut Style {
61        &mut self.style
62    }
63
64    #[inline]
65    pub fn set_style(&mut self, value: Style) -> &mut Self {
66        self.style = Box::new(value);
67        self
68    }
69
70    #[inline]
71    pub fn get_coordinate(&self) -> &Coordinate {
72        &self.coordinate
73    }
74
75    #[inline]
76    pub fn get_coordinate_mut(&mut self) -> &mut Coordinate {
77        &mut self.coordinate
78    }
79
80    /// Change the coordinate.
81    /// Change the formula address as well.
82    pub fn set_coordinate<T>(&mut self, coordinate: T) -> &mut Self
83    where
84        T: Into<CellCoordinates>,
85    {
86        let CellCoordinates { col, row } = coordinate.into();
87
88        let formula = self.cell_value.get_formula();
89        if formula != "" {
90            let org_col_num = self.coordinate.get_col_num();
91            let org_row_num = self.coordinate.get_row_num();
92            let offset_col_num = col as i32 - *org_col_num as i32;
93            let offset_row_num = row as i32 - *org_row_num as i32;
94            let mut tokens = parse_to_tokens(format!("={}", formula));
95            adjustment_formula_coordinate(&mut tokens, &offset_col_num, &offset_row_num);
96            let result_formula = render(tokens.as_ref());
97            self.cell_value.set_formula(result_formula);
98        }
99        self.coordinate.set_col_num(col);
100        self.coordinate.set_row_num(row);
101        self
102    }
103
104    #[inline]
105    pub fn get_hyperlink(&self) -> Option<&Hyperlink> {
106        self.hyperlink.as_deref()
107    }
108
109    #[inline]
110    pub fn get_hyperlink_mut(&mut self) -> &mut Hyperlink {
111        if self.hyperlink.is_some() {
112            return self.hyperlink.as_mut().unwrap();
113        }
114        self.set_hyperlink(Hyperlink::default());
115        self.hyperlink.as_mut().unwrap()
116    }
117
118    #[inline]
119    pub fn set_hyperlink(&mut self, value: Hyperlink) -> &mut Self {
120        self.hyperlink = Some(Box::new(value));
121        self
122    }
123
124    #[inline]
125    pub fn get_cell_meta_index(&self) -> &u32 {
126        self.cell_meta_index.get_value()
127    }
128
129    #[inline]
130    pub fn set_cell_meta_index(&mut self, value: u32) -> &mut Self {
131        self.cell_meta_index.set_value(value);
132        self
133    }
134
135    #[inline]
136    pub fn get_value(&self) -> Cow<'static, str> {
137        self.cell_value.get_value()
138    }
139
140    #[inline]
141    pub fn get_value_number(&self) -> Option<f64> {
142        self.cell_value.get_value_number()
143    }
144
145    #[inline]
146    pub fn get_value_lazy(&mut self) -> Cow<'static, str> {
147        self.cell_value.get_value_lazy()
148    }
149
150    /// Set the cell's value after trying to convert `value` into one of the supported data types.
151    /// <br />
152    /// Types that `value` may be converted to:
153    /// - `Empty` - if the string was `""`
154    /// - `Numeric` - if the string can be parsed to an `f64`
155    /// - `Bool` - if the string was either `"TRUE"` or `"FALSE"`
156    /// - `Error` - if the string was either `"#VALUE!"`,`"#REF!"`,`"#NUM!"`,`"#NULL!"`,`"#NAME?"`,`"#N/A"`,`"#DATA!"` or `"#DIV/0!"`
157    /// - `String` - if the string does not fulfill any of the other conditions
158    #[inline]
159    pub fn set_value<S: Into<String>>(&mut self, value: S) -> &mut Self {
160        self.cell_value.set_value(value);
161        self
162    }
163
164    #[inline]
165    pub(crate) fn set_value_crate<S: Into<String>>(&mut self, value: S) -> &mut Self {
166        self.cell_value.set_value_crate(value);
167        self
168    }
169
170    #[inline]
171    pub fn set_value_lazy<S: Into<String>>(&mut self, value: S) -> &mut Self {
172        self.cell_value.set_value_lazy(value);
173        self
174    }
175
176    #[inline]
177    pub fn set_value_string<S: Into<String>>(&mut self, value: S) -> &mut Self {
178        self.cell_value.set_value_string(value);
179        self
180    }
181
182    #[inline]
183    pub(crate) fn set_value_string_crate<S: Into<String>>(&mut self, value: S) -> &mut Self {
184        self.cell_value.set_value_string_crate(value);
185        self
186    }
187
188    #[inline]
189    pub fn set_value_bool(&mut self, value: bool) -> &mut Self {
190        self.cell_value.set_value_bool(value);
191        self
192    }
193
194    #[inline]
195    pub(crate) fn set_value_bool_crate(&mut self, value: bool) -> &mut Self {
196        self.cell_value.set_value_bool_crate(value);
197        self
198    }
199
200    #[inline]
201    pub fn set_value_number<T>(&mut self, value: T) -> &mut Self
202    where
203        T: Into<f64>,
204    {
205        self.cell_value.set_value_number(value);
206        self
207    }
208
209    #[inline]
210    pub fn set_rich_text(&mut self, value: RichText) -> &mut Self {
211        self.cell_value.set_rich_text(value);
212        self
213    }
214
215    #[inline]
216    pub fn set_error<S: Into<String>>(&mut self, value: S) -> &mut Self {
217        self.cell_value.set_error(value);
218        self
219    }
220
221    #[inline]
222    pub fn set_formula<S: Into<String>>(&mut self, value: S) -> &mut Self {
223        self.cell_value.set_formula(value);
224        self
225    }
226
227    #[inline]
228    pub fn set_formula_result_default<S: Into<String>>(&mut self, value: S) -> &mut Self {
229        self.cell_value.set_formula_result_default(value);
230        self
231    }
232
233    #[inline]
234    pub fn set_blank(&mut self) -> &mut Self {
235        self.cell_value.set_blank();
236        self
237    }
238
239    #[inline]
240    pub(crate) fn set_shared_string_item(&mut self, value: SharedStringItem) -> &mut Self {
241        self.cell_value.set_shared_string_item(value);
242        self
243    }
244
245    #[inline]
246    pub fn get_data_type(&self) -> &str {
247        self.cell_value.get_data_type()
248    }
249
250    #[inline]
251    pub fn get_raw_value(&self) -> &CellRawValue {
252        self.cell_value.get_raw_value()
253    }
254
255    #[inline]
256    pub(crate) fn get_data_type_crate(&self) -> &str {
257        self.cell_value.get_data_type_crate()
258    }
259
260    #[inline]
261    pub fn is_formula(&self) -> bool {
262        self.cell_value.is_formula()
263    }
264
265    #[inline]
266    pub fn get_formula(&self) -> &str {
267        self.cell_value.get_formula()
268    }
269
270    #[inline]
271    pub fn get_formula_obj(&self) -> Option<&CellFormula> {
272        self.cell_value.get_formula_obj()
273    }
274
275    #[inline]
276    pub fn get_formula_shared_index(&self) -> Option<&u32> {
277        if let Some(v) = self.get_formula_obj() {
278            if v.get_formula_type() == &CellFormulaValues::Shared {
279                return Some(v.get_shared_index());
280            }
281        }
282        None
283    }
284
285    pub(crate) fn get_width_point(&self, column_font_size: &f64) -> f64 {
286        // get cell value len.
287        let char_cnt = self.get_width_point_cell();
288
289        // get font size.
290        let font_size = match self.get_style().get_font() {
291            Some(font) => font.get_font_size().get_val(),
292            None => column_font_size,
293        };
294
295        let mut column_width = 1.4 * char_cnt;
296        column_width = column_width * font_size / 11f64;
297
298        column_width
299    }
300
301    pub(crate) fn get_width_point_cell(&self) -> f64 {
302        let value = self.get_formatted_value();
303
304        value.split('\n').fold(0f64, |mut acc, value| {
305            let mut point = 0f64;
306            for chr in value.chars() {
307                let clen = if chr.len_utf8() > 1 { 1.5 } else { 1.0 };
308
309                point += clen;
310            }
311            if point > acc {
312                acc = point;
313            }
314            acc
315        })
316    }
317
318    pub fn get_formatted_value(&self) -> String {
319        let value = self.get_value();
320
321        // convert value
322        let result = match self.get_style().get_number_format() {
323            Some(nmuber_format) => to_formatted_string(&value, nmuber_format.get_format_code()),
324            None => to_formatted_string(&value, NumberingFormat::FORMAT_GENERAL),
325        };
326        result
327    }
328
329    // When opened in software such as Excel, it is visually blank.
330    #[inline]
331    pub(crate) fn is_visually_empty(&self) -> bool {
332        self.cell_value.is_visually_empty()
333            && self.style.is_visually_empty()
334            && self.hyperlink.is_none()
335    }
336
337    #[inline]
338    pub(crate) fn set_obj(&mut self, cell: Self) -> &mut Self {
339        self.cell_value = cell.cell_value;
340        self.style = cell.style;
341        self.hyperlink = cell.hyperlink;
342        self
343    }
344
345    pub(crate) fn set_attributes<R: std::io::BufRead>(
346        &mut self,
347        reader: &mut Reader<R>,
348        e: &BytesStart,
349        shared_string_table: &SharedStringTable,
350        stylesheet: &Stylesheet,
351        empty_flag: bool,
352        formula_shared_list: &mut HashMap<u32, (String, Vec<FormulaToken>)>,
353    ) {
354        let mut type_value: String = String::new();
355        let mut cell_reference: String = String::new();
356
357        if let Some(v) = get_attribute(e, b"r") {
358            cell_reference = v;
359            self.coordinate.set_coordinate(&cell_reference);
360        }
361
362        if let Some(v) = get_attribute(e, b"s") {
363            let style = stylesheet.get_style(v.parse::<usize>().unwrap());
364            self.set_style(style);
365        }
366
367        if let Some(v) = get_attribute(e, b"t") {
368            type_value = v;
369        }
370
371        set_string_from_xml!(self, e, cell_meta_index, "cm");
372
373        if empty_flag {
374            return;
375        }
376
377        let mut string_value: String = String::new();
378        let mut buf = Vec::new();
379        loop {
380            match reader.read_event_into(&mut buf) {
381                Ok(Event::Text(e)) => string_value = e.unescape().unwrap().to_string(),
382                Ok(Event::Start(ref e)) => match e.name().into_inner() {
383                    b"f" => {
384                        let mut obj = CellFormula::default();
385                        obj.set_attributes(reader, e, false, &cell_reference, formula_shared_list);
386                        self.cell_value.set_formula_obj(obj);
387                    }
388                    b"t" => {
389                        if let Some(Ok(attribute)) = e.attributes().next() {
390                            if attribute.key.into_inner() == b"xml:space"
391                                && attribute.value.as_ref() == b"preserve"
392                            {
393                                reader.config_mut().trim_text(false);
394                            }
395                        }
396                    }
397                    _ => (),
398                },
399                Ok(Event::Empty(ref e)) => {
400                    if e.name().into_inner() == b"f" {
401                        let mut obj = CellFormula::default();
402                        obj.set_attributes(reader, e, true, &cell_reference, formula_shared_list);
403                        self.cell_value.set_formula_obj(obj);
404                    }
405                }
406                Ok(Event::End(ref e)) => match e.name().into_inner() {
407                    b"v" => match type_value.as_str() {
408                        "str" => {
409                            self.set_value_string_crate(&string_value);
410                        }
411                        "s" => {
412                            let index = string_value.parse::<usize>().unwrap();
413                            let shared_string_item = shared_string_table
414                                .get_shared_string_item()
415                                .get(index)
416                                .unwrap();
417                            self.set_shared_string_item(shared_string_item.clone());
418                        }
419                        "b" => {
420                            let prm = string_value == "1";
421                            self.set_value_bool_crate(prm);
422                        }
423                        "e" => {
424                            self.set_error(&string_value);
425                        }
426                        "" | "n" => {
427                            self.set_value_crate(&string_value);
428                        }
429                        _ => {}
430                    },
431                    b"is" => {
432                        if type_value == "inlineStr" {
433                            self.set_value_crate(&string_value);
434                        }
435                    }
436                    b"c" => return,
437                    b"t" => {
438                        reader.config_mut().trim_text(true);
439                    }
440                    _ => (),
441                },
442                Ok(Event::Eof) => panic!("Error: Could not find {} end element", "c"),
443                Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
444                _ => (),
445            }
446            buf.clear();
447        }
448    }
449
450    pub(crate) fn write_to(
451        &self,
452        writer: &mut Writer<Cursor<Vec<u8>>>,
453        shared_string_table: &RwLock<SharedStringTable>,
454        stylesheet: &mut Stylesheet,
455        formula_shared_list: &HashMap<&u32, (String, Option<String>)>,
456    ) {
457        let empty_flag_value = self.cell_value.is_empty();
458        let empty_flag_style = self.style.is_empty();
459        if empty_flag_value && empty_flag_style {
460            return;
461        }
462
463        // c
464        let mut attributes: Vec<(&str, &str)> = Vec::new();
465        let coordinate = self.coordinate.to_string();
466        attributes.push(("r", &coordinate));
467        if self.get_data_type_crate() == "s"
468            || self.get_data_type_crate() == "b"
469            || self.get_data_type_crate() == "str"
470            || self.get_data_type_crate() == "e"
471        {
472            attributes.push(("t", self.get_data_type_crate()));
473        }
474        let xf_index_str: String;
475        let xf_index = stylesheet.set_style(self.get_style());
476        if xf_index > 0 {
477            xf_index_str = xf_index.to_string();
478            attributes.push(("s", &xf_index_str));
479        }
480
481        let cell_meta_index_str = self.cell_meta_index.get_value_string();
482        if self.cell_meta_index.has_value() {
483            // NOT SUPPORT
484            //attributes.push(("cm", &cell_meta_index_str));
485        }
486
487        if empty_flag_value {
488            write_start_tag(writer, "c", attributes, true);
489            return;
490        }
491
492        write_start_tag(writer, "c", attributes, false);
493        // f
494        match &self.cell_value.formula {
495            Some(v) => {
496                v.write_to(writer, &coordinate, formula_shared_list);
497            }
498            None => {}
499        }
500
501        // v
502        if self.cell_value.is_value_empty() {
503            write_start_tag(writer, "v", vec![], true);
504        } else {
505            write_start_tag(writer, "v", vec![], false);
506
507            //todo use typed value
508            match self.get_data_type_crate() {
509                "s" => {
510                    let val_index = shared_string_table
511                        .write()
512                        .unwrap()
513                        .set_cell(self.get_cell_value());
514                    write_text_node(writer, val_index.to_string());
515                }
516                "str" => {
517                    write_text_node_conversion(writer, self.get_value());
518                }
519                "b" => {
520                    let upper_value = self.get_value().to_uppercase();
521                    let prm = if upper_value == "TRUE" { "1" } else { "0" };
522                    write_text_node(writer, prm);
523                }
524                "e" => {
525                    let prm = "#VALUE!";
526                    write_text_node(writer, prm);
527                }
528                _ => write_text_node_conversion(writer, self.get_value()),
529            }
530            write_end_tag(writer, "v");
531        }
532
533        write_end_tag(writer, "c");
534    }
535}
536impl AdjustmentCoordinate for Cell {
537    #[inline]
538    fn adjustment_insert_coordinate(
539        &mut self,
540        root_col_num: &u32,
541        offset_col_num: &u32,
542        root_row_num: &u32,
543        offset_row_num: &u32,
544    ) {
545        self.coordinate.adjustment_insert_coordinate(
546            root_col_num,
547            offset_col_num,
548            root_row_num,
549            offset_row_num,
550        );
551    }
552
553    #[inline]
554    fn adjustment_remove_coordinate(
555        &mut self,
556        root_col_num: &u32,
557        offset_col_num: &u32,
558        root_row_num: &u32,
559        offset_row_num: &u32,
560    ) {
561        self.coordinate.adjustment_remove_coordinate(
562            root_col_num,
563            offset_col_num,
564            root_row_num,
565            offset_row_num,
566        );
567    }
568}
569impl AdjustmentCoordinateWith2Sheet for Cell {
570    #[inline]
571    fn adjustment_insert_coordinate_with_2sheet(
572        &mut self,
573        self_sheet_name: &str,
574        sheet_name: &str,
575        root_col_num: &u32,
576        offset_col_num: &u32,
577        root_row_num: &u32,
578        offset_row_num: &u32,
579    ) {
580        self.cell_value.adjustment_insert_coordinate_with_2sheet(
581            self_sheet_name,
582            sheet_name,
583            root_col_num,
584            offset_col_num,
585            root_row_num,
586            offset_row_num,
587        );
588    }
589
590    #[inline]
591    fn adjustment_remove_coordinate_with_2sheet(
592        &mut self,
593        self_sheet_name: &str,
594        sheet_name: &str,
595        root_col_num: &u32,
596        offset_col_num: &u32,
597        root_row_num: &u32,
598        offset_row_num: &u32,
599    ) {
600        self.cell_value.adjustment_remove_coordinate_with_2sheet(
601            self_sheet_name,
602            sheet_name,
603            root_col_num,
604            offset_col_num,
605            root_row_num,
606            offset_row_num,
607        );
608    }
609}