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 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 }
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 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 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 let (mut drawings, mut drawings_rel) = (None, None);
350 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}