1use crate::{
2 model::Model,
3 number_format::{get_default_num_fmt_id, get_new_num_fmt_index, get_num_fmt},
4 types::{
5 Border, CellStyleXfs, CellStyles, CellXfs, Dxf, Fill, Font, NumFmt, Style, StyleIncludes,
6 Styles,
7 },
8};
9
10impl Styles {
11 fn get_font_index(&self, font: &Font) -> Option<i32> {
12 for (font_index, item) in self.fonts.iter().enumerate() {
13 if item == font {
14 return Some(font_index as i32);
15 }
16 }
17 None
18 }
19 fn get_fill_index(&self, fill: &Fill) -> Option<i32> {
20 for (fill_index, item) in self.fills.iter().enumerate() {
21 if item == fill {
22 return Some(fill_index as i32);
23 }
24 }
25 None
26 }
27 fn get_border_index(&self, border: &Border) -> Option<i32> {
28 for (border_index, item) in self.borders.iter().enumerate() {
29 if item == border {
30 return Some(border_index as i32);
31 }
32 }
33 None
34 }
35 fn get_num_fmt_index(&self, format_code: &str) -> Option<i32> {
36 if let Some(index) = get_default_num_fmt_id(format_code) {
37 return Some(index);
38 }
39 for item in self.num_fmts.iter() {
40 if item.format_code == format_code {
41 return Some(item.num_fmt_id);
42 }
43 }
44 None
45 }
46
47 fn get_or_create_component_ids(&mut self, style: &Style) -> (i32, i32, i32, i32) {
50 let font = &style.font;
51 let font_id = if let Some(index) = self.get_font_index(font) {
52 index
53 } else {
54 self.fonts.push(font.clone());
55 self.fonts.len() as i32 - 1
56 };
57 let fill = &style.fill;
58 let fill_id = if let Some(index) = self.get_fill_index(fill) {
59 index
60 } else {
61 self.fills.push(fill.clone());
62 self.fills.len() as i32 - 1
63 };
64 let border = &style.border;
65 let border_id = if let Some(index) = self.get_border_index(border) {
66 index
67 } else {
68 self.borders.push(border.clone());
69 self.borders.len() as i32 - 1
70 };
71 let num_fmt = &style.num_fmt;
72 let num_fmt_id;
73 if let Some(index) = self.get_num_fmt_index(num_fmt) {
74 num_fmt_id = index;
75 } else {
76 num_fmt_id = get_new_num_fmt_index(&self.num_fmts);
77 self.num_fmts.push(NumFmt {
78 format_code: num_fmt.to_string(),
79 num_fmt_id,
80 });
81 }
82 (num_fmt_id, font_id, fill_id, border_id)
83 }
84
85 fn create_base_style(&mut self, style: &Style, includes: StyleIncludes) -> i32 {
89 let (num_fmt_id, font_id, fill_id, border_id) = self.get_or_create_component_ids(style);
90 self.cell_style_xfs.push(CellStyleXfs {
93 num_fmt_id,
94 font_id,
95 fill_id,
96 border_id,
97 apply_number_format: includes.number_format,
98 apply_font: includes.font,
99 apply_fill: includes.fill,
100 apply_border: includes.border,
101 apply_alignment: includes.alignment,
102 apply_protection: includes.protection,
103 });
104 let xf_id = self.cell_style_xfs.len() as i32 - 1;
105 self.cell_xfs.push(CellXfs {
106 xf_id,
107 num_fmt_id,
108 font_id,
109 fill_id,
110 border_id,
111 apply_number_format: false,
112 apply_border: false,
113 apply_alignment: false,
114 apply_protection: false,
115 apply_font: false,
116 apply_fill: false,
117 quote_prefix: false,
120 alignment: style.alignment.clone(),
121 });
122 xf_id
123 }
124
125 pub fn create_new_style(&mut self, style: &Style) -> i32 {
126 let (num_fmt_id, font_id, fill_id, border_id) = self.get_or_create_component_ids(style);
127 self.cell_xfs.push(CellXfs {
128 xf_id: 0,
129 num_fmt_id,
130 font_id,
131 fill_id,
132 border_id,
133 apply_number_format: false,
134 apply_border: false,
135 apply_alignment: false,
136 apply_protection: false,
137 apply_font: false,
138 apply_fill: false,
139 quote_prefix: style.quote_prefix,
140 alignment: style.alignment.clone(),
141 });
142 self.cell_xfs.len() as i32 - 1
143 }
144
145 pub fn get_style_index(&self, style: &Style) -> Option<i32> {
146 for (index, cell_xf) in self.cell_xfs.iter().enumerate() {
147 if cell_xf.xf_id != 0 {
151 continue;
152 }
153 let border_id = cell_xf.border_id as usize;
154 let fill_id = cell_xf.fill_id as usize;
155 let font_id = cell_xf.font_id as usize;
156 let num_fmt_id = cell_xf.num_fmt_id;
157 let quote_prefix = cell_xf.quote_prefix;
158 if style
159 == &(Style {
160 alignment: cell_xf.alignment.clone(),
161 num_fmt: get_num_fmt(num_fmt_id, &self.num_fmts),
162 fill: self.fills[fill_id].clone(),
163 font: self.fonts[font_id].clone(),
164 border: self.borders[border_id].clone(),
165 quote_prefix,
166 })
167 {
168 return Some(index as i32);
169 }
170 }
171 None
172 }
173
174 pub(crate) fn get_style_index_or_create(&mut self, style: &Style) -> i32 {
175 if let Some(index) = self.get_style_index(style) {
177 index
178 } else {
179 self.create_new_style(style)
180 }
181 }
182
183 pub(crate) fn add_named_cell_style(
186 &mut self,
187 style_name: &str,
188 xf_id: i32,
189 ) -> Result<(), String> {
190 if self.get_xf_id_by_name(style_name).is_ok() {
191 return Err("A style with that name already exists".to_string());
192 }
193 if xf_id < 0 || xf_id as usize >= self.cell_style_xfs.len() {
194 return Err("There is no cell style xf with that index".to_string());
195 }
196 let cell_style = CellStyles {
197 name: style_name.to_string(),
198 xf_id,
199 builtin_id: 0,
200 };
201 self.cell_styles.push(cell_style);
202 Ok(())
203 }
204
205 pub(crate) fn get_xf_id_by_name(&self, style_name: &str) -> Result<i32, String> {
208 for cell_style in &self.cell_styles {
209 if cell_style.name == style_name {
210 return Ok(cell_style.xf_id);
211 }
212 }
213 Err(format!("Style '{style_name}' not found"))
214 }
215
216 pub fn get_style_index_by_name(&self, style_name: &str) -> Result<i32, String> {
221 let xf_id = self.get_xf_id_by_name(style_name)?;
222 for (index, cell_xf) in self.cell_xfs.iter().enumerate() {
223 if cell_xf.xf_id == xf_id && !Self::cell_xf_has_overrides(cell_xf) {
224 return Ok(index as i32);
225 }
226 }
227 Err(format!("Style '{style_name}' has no plain cell xf"))
228 }
229
230 fn cell_xf_has_overrides(cell_xf: &CellXfs) -> bool {
231 cell_xf.apply_number_format
232 || cell_xf.apply_font
233 || cell_xf.apply_fill
234 || cell_xf.apply_border
235 || cell_xf.apply_alignment
236 || cell_xf.apply_protection
237 || cell_xf.quote_prefix
240 }
241
242 pub(crate) fn get_or_create_style_index_by_name(
245 &mut self,
246 style_name: &str,
247 ) -> Result<i32, String> {
248 if let Ok(index) = self.get_style_index_by_name(style_name) {
249 return Ok(index);
250 }
251 let xf_id = self.get_xf_id_by_name(style_name)?;
252 let style_xf = self
253 .cell_style_xfs
254 .get(xf_id as usize)
255 .ok_or_else(|| format!("Style '{style_name}' points to an invalid xf id"))?;
256 self.cell_xfs.push(CellXfs {
257 xf_id,
258 num_fmt_id: style_xf.num_fmt_id,
259 font_id: style_xf.font_id,
260 fill_id: style_xf.fill_id,
261 border_id: style_xf.border_id,
262 apply_number_format: false,
263 apply_border: false,
264 apply_alignment: false,
265 apply_protection: false,
266 apply_font: false,
267 apply_fill: false,
268 quote_prefix: false,
269 alignment: None,
270 });
271 Ok(self.cell_xfs.len() as i32 - 1)
272 }
273
274 pub(crate) fn get_style_index_for_applied_style(
284 &mut self,
285 style_name: &str,
286 current_index: i32,
287 ) -> Result<i32, String> {
288 let xf_id = self.get_xf_id_by_name(style_name)?;
289 let record = self
290 .cell_style_xfs
291 .get(xf_id as usize)
292 .ok_or_else(|| format!("Style '{style_name}' points to an invalid xf id"))?
293 .clone();
294 let current = self
295 .cell_xfs
296 .get(current_index as usize)
297 .ok_or("Invalid index provided".to_string())?
298 .clone();
299 let style_alignment = self
301 .get_style_index_by_name(style_name)
302 .ok()
303 .and_then(|index| self.cell_xfs[index as usize].alignment.clone());
304
305 let new_xf = CellXfs {
306 xf_id,
307 num_fmt_id: if record.apply_number_format {
308 record.num_fmt_id
309 } else {
310 current.num_fmt_id
311 },
312 font_id: if record.apply_font {
313 record.font_id
314 } else {
315 current.font_id
316 },
317 fill_id: if record.apply_fill {
318 record.fill_id
319 } else {
320 current.fill_id
321 },
322 border_id: if record.apply_border {
323 record.border_id
324 } else {
325 current.border_id
326 },
327 alignment: if record.apply_alignment {
328 style_alignment
329 } else {
330 current.alignment.clone()
331 },
332 apply_number_format: !record.apply_number_format,
333 apply_font: !record.apply_font,
334 apply_fill: !record.apply_fill,
335 apply_border: !record.apply_border,
336 apply_alignment: !record.apply_alignment,
337 apply_protection: !record.apply_protection,
338 quote_prefix: current.quote_prefix,
339 };
340 if let Some(index) = self.cell_xfs.iter().position(|xf| xf == &new_xf) {
341 return Ok(index as i32);
342 }
343 self.cell_xfs.push(new_xf);
344 Ok(self.cell_xfs.len() as i32 - 1)
345 }
346
347 pub fn get_style_includes(&self, style_name: &str) -> Result<StyleIncludes, String> {
350 let xf_id = self.get_xf_id_by_name(style_name)?;
351 let record = self
352 .cell_style_xfs
353 .get(xf_id as usize)
354 .ok_or_else(|| format!("Style '{style_name}' points to an invalid xf id"))?;
355 Ok(StyleIncludes {
356 number_format: record.apply_number_format,
357 font: record.apply_font,
358 fill: record.apply_fill,
359 border: record.apply_border,
360 alignment: record.apply_alignment,
361 protection: record.apply_protection,
362 })
363 }
364
365 pub(crate) fn get_style_by_name(&self, style_name: &str) -> Result<Style, String> {
369 if let Ok(index) = self.get_style_index_by_name(style_name) {
370 return self.get_style(index);
371 }
372 let xf_id = self.get_xf_id_by_name(style_name)?;
373 let style_xf = self
374 .cell_style_xfs
375 .get(xf_id as usize)
376 .ok_or_else(|| format!("Style '{style_name}' points to an invalid xf id"))?;
377 Ok(Style {
378 alignment: None,
379 num_fmt: get_num_fmt(style_xf.num_fmt_id, &self.num_fmts),
380 fill: self.fills[style_xf.fill_id as usize].clone(),
381 font: self.fonts[style_xf.font_id as usize].clone(),
382 border: self.borders[style_xf.border_id as usize].clone(),
383 quote_prefix: false,
384 })
385 }
386
387 pub fn create_named_style(
392 &mut self,
393 style_name: &str,
394 style: &Style,
395 includes: StyleIncludes,
396 ) -> Result<(), String> {
397 if self.get_xf_id_by_name(style_name).is_ok() {
398 return Err("A style with that name already exists".to_string());
399 }
400 let xf_id = self.create_base_style(style, includes);
401 self.add_named_cell_style(style_name, xf_id)
402 }
403
404 pub fn get_named_style_list(&self) -> Vec<String> {
406 self.cell_styles.iter().map(|cs| cs.name.clone()).collect()
407 }
408
409 pub fn is_builtin_style(&self, style_name: &str) -> bool {
413 self.cell_styles.iter().any(|cs| {
414 cs.name == style_name && (cs.builtin_id > 0 || cs.name.eq_ignore_ascii_case("Normal"))
415 })
416 }
417
418 pub(crate) fn delete_named_style_entry(&mut self, style_name: &str) -> Result<(), String> {
421 let pos = self
422 .cell_styles
423 .iter()
424 .position(|cs| cs.name == style_name)
425 .ok_or_else(|| format!("Style '{style_name}' not found"))?;
426 self.cell_styles.remove(pos);
427 Ok(())
428 }
429
430 pub(crate) fn rename_named_style_entry(
433 &mut self,
434 style_name: &str,
435 new_name: &str,
436 ) -> Result<(), String> {
437 let cs = self
438 .cell_styles
439 .iter_mut()
440 .find(|cs| cs.name == style_name)
441 .ok_or_else(|| format!("Style '{style_name}' not found"))?;
442 cs.name = new_name.to_string();
443 Ok(())
444 }
445
446 pub(crate) fn get_style_with_quote_prefix(&mut self, index: i32) -> Result<i32, String> {
450 let mut style = self.get_style(index)?;
451 style.quote_prefix = true;
452 Ok(self.get_style_index_or_create(&style))
453 }
454
455 pub(crate) fn get_style_with_format(
459 &mut self,
460 index: i32,
461 num_fmt: &str,
462 ) -> Result<i32, String> {
463 let mut style = self.get_style(index)?;
464 style.num_fmt = num_fmt.to_string();
465 Ok(self.get_style_index_or_create(&style))
466 }
467
468 pub(crate) fn get_style_without_quote_prefix(&mut self, index: i32) -> Result<i32, String> {
472 let mut style = self.get_style(index)?;
473 style.quote_prefix = false;
474 Ok(self.get_style_index_or_create(&style))
475 }
476
477 pub(crate) fn style_is_quote_prefix(&self, index: i32) -> bool {
478 let cell_xf = &self.cell_xfs[index as usize];
479 cell_xf.quote_prefix
480 }
481
482 pub(crate) fn get_style(&self, index: i32) -> Result<Style, String> {
483 let cell_xf = &self
484 .cell_xfs
485 .get(index as usize)
486 .ok_or("Invalid index provided".to_string())?;
487 let border_id = cell_xf.border_id as usize;
488 let fill_id = cell_xf.fill_id as usize;
489 let font_id = cell_xf.font_id as usize;
490 let num_fmt_id = cell_xf.num_fmt_id;
491 let quote_prefix = cell_xf.quote_prefix;
492 let alignment = cell_xf.alignment.clone();
493
494 Ok(Style {
495 alignment,
496 num_fmt: get_num_fmt(num_fmt_id, &self.num_fmts),
497 fill: self.fills[fill_id].clone(),
498 font: self.fonts[font_id].clone(),
499 border: self.borders[border_id].clone(),
500 quote_prefix,
501 })
502 }
503}
504
505impl<'a> Model<'a> {
507 pub fn set_cell_style(
508 &mut self,
509 sheet: u32,
510 row: i32,
511 column: i32,
512 style: &Style,
513 ) -> Result<(), String> {
514 let style_index = self.workbook.styles.get_style_index_or_create(style);
515 self.workbook
516 .worksheet_mut(sheet)?
517 .set_cell_style(row, column, style_index)
518 }
519
520 pub fn copy_cell_style(
521 &mut self,
522 source_cell: (u32, i32, i32),
523 destination_cell: (u32, i32, i32),
524 ) -> Result<(), String> {
525 let source_style_index = self
526 .workbook
527 .worksheet(source_cell.0)?
528 .get_style(source_cell.1, source_cell.2);
529
530 self.workbook
531 .worksheet_mut(destination_cell.0)?
532 .set_cell_style(destination_cell.1, destination_cell.2, source_style_index)
533 }
534
535 pub fn set_cell_style_by_name(
539 &mut self,
540 sheet: u32,
541 row: i32,
542 column: i32,
543 style_name: &str,
544 ) -> Result<(), String> {
545 let current_index = self.workbook.worksheet(sheet)?.get_style(row, column);
546 let style_index = self
547 .workbook
548 .styles
549 .get_style_index_for_applied_style(style_name, current_index)?;
550 self.workbook
551 .worksheet_mut(sheet)?
552 .set_cell_style(row, column, style_index)
553 }
554
555 pub fn set_sheet_style(&mut self, sheet: u32, style_name: &str) -> Result<(), String> {
556 let style_index = self
557 .workbook
558 .styles
559 .get_or_create_style_index_by_name(style_name)?;
560 self.workbook.worksheet_mut(sheet)?.set_style(style_index)?;
561 Ok(())
562 }
563
564 pub fn set_sheet_row_style(
565 &mut self,
566 sheet: u32,
567 row: i32,
568 style_name: &str,
569 ) -> Result<(), String> {
570 let style_index = self
571 .workbook
572 .styles
573 .get_or_create_style_index_by_name(style_name)?;
574 self.workbook
575 .worksheet_mut(sheet)?
576 .set_row_style(row, style_index)?;
577 Ok(())
578 }
579
580 pub fn set_sheet_column_style(
581 &mut self,
582 sheet: u32,
583 column: i32,
584 style_name: &str,
585 ) -> Result<(), String> {
586 let style_index = self
587 .workbook
588 .styles
589 .get_or_create_style_index_by_name(style_name)?;
590 self.workbook
591 .worksheet_mut(sheet)?
592 .set_column_style(column, style_index)?;
593 Ok(())
594 }
595
596 pub fn get_named_style_list(&self) -> Vec<String> {
598 self.workbook.styles.get_named_style_list()
599 }
600
601 pub fn get_named_style(&self, name: &str) -> Result<Style, String> {
603 self.workbook.styles.get_style_by_name(name)
604 }
605
606 pub fn get_named_style_includes(&self, name: &str) -> Result<StyleIncludes, String> {
608 self.workbook.styles.get_style_includes(name)
609 }
610
611 pub fn create_named_style(
613 &mut self,
614 name: &str,
615 style: &Style,
616 includes: StyleIncludes,
617 ) -> Result<(), String> {
618 self.workbook
619 .styles
620 .create_named_style(name, style, includes)
621 }
622
623 pub fn delete_named_style(&mut self, name: &str) -> Result<(), String> {
626 if self.workbook.styles.is_builtin_style(name) {
627 return Err(format!("Cannot delete built-in style '{name}'"));
628 }
629 self.workbook.styles.delete_named_style_entry(name)
630 }
631
632 pub fn update_named_style(
647 &mut self,
648 name: &str,
649 new_name: &str,
650 style: &Style,
651 includes: StyleIncludes,
652 ) -> Result<(), String> {
653 let styles = &mut self.workbook.styles;
654 if styles.is_builtin_style(name) {
655 return Err(format!("Cannot modify built-in style '{name}'"));
656 }
657 let xf_id = styles.get_xf_id_by_name(name)?;
658 if name != new_name && styles.get_xf_id_by_name(new_name).is_ok() {
659 return Err(format!("A style named '{new_name}' already exists"));
660 }
661 if xf_id < 0 || xf_id as usize >= styles.cell_style_xfs.len() {
662 return Err(format!("Style '{name}' points to an invalid xf id"));
663 }
664
665 let (num_fmt_id, font_id, fill_id, border_id) = styles.get_or_create_component_ids(style);
666
667 let record = &mut styles.cell_style_xfs[xf_id as usize];
668 record.num_fmt_id = num_fmt_id;
669 record.font_id = font_id;
670 record.fill_id = fill_id;
671 record.border_id = border_id;
672 record.apply_number_format = includes.number_format;
673 record.apply_font = includes.font;
674 record.apply_fill = includes.fill;
675 record.apply_border = includes.border;
676 record.apply_alignment = includes.alignment;
677 record.apply_protection = includes.protection;
678
679 for cell_xf in styles.cell_xfs.iter_mut().filter(|xf| xf.xf_id == xf_id) {
680 if !cell_xf.apply_number_format {
681 cell_xf.num_fmt_id = num_fmt_id;
682 }
683 if !cell_xf.apply_font {
684 cell_xf.font_id = font_id;
685 }
686 if !cell_xf.apply_fill {
687 cell_xf.fill_id = fill_id;
688 }
689 if !cell_xf.apply_border {
690 cell_xf.border_id = border_id;
691 }
692 if !cell_xf.apply_alignment {
693 cell_xf.alignment = style.alignment.clone();
694 }
695 }
696
697 if name != new_name {
698 styles.rename_named_style_entry(name, new_name)?;
699 }
700 Ok(())
701 }
702}
703
704impl Dxf {
705 pub fn apply_to(&self, base: &Style) -> Style {
708 let mut style = base.clone();
709
710 if let Some(ref dxf_fill) = self.fill {
711 style.fill = dxf_fill.clone();
712 }
713
714 if let Some(ref dxf_font) = self.font {
715 if dxf_font.color != Font::default().color {
717 style.font.color = dxf_font.color.clone();
718 }
719 if let Some(b) = dxf_font.b {
720 style.font.b = b;
721 }
722 if let Some(i) = dxf_font.i {
723 style.font.i = i;
724 }
725 if let Some(u) = dxf_font.u {
726 style.font.u = u;
727 }
728 if let Some(strike) = dxf_font.strike {
729 style.font.strike = strike;
730 }
731 }
732
733 if let Some(ref dxf_border) = self.border {
734 style.border = dxf_border.clone();
735 }
736
737 if let Some(ref dxf_num_fmt) = self.num_fmt {
738 style.num_fmt = dxf_num_fmt.format_code.clone();
739 }
740
741 if let Some(ref dxf_alignment) = self.alignment {
742 style.alignment = Some(dxf_alignment.clone());
743 }
744
745 style
746 }
747}