umya_spreadsheet/structs/
cell.rs1use 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 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 #[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 let char_cnt = self.get_width_point_cell();
288
289 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 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 #[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 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 }
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 match &self.cell_value.formula {
495 Some(v) => {
496 v.write_to(writer, &coordinate, formula_shared_list);
497 }
498 None => {}
499 }
500
501 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 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}