edit_xlsx/api/
worksheet.rs

1pub(crate) mod write;
2pub(crate) mod row;
3pub(crate) mod col;
4pub(crate) mod read;
5mod format;
6mod hyperlink;
7mod image;
8mod theme;
9
10use std::cell::RefCell;
11use std::collections::HashMap;
12use std::fs::File;
13use std::path::Path;
14use std::rc::Rc;
15use zip::ZipArchive;
16use crate::{Cell, Filters, Format, FormatColor, FormatFill, FormatFont, xml};
17use crate::api::cell::location::{Location, LocationRange};
18use crate::api::worksheet::col::WorkSheetCol;
19use crate::api::worksheet::image::Image;
20use crate::api::worksheet::read::Read;
21use crate::api::worksheet::row::WorkSheetRow;
22use crate::api::worksheet::write::Write;
23use crate::api::workbook::Workbook as ApiWorkbook;
24use crate::file::XlsxFileType;
25use crate::result::{WorkSheetError, WorkSheetResult};
26use crate::xml::drawings::Drawings;
27use crate::xml::drawings::vml_drawing::VmlDrawing;
28use crate::xml::io::IoV2;
29use crate::xml::metadata::Metadata;
30use crate::xml::relationships::Relationships;
31use crate::xml::shared_string::SharedString;
32use crate::xml::worksheet::WorkSheet as XmlWorkSheet;
33use crate::xml::workbook::Workbook;
34use crate::xml::style::StyleSheet;
35
36#[derive(Debug)]
37pub struct WorkSheet {
38    pub(crate) id: u32,
39    pub(crate) name: String,
40    pub(crate) target: String,
41    pub(crate) target_id: u32,
42    workbook: Rc<RefCell<Workbook>>,
43    workbook_rel: Rc<RefCell<Relationships>>,
44    worksheet: XmlWorkSheet,
45    worksheet_rel: Relationships,
46    style_sheet: Rc<RefCell<StyleSheet>>,
47    content_types: Rc<RefCell<xml::content_types::ContentTypes>>,
48    medias: Rc<RefCell<xml::medias::Medias>>,
49    themes: Rc<RefCell<xml::theme::Themes>>,
50    vml_drawing: Option<VmlDrawing>,
51    drawings: Option<Drawings>,
52    drawings_rel: Option<Relationships>,
53    metadata: Rc<RefCell<Metadata>>,
54    shared_string: Rc<SharedString>,
55}
56
57impl Write for WorkSheet {}
58impl WorkSheetRow for WorkSheet {}
59impl WorkSheetCol for WorkSheet {}
60impl Read for WorkSheet {}
61
62impl WorkSheet {
63    pub(crate) fn save_as<P: AsRef<Path>>(&self, file_path: P) -> WorkSheetResult<()> {
64        self.worksheet.save(&file_path, &self.target);
65        self.worksheet_rel.save(&file_path, XlsxFileType::WorksheetRels(self.target_id));
66        // self.worksheet_rel.get_drawings_rids().iter().for_each(|id|{
67        //     if let Some(drawings) = &self.drawings {
68        //         drawings.save(&file_path, *id);
69        //     }
70        //     if let Some(drawings_rel) = &self.drawings_rel {
71        //         drawings_rel.save(&file_path, XlsxFileType::DrawingRels(*id));
72        //     }
73        // });
74        if let Some(id) = self.worksheet_rel.get_drawings_rids().first() {
75            if let Some(drawings) = &self.drawings {
76                drawings.save(&file_path, *id);
77            }
78            if let Some(drawings_rel) = &self.drawings_rel {
79                drawings_rel.save(&file_path, XlsxFileType::DrawingRels(*id));
80            }
81        };
82        if let Some(id) = self.worksheet_rel.get_vml_drawing_rid() {
83            // self.vml_drawing.as_ref().unwrap().save(&file_path, id);
84            // self.vml_drawing.as_ref().unwrap().save(&file_path, id);
85        }
86        Ok(())
87    }
88}
89
90impl WorkSheet {
91    pub fn autofilter<L: LocationRange>(&mut self, loc_range: L) {
92        self.worksheet.autofilter(loc_range);
93    }
94
95    pub fn filter_column<L: Location>(&mut self, col: L, filters: &Filters) {
96        self.worksheet.filter_column(col, filters);
97    }
98}
99
100impl WorkSheet {
101    pub fn max_column(&self) -> u32 {
102        let worksheet = &self.worksheet;
103        let sheet_data = &worksheet.sheet_data;
104        sheet_data.max_col()
105    }
106
107    pub fn max_row(&self) -> u32 {
108        let worksheet = &self.worksheet;
109        let sheet_data = &worksheet.sheet_data;
110        sheet_data.max_row()
111    }
112
113    // fn autofit(&mut self) {
114    //     todo!();
115    //     let worksheets = &mut self.worksheets.borrow_mut();
116    //     let worksheet = worksheets.get_mut(&self.id).unwrap();
117    //     worksheet.autofit_cols();
118    // }
119
120    pub fn get_name(&self) -> &str {
121        &self.name
122    }
123
124    pub fn set_name(&mut self, name: &str) -> WorkSheetResult<()> {
125        let workbook = &mut self.workbook.borrow_mut();
126        let name_existed = workbook.sheets.sheets
127            .iter()
128            .filter(|sheet| sheet.name == name)
129            .count() > 0;
130        if name_existed {
131            Err(WorkSheetError::DuplicatedSheets)
132        } else {
133            workbook.sheets.sheets
134                .iter_mut()
135                .filter(|sheet| sheet.name == self.name)
136                .for_each(|sheet| sheet.name = name.to_string());
137            self.name = name.to_string();
138            Ok(())
139        }
140    }
141
142    pub fn activate(&mut self) {
143        let workbook = &mut self.workbook.borrow_mut();
144        let book_views = &mut workbook.book_views;
145        book_views.set_active_tab(self.id - 1)
146    }
147
148    pub fn select(&mut self) {
149        let worksheet = &mut self.worksheet;
150        let sheet_views = &mut worksheet.sheet_views;
151        sheet_views.set_tab_selected(1);
152    }
153
154    pub fn deselect(&mut self) {
155        let worksheet = &mut self.worksheet;
156        let sheet_views = &mut worksheet.sheet_views;
157        sheet_views.set_tab_selected(0);
158    }
159
160    pub fn right_to_left(&mut self) {
161        self.worksheet.sheet_views.set_right_to_left(1);
162    }
163
164    pub fn set_top_left_cell<L: Location>(&mut self, loc: L) {
165        let worksheet = &mut self.worksheet;
166        let sheet_views = &mut worksheet.sheet_views;
167        sheet_views.set_top_left_cell(&loc.to_ref());
168    }
169
170    pub fn set_zoom(&mut self, zoom_scale: u16) {
171        let worksheet = &mut self.worksheet;
172        let sheet_views = &mut worksheet.sheet_views;
173        sheet_views.set_zoom_scale(zoom_scale);
174    }
175
176    pub fn set_selection<L: LocationRange>(&mut self, loc_range: L) -> WorkSheetResult<()> {
177        let worksheet = &mut self.worksheet;
178        let sheet_views = &mut worksheet.sheet_views;
179        sheet_views.set_selection(&loc_range);
180        Ok(())
181    }
182
183    pub fn freeze_panes<L: Location>(&mut self, loc: L) -> WorkSheetResult<()> {
184        let worksheet = &mut self.worksheet;
185        let sheet_views = &mut worksheet.sheet_views;
186        sheet_views.set_freeze_panes(loc);
187        Ok(())
188    }
189
190    pub fn split_panes(&mut self, width: f64, height: f64) -> WorkSheetResult<()> {
191        let width = (420.0 + width * 120.0) as u32;
192        let height = (280.0 + height * 20.0) as u32;
193        let worksheet = &mut self.worksheet;
194        let sheet_views = &mut worksheet.sheet_views;
195        sheet_views.split_panes(width, height);
196        Ok(())
197    }
198
199    pub fn set_default_row(&mut self, height: f64) {
200        let worksheet = &mut self.worksheet;
201        worksheet.set_default_row_height(height);
202    }
203
204    pub fn get_default_row(&self) -> f64 {
205        let worksheet = &self.worksheet;
206        worksheet.get_default_row_height()
207    }
208
209    pub fn set_default_column(&mut self, height: f64) {
210        let worksheet = &mut self.worksheet;
211        worksheet.set_default_col_width(height);
212    }
213
214    pub fn set_default_column_adaptive(&mut self) {
215        let worksheet = &mut self.worksheet;
216        worksheet.set_default_col_width_adaptive();
217    }
218
219    pub fn get_default_column(&self) -> Option<f64> {
220        let worksheet = &self.worksheet;
221        worksheet.get_default_col_width()
222    }
223
224    pub fn hide_unused_rows(&mut self, hide: bool) {
225        let worksheet = &mut self.worksheet;
226        worksheet.hide_unused_rows(hide);
227    }
228
229    pub fn outline_settings(&mut self, visible: bool, symbols_below: bool, symbols_right: bool, auto_style: bool) {
230        let worksheet = &mut self.worksheet;
231        worksheet.outline_settings(visible, symbols_below, symbols_right, auto_style)
232    }
233
234    pub fn ignore_errors<L: Location>(&mut self, error_map: HashMap<&str, L>) {
235        let error_map = error_map.iter().map(|(&e, l)| (e, l.to_ref())).collect::<HashMap<&str, String>>();
236        let worksheet = &mut self.worksheet;
237        worksheet.ignore_errors(error_map);
238    }
239
240    pub fn hide(&mut self) {
241        let mut workbook = self.workbook.borrow_mut();
242        let sheet = &mut workbook
243            .sheets.sheets
244            .iter_mut()
245            .find(|s| { s.sheet_id == self.id })
246            .unwrap();
247        sheet.state = Some(String::from("hidden"));
248    }
249
250    pub fn set_tab_color(&mut self, tab_color: &FormatColor) {
251        self.worksheet.set_tab_color(tab_color);
252    }
253
254    pub fn set_background<P: AsRef<Path>>(&mut self, filename: P) -> WorkSheetResult<()> {
255        let r_id = self.add_background(&filename)?;
256        self.worksheet.set_background(r_id);
257        Ok(())
258    }
259
260    pub fn insert_image<L: LocationRange, P: AsRef<Path>>(&mut self, loc_range: L, filename: &P) -> WorkSheetResult<()> {
261        let (from_row, from_col, to_row, to_col) = loc_range.to_range();
262        let r_id = self.add_drawing((from_row, from_col, to_row, to_col), filename)?;
263        self.worksheet.insert_image(r_id);
264        Ok(())
265    }
266
267    pub fn id(&self) -> u32 {
268        self.id
269    }
270}
271
272impl WorkSheet {
273    pub(crate) fn add_worksheet (
274        sheet_id: u32,
275        name: &str,
276        target_id: u32,
277        workbook: &ApiWorkbook,
278    ) -> WorkSheet {
279        Self {
280            id: sheet_id,
281            name: name.to_string(),
282            target: format!("worksheets/sheet{target_id}.xml"),
283            target_id,
284            workbook: workbook.workbook.clone(),
285            workbook_rel: workbook.workbook_rel.clone(),
286            worksheet: XmlWorkSheet::default(),
287            worksheet_rel: Relationships::default(),
288            style_sheet: workbook.style_sheet.clone(),
289            content_types: workbook.content_types.clone(),
290            medias: workbook.medias.clone(),
291            themes: workbook.themes.clone(),
292            vml_drawing: None,
293            drawings: None,
294            drawings_rel: None,
295            metadata: workbook.metadata.clone(),
296            shared_string: workbook.shared_string.clone(),
297        }
298    }
299
300    pub(crate) fn from_worksheet(
301        sheet_id: u32,
302        name: &str,
303        target_id: u32,
304        worksheet: &WorkSheet,
305    ) -> WorkSheet {
306        Self {
307            id: sheet_id,
308            name: name.to_string(),
309            target: format!("worksheets/sheet{target_id}.xml"),
310            target_id,
311            workbook: worksheet.workbook.clone(),
312            workbook_rel: worksheet.workbook_rel.clone(),
313            worksheet: worksheet.worksheet.clone(),
314            worksheet_rel: worksheet.worksheet_rel.clone(),
315            style_sheet: worksheet.style_sheet.clone(),
316            content_types: worksheet.content_types.clone(),
317            medias: worksheet.medias.clone(),
318            themes: worksheet.themes.clone(),
319            vml_drawing: None,
320            drawings: worksheet.drawings.clone(),
321            drawings_rel: worksheet.drawings_rel.clone(),
322            metadata: worksheet.metadata.clone(),
323            shared_string: worksheet.shared_string.clone(),
324        }
325    }
326
327    pub(crate) fn from_archive<P: AsRef<Path>>(
328        sheet_id: u32,
329        name: &str,
330        target: &str,
331        target_id: u32,
332        file_path: P,
333        archive: &mut ZipArchive<File>,
334        workbook: Rc<RefCell<Workbook>>,
335        workbook_rel: Rc<RefCell<Relationships>>,
336        style_sheet: Rc<RefCell<StyleSheet>>,
337        content_types: Rc<RefCell<xml::content_types::ContentTypes>>,
338        medias: Rc<RefCell<xml::medias::Medias>>,
339        themes: Rc<RefCell<xml::theme::Themes>>,
340        metadata: Rc<RefCell<Metadata>>,
341        shared_string: Rc<SharedString>,
342    ) -> WorkSheet {
343        // Read worksheet from zip dir
344        let mut worksheet = XmlWorkSheet::from_zip_file(archive, &format!("xl/{target}")).unwrap_or_default();
345        worksheet.sheet_data.clean_formula_value();
346        let worksheet_rel_id: String = target.chars().filter(|&c| c >= '0' && c <= '9').collect();
347        let worksheet_rel = Relationships::from_zip_file(archive, &format!("xl/worksheets/_rels/sheet{worksheet_rel_id}.xml.rels")).unwrap_or_default();
348        // load drawings
349        let (mut drawings, mut drawings_rel) = (None, None);
350        // worksheet_rel.get_drawings_rids().iter().for_each(|&drawings_id|{
351        //     drawings = Drawings::from_zip_file(archive, &format!("xl/drawings/drawing{drawings_id}.xml"));
352        //     drawings_rel = Relationships::from_zip_file(archive, &format!("xl/drawings/_rels/drawing{drawings_id}.xml.rels"));
353        // });
354        if let Some(&drawings_id) = worksheet_rel.get_drawings_rids().first() {
355            drawings = Drawings::from_zip_file(archive, &format!("xl/drawings/drawing{drawings_id}.xml"));
356            drawings_rel = Relationships::from_zip_file(archive, &format!("xl/drawings/_rels/drawing{drawings_id}.xml.rels"));
357        };
358        let vml_drawing = match worksheet_rel.get_vml_drawing_rid() {
359            Some(vml_drawing_id) => VmlDrawing::from_zip_file(archive, &format!("xl/drawings/vmlDrawing{vml_drawing_id}.xml")),
360            None => None
361        };
362        WorkSheet {
363            id: sheet_id,
364            name: String::from(name),
365            target: format!("{target}"),
366            target_id,
367            workbook,
368            workbook_rel,
369            worksheet,
370            worksheet_rel,
371            style_sheet,
372            content_types,
373            medias,
374            themes,
375            vml_drawing,
376            drawings,
377            drawings_rel,
378            metadata,
379            shared_string,
380        }
381    }
382}