1use crate::helper::address::*;
2use crate::helper::coordinate::*;
3use crate::reader::xlsx::*;
4use crate::structs::drawing::Theme;
5use crate::structs::Address;
6use crate::structs::CellValue;
7use crate::structs::Cells;
8use crate::structs::DefinedName;
9use crate::structs::Properties;
10use crate::structs::SharedStringTable;
11use crate::structs::Stylesheet;
12use crate::structs::WorkbookProtection;
13use crate::structs::WorkbookView;
14use crate::structs::Worksheet;
15use crate::traits::AdjustmentCoordinate;
16use crate::traits::AdjustmentCoordinateWithSheet;
17use crate::StringValue;
18use std::sync::Arc;
19use std::sync::RwLock;
20use thin_vec::ThinVec;
21
22#[derive(Clone, Default, Debug)]
25pub struct Spreadsheet {
26 properties: Properties,
27 work_sheet_collection: ThinVec<Worksheet>,
28 macros_code: Option<ThinVec<u8>>,
29 jsa_macros_code: Option<ThinVec<u8>>,
30 code_name: StringValue,
31 ribbon_xml_data: StringValue,
32 theme: Theme,
33 stylesheet: Stylesheet,
34 shared_string_table: Arc<RwLock<SharedStringTable>>,
35 workbook_view: WorkbookView,
36 backup_context_types: ThinVec<(Box<str>, Box<str>)>,
37 pivot_caches: ThinVec<(Box<str>, Box<str>, Box<str>)>,
38 workbook_protection: Option<Box<WorkbookProtection>>,
39 defined_names: ThinVec<DefinedName>,
40}
41
42impl Spreadsheet {
43 #[inline]
57 pub fn insert_new_row(&mut self, sheet_name: &str, row_index: &u32, num_rows: &u32) {
58 self.adjustment_insert_coordinate_with_sheet(sheet_name, &0, &0, row_index, num_rows);
59 }
60
61 #[inline]
72 pub fn insert_new_column(&mut self, sheet_name: &str, column: &str, num_columns: &u32) {
73 self.insert_new_column_by_index(sheet_name, &column_index_from_string(column), num_columns);
74 }
75
76 #[inline]
87 pub fn insert_new_column_by_index(
88 &mut self,
89 sheet_name: &str,
90 column_index: &u32,
91 num_columns: &u32,
92 ) {
93 self.adjustment_insert_coordinate_with_sheet(sheet_name, column_index, num_columns, &0, &0);
94 }
95
96 #[inline]
107 pub fn remove_row(&mut self, sheet_name: &str, row_index: &u32, num_rows: &u32) {
108 self.adjustment_remove_coordinate_with_sheet(sheet_name, &0, &0, row_index, num_rows);
109 }
110
111 #[inline]
122 pub fn remove_column(&mut self, sheet_name: &str, column: &str, num_columns: &u32) {
123 self.remove_column_by_index(sheet_name, &column_index_from_string(column), num_columns);
124 }
125
126 #[inline]
137 pub fn remove_column_by_index(
138 &mut self,
139 sheet_name: &str,
140 column_index: &u32,
141 num_columns: &u32,
142 ) {
143 self.adjustment_remove_coordinate_with_sheet(sheet_name, column_index, num_columns, &0, &0);
144 }
145
146 #[inline]
157 pub fn get_cell_value_by_address(&self, address: &str) -> Vec<&CellValue> {
158 let (sheet_name, range) = split_address(address);
159 self.get_sheet_by_name(&sheet_name)
160 .unwrap()
161 .get_cell_value_by_range(&range)
162 }
163
164 #[inline]
171 pub(crate) fn get_cell_value_by_address_crate(&self, address: &Address) -> Vec<&CellValue> {
172 self.get_sheet_by_name(address.get_sheet_name())
173 .unwrap()
174 .get_cell_value_by_range(&address.get_range().get_range())
175 }
176
177 #[inline]
179 pub fn get_theme(&self) -> &Theme {
180 &self.theme
181 }
182
183 #[inline]
185 pub fn get_theme_mut(&mut self) -> &mut Theme {
186 &mut self.theme
187 }
188
189 #[inline]
193 pub fn set_theme(&mut self, value: Theme) -> &mut Self {
194 self.theme = value;
195 self
196 }
197
198 #[inline]
200 pub fn get_properties(&self) -> &Properties {
201 &self.properties
202 }
203
204 #[inline]
206 pub fn get_properties_mut(&mut self) -> &mut Properties {
207 &mut self.properties
208 }
209
210 #[inline]
214 pub fn set_properties(&mut self, value: Properties) -> &mut Self {
215 self.properties = value;
216 self
217 }
218
219 #[inline]
223 pub fn get_macros_code(&self) -> Option<&[u8]> {
224 self.macros_code.as_deref()
225 }
226
227 #[inline]
231 pub fn set_macros_code(&mut self, value: impl Into<ThinVec<u8>>) -> &mut Self {
232 self.macros_code = Some(value.into());
233 self
234 }
235
236 #[inline]
238 pub fn remove_macros_code(&mut self) -> &mut Self {
239 self.macros_code = None;
240 self
241 }
242
243 #[inline]
245 pub fn get_has_macros(&self) -> bool {
246 self.macros_code.is_some()
247 }
248
249 #[inline]
253 pub fn get_jsa_macros_code(&self) -> Option<&[u8]> {
254 self.jsa_macros_code.as_deref()
255 }
256
257 #[inline]
261 pub fn set_jsa_macros_code(&mut self, value: impl Into<ThinVec<u8>>) -> &mut Self {
262 self.jsa_macros_code = Some(value.into());
263 self
264 }
265
266 #[inline]
268 pub fn remove_jsa_macros_code(&mut self) -> &mut Self {
269 self.jsa_macros_code = None;
270 self
271 }
272
273 #[inline]
275 pub fn get_has_jsa_macros(&self) -> bool {
276 self.jsa_macros_code.is_some()
277 }
278
279 #[inline]
288 pub fn set_code_name<S: Into<String>>(&mut self, codename: S) -> &mut Self {
289 self.code_name.set_value(codename);
290 self
291 }
292
293 #[inline]
298 pub fn get_code_name(&self) -> Option<&str> {
299 self.code_name.get_value()
300 }
301
302 #[inline]
305 pub(crate) fn get_stylesheet(&self) -> &Stylesheet {
306 &self.stylesheet
307 }
308
309 #[inline]
314 pub(crate) fn set_stylesheet(&mut self, value: Stylesheet) -> &mut Self {
315 self.stylesheet = value;
316 self
317 }
318
319 #[inline]
322 pub(crate) fn set_stylesheet_defalut_value(&mut self) -> &mut Self {
323 self.stylesheet.set_defalut_value();
324 self
325 }
326
327 #[inline]
330 pub(crate) fn get_shared_string_table(&self) -> Arc<RwLock<SharedStringTable>> {
331 self.shared_string_table.clone()
332 }
333
334 #[inline]
339 pub(crate) fn set_shared_string_table(&mut self, value: SharedStringTable) -> &mut Self {
340 self.shared_string_table = Arc::new(RwLock::new(value));
341 self
342 }
343
344 pub fn get_sheet_collection(&self) -> &[Worksheet] {
346 for worksheet in &self.work_sheet_collection {
347 assert!(worksheet.is_deserialized(),"This Worksheet is Not Deserialized. Please exec to read_sheet(&mut self, index: usize);");
348 }
349 &self.work_sheet_collection
350 }
351
352 #[inline]
355 pub fn get_sheet_collection_no_check(&self) -> &[Worksheet] {
356 &self.work_sheet_collection
357 }
358
359 #[inline]
361 pub fn get_sheet_collection_mut(&mut self) -> &mut ThinVec<Worksheet> {
362 self.read_sheet_collection();
363 &mut self.work_sheet_collection
364 }
365
366 #[inline]
370 pub fn get_sheet_count(&self) -> usize {
371 self.work_sheet_collection.len()
372 }
373
374 #[inline]
376 pub fn read_sheet_collection(&mut self) -> &mut Self {
377 let shared_string_table = self.get_shared_string_table();
378 let stylesheet = self.get_stylesheet().clone();
379 for worksheet in &mut self.work_sheet_collection {
380 raw_to_deserialize_by_worksheet(worksheet, &shared_string_table, &stylesheet);
381 }
382 self
383 }
384
385 #[inline]
387 pub fn read_sheet(&mut self, index: usize) -> &mut Self {
388 let shared_string_table = self.get_shared_string_table();
389 let stylesheet = self.get_stylesheet().clone();
390 let worksheet = self.work_sheet_collection.get_mut(index).unwrap();
391 raw_to_deserialize_by_worksheet(worksheet, &shared_string_table, &stylesheet);
392 self
393 }
394
395 #[inline]
397 pub fn read_sheet_by_name(&mut self, sheet_name: &str) -> &mut Self {
398 let index = self.find_sheet_index_by_name(sheet_name).unwrap();
399 self.read_sheet(index)
400 }
401
402 #[inline]
403 pub(crate) fn find_sheet_index_by_name(&self, sheet_name: &str) -> Option<usize> {
404 self.work_sheet_collection
405 .iter()
406 .position(|sheet| sheet.get_name() == sheet_name)
407 }
408
409 #[inline]
415 pub fn get_sheet(&self, index: &usize) -> Option<&Worksheet> {
416 self.work_sheet_collection
417 .get(*index)
418 .map(|v| {
419 assert!(v.is_deserialized(),"This Worksheet is Not Deserialized. Please exec to read_sheet(&mut self, index: usize);");
420 v
421 })
422 }
423
424 #[inline]
430 pub fn get_sheet_by_name(&self, sheet_name: &str) -> Option<&Worksheet> {
431 self.find_sheet_index_by_name(sheet_name)
432 .and_then(|index| self.get_sheet(&index))
433 }
434
435 pub fn get_lazy_read_sheet_cells(&self, index: &usize) -> Result<Cells, &'static str> {
436 let shared_string_table = self.get_shared_string_table();
437 self.work_sheet_collection
438 .get(*index)
439 .map(|v| {
440 v.get_cell_collection_stream(
441 &shared_string_table.read().unwrap(),
442 self.get_stylesheet(),
443 )
444 })
445 .ok_or("Not found.")
446 }
447
448 pub fn get_sheet_mut(&mut self, index: &usize) -> Option<&mut Worksheet> {
454 let shared_string_table = self.get_shared_string_table();
455 let stylesheet = self.get_stylesheet().clone();
456 self.work_sheet_collection.get_mut(*index).map(|v| {
457 raw_to_deserialize_by_worksheet(v, &shared_string_table, &stylesheet);
458 v
459 })
460 }
461
462 #[inline]
468 pub fn get_sheet_by_name_mut(&mut self, sheet_name: &str) -> Option<&mut Worksheet> {
469 self.find_sheet_index_by_name(sheet_name)
470 .and_then(move |index| self.get_sheet_mut(&index))
471 }
472
473 #[inline]
474 pub fn set_active_sheet(&mut self, index: u32) -> &mut Self {
475 self.get_workbook_view_mut().set_active_tab(index);
476 self
477 }
478
479 #[inline]
483 pub fn get_active_sheet(&self) -> &Worksheet {
484 let index = *self.get_workbook_view().get_active_tab();
485 self.get_sheet(&(index as usize)).unwrap()
486 }
487
488 #[inline]
492 pub fn get_active_sheet_mut(&mut self) -> &mut Worksheet {
493 let index = *self.get_workbook_view().get_active_tab();
494 self.get_sheet_mut(&(index as usize)).unwrap()
495 }
496
497 #[inline]
503 pub fn add_sheet(&mut self, value: Worksheet) -> Result<&mut Worksheet, &'static str> {
504 let title = value.get_name();
505 Spreadsheet::check_sheet_name(self, title)?;
506 self.work_sheet_collection.push(value);
507 Ok(self.work_sheet_collection.last_mut().unwrap())
508 }
509
510 #[inline]
516 pub fn remove_sheet(&mut self, index: usize) -> Result<(), &'static str> {
517 if self.work_sheet_collection.len() <= index {
518 return Err("out of index.");
519 }
520 self.work_sheet_collection.remove(index);
521 Ok(())
522 }
523
524 pub fn remove_sheet_by_name(&mut self, sheet_name: &str) -> Result<(), &'static str> {
530 let cnt_before = self.work_sheet_collection.len();
531 self.work_sheet_collection
532 .retain(|x| x.get_name() != sheet_name);
533 let cnt_after = self.work_sheet_collection.len();
534 if cnt_before == cnt_after {
535 return Err("out of index.");
536 }
537 Ok(())
538 }
539
540 #[inline]
546 pub fn new_sheet<S: Into<String>>(
547 &mut self,
548 sheet_title: S,
549 ) -> Result<&mut Worksheet, &'static str> {
550 let v = sheet_title.into();
551 Spreadsheet::check_sheet_name(self, &v)?;
552 let sheet_id = (self.work_sheet_collection.len() + 1).to_string();
553 Ok(Spreadsheet::add_new_sheet_crate(
554 self,
555 sheet_id,
556 v.to_string(),
557 ))
558 }
559
560 pub(crate) fn add_new_sheet_crate<S: Into<String>>(
568 &mut self,
569 sheet_id: S,
570 sheet_title: S,
571 ) -> &mut Worksheet {
572 let mut worksheet = Worksheet::default();
573 worksheet.set_sheet_id(sheet_id);
574 worksheet.set_name(sheet_title.into());
575 worksheet
576 .get_sheet_format_properties_mut()
577 .set_defalut_value();
578 self.work_sheet_collection.push(worksheet);
579 self.work_sheet_collection.last_mut().unwrap()
580 }
581
582 pub fn set_sheet_name<S: Into<String>>(
589 &mut self,
590 index: usize,
591 sheet_name: S,
592 ) -> Result<(), &'static str> {
593 let sheet_name_str = sheet_name.into();
594 Spreadsheet::check_sheet_name(self, sheet_name_str.as_ref())?;
595 self.work_sheet_collection
596 .get_mut(index)
597 .map(|sheet| {
598 sheet.set_name(sheet_name_str);
599 })
600 .ok_or("sheet not found.")
601 }
602
603 pub(crate) fn check_sheet_name(&self, value: &str) -> Result<(), &'static str> {
606 match self
607 .work_sheet_collection
608 .iter()
609 .any(|work_sheet| value == work_sheet.get_name())
610 {
611 true => Err("name duplicate."),
612 false => Ok(()),
613 }
614 }
615
616 #[inline]
619 pub(crate) fn has_ribbon(&self) -> bool {
620 self.ribbon_xml_data.has_value()
621 }
622
623 #[inline]
625 pub fn get_workbook_view(&self) -> &WorkbookView {
626 &self.workbook_view
627 }
628
629 #[inline]
631 pub fn get_workbook_view_mut(&mut self) -> &mut WorkbookView {
632 &mut self.workbook_view
633 }
634
635 #[inline]
639 pub fn set_workbook_view(&mut self, value: WorkbookView) -> &mut Self {
640 self.workbook_view = value;
641 self
642 }
643
644 #[inline]
647 pub(crate) fn has_defined_names(&self) -> bool {
648 if !self.defined_names.is_empty() {
649 return true;
650 }
651 self.get_sheet_collection_no_check()
652 .iter()
653 .any(|sheet| sheet.has_defined_names())
654 }
655
656 #[inline]
657 pub(crate) fn get_backup_context_types(&self) -> &[(Box<str>, Box<str>)] {
658 &self.backup_context_types
659 }
660
661 #[inline]
662 pub(crate) fn set_backup_context_types(
663 &mut self,
664 value: impl Into<ThinVec<(String, String)>>,
665 ) -> &mut Self {
666 self.backup_context_types = value
667 .into()
668 .into_iter()
669 .map(|(a, b)| (a.into_boxed_str(), b.into_boxed_str()))
670 .collect();
671 self
672 }
673
674 pub(crate) fn get_pivot_caches(&self) -> Vec<(String, String, String)> {
675 let mut result: Vec<(String, String, String)> = Vec::new();
676 for (val1, val2, val3) in &self.pivot_caches {
677 let val3_up = format!("xl/{}", &val3);
678 for worksheet in self.get_sheet_collection_no_check() {
679 for pivot_cache_definition in worksheet.get_pivot_cache_definition_collection() {
680 if &val3_up == pivot_cache_definition
681 && !result.iter().any(|(_, _, r_val3)| r_val3 == &**val3)
682 {
683 result.push((val1.to_string(), val2.to_string(), val3.to_string()));
684 }
685 }
686 }
687 }
688 result
689 }
690
691 #[inline]
692 pub(crate) fn add_pivot_caches(&mut self, value: (String, String, String)) -> &mut Self {
693 self.pivot_caches.push((
694 value.0.into_boxed_str(),
695 value.1.into_boxed_str(),
696 value.2.into_boxed_str(),
697 ));
698 self
699 }
700
701 #[inline]
702 pub(crate) fn update_pivot_caches(&mut self, key: String, value: String) -> &mut Self {
703 self.pivot_caches.iter_mut().for_each(|(val1, _, val3)| {
704 if &**val1 == &key {
705 *val3 = value.clone().into_boxed_str()
706 };
707 });
708 self
709 }
710
711 #[inline]
712 pub fn get_workbook_protection(&self) -> Option<&WorkbookProtection> {
713 self.workbook_protection.as_deref()
714 }
715
716 #[inline]
717 pub fn get_workbook_protection_mut(&mut self) -> &mut WorkbookProtection {
718 self.workbook_protection
719 .get_or_insert(Box::new(WorkbookProtection::default()))
720 }
721
722 #[inline]
723 pub fn set_workbook_protection(&mut self, value: WorkbookProtection) -> &mut Self {
724 self.workbook_protection = Some(Box::new(value));
725 self
726 }
727
728 #[inline]
729 pub fn remove_workbook_protection(&mut self) -> &mut Self {
730 self.workbook_protection = None;
731 self
732 }
733
734 #[inline]
736 pub fn get_defined_names(&self) -> &[DefinedName] {
737 &self.defined_names
738 }
739
740 #[inline]
742 pub fn get_defined_names_mut(&mut self) -> &mut ThinVec<DefinedName> {
743 &mut self.defined_names
744 }
745
746 #[inline]
750 pub fn set_defined_names(&mut self, value: impl Into<ThinVec<DefinedName>>) {
751 self.defined_names = value.into();
752 }
753
754 #[inline]
758 pub fn add_defined_names(&mut self, value: DefinedName) {
759 self.defined_names.push(value);
760 }
761
762 #[inline]
764 pub fn has_threaded_comments(&self) -> bool {
765 for worksheet in &self.work_sheet_collection {
766 if worksheet.has_threaded_comments() {
767 return true;
768 }
769 }
770 return false;
771 }
772}
773impl AdjustmentCoordinateWithSheet for Spreadsheet {
774 fn adjustment_insert_coordinate_with_sheet(
775 &mut self,
776 sheet_name: &str,
777 root_col_num: &u32,
778 offset_col_num: &u32,
779 root_row_num: &u32,
780 offset_row_num: &u32,
781 ) {
782 self.read_sheet_collection();
783 for worksheet in &mut self.work_sheet_collection {
784 worksheet.adjustment_insert_coordinate(
785 root_col_num,
786 offset_col_num,
787 root_row_num,
788 offset_row_num,
789 );
790 worksheet.adjustment_insert_coordinate_with_sheet(
791 sheet_name,
792 root_col_num,
793 offset_col_num,
794 root_row_num,
795 offset_row_num,
796 );
797 }
798 }
799
800 fn adjustment_remove_coordinate_with_sheet(
801 &mut self,
802 sheet_name: &str,
803 root_col_num: &u32,
804 offset_col_num: &u32,
805 root_row_num: &u32,
806 offset_row_num: &u32,
807 ) {
808 self.read_sheet_collection();
809 for worksheet in &mut self.work_sheet_collection {
810 worksheet.adjustment_remove_coordinate(
811 root_col_num,
812 offset_col_num,
813 root_row_num,
814 offset_row_num,
815 );
816 worksheet.adjustment_remove_coordinate_with_sheet(
817 sheet_name,
818 root_col_num,
819 offset_col_num,
820 root_row_num,
821 offset_row_num,
822 );
823 }
824 }
825}