edit_xlsx/api/worksheet/
col.rs

1//!
2//! Manages the Column settings that are modified,
3//! only the parts that are not None are applied to the [`Column`]'s modifications.
4//!
5//! This module contains the [`Column`] type, the [`WorkSheetCol`] trait for
6//! [`WorkSheet`]s working with [`Column`]s.
7//!
8//! # Examples
9//!
10//! There are multiple ways to create a new [`Column`]
11//!
12//! ```
13//! use edit_xlsx::Column;
14//! let col = Column::new(15.0, 2, 1, 0);
15//! assert_eq!(col.width, Some(15.0));
16//! assert_eq!(col.outline_level, Some(2));
17//! assert_eq!(col.hidden, Some(1));
18//! assert_eq!(col.collapsed, Some(0));
19//! ```
20//! Since the [`Column`] records the fields you want to update to worksheets, all their fields are optional
21//! If you create a new [`Column`] by default, the fields in it will be filled with None.
22//! ```
23//! use edit_xlsx::Column;
24//! let col = Column::default();
25//! assert_eq!(col.width, None);
26//! assert_eq!(col.outline_level, None);
27//! assert_eq!(col.hidden, None);
28//! assert_eq!(col.collapsed, None);
29//! ```
30//!
31//! You can update Worksheet Columns by using the methods in WorkSheetCol
32//! ```
33//! use edit_xlsx::{Column, Workbook, WorkSheetCol};
34//! let mut workbook = Workbook::new();
35//! let worksheet = workbook.get_worksheet_mut(1).unwrap();
36//! let col = Column::new(15.0, 2, 1, 0);
37//! worksheet.set_columns("A:C", &col).unwrap();
38//! workbook.save_as("./examples/col_update_columns.xlsx").unwrap()
39//! ```
40
41use std::collections::HashMap;
42pub(crate) use crate::api::cell::location::LocationRange;
43use crate::api::worksheet::format::_Format;
44use crate::api::worksheet::WorkSheet;
45use crate::{Format, Row, Cell};
46use crate::result::WorkSheetResult;
47
48/// [`Column`] records the fields you want to update to worksheets.
49///
50/// # Fields:
51/// | field | type |meaning|
52/// | ---- | ---- |----|
53/// | `width` | [`Option<f64>`] |The custom width you want to update with.|
54/// | `outline_level` | [`Option<u8>`] |The outline level of a column, learn more from [official documentation](https://support.microsoft.com/en-us/office/outline-group-data-in-a-worksheet-08ce98c4-0063-4d42-8ac7-8278c49e9aff).|
55/// | `hidden` | [`Option<u8>`] |Whether the column is hidden or not.|
56/// | `collapsed` | [`Option<u8>`] |collapse columns to group them.|
57#[derive(Copy, Clone, Default, Debug)]
58pub struct Column {
59    pub width: Option<f64>,
60    pub(crate) style: Option<u32>,
61    pub outline_level: Option<u8>,
62    pub hidden: Option<u8>,
63    pub collapsed: Option<u8>,
64}
65
66impl Column {
67    //
68    // constructors
69    //
70    /// If you need to customize each field, you can use the [`Column::new()`] method to create a [`Column`]
71    /// ```
72    /// use edit_xlsx::Column;
73    /// let col = Column::new(15.0, 2, 1, 0);
74    /// assert_eq!(col.width, Some(15.0));
75    /// assert_eq!(col.outline_level, Some(2));
76    /// assert_eq!(col.hidden, Some(1));
77    /// assert_eq!(col.collapsed, Some(0));
78    /// ```
79    pub fn new(width: f64, outline_level: u8, hidden: u8, collapsed: u8) -> Column {
80        Column {
81            width: Some(width),
82            style: None,
83            outline_level: Some(outline_level),
84            hidden: Some(hidden),
85            collapsed: Some(collapsed),
86        }
87    }
88
89    /// If you want to custom the format of col, you can use [`Column::new_by_worksheet()`] method.
90    /// **NOTICE**: A [`Column`] created using the [`Column::new_by_worksheet()`] method can only be used in incoming worksheets.
91    /// ```
92    /// use edit_xlsx::{Workbook, WorkSheetCol, Column, Format, FormatColor};
93    /// let red = Format::default().set_background_color(FormatColor::RGB(255, 0, 0));
94    /// let mut workbook = Workbook::new();
95    /// let worksheet = workbook.get_worksheet_mut(1).unwrap();
96    /// let col = Column::new_by_worksheet(15.0, 2, 1, 0, &red, worksheet);
97    /// worksheet.set_columns("A:C", &col).unwrap();
98    /// workbook.save_as("./examples/col_new_by_worksheet.xlsx").unwrap()
99    /// ```
100    pub fn new_by_worksheet(width: f64, outline_level: u8
101                            , hidden: u8, collapsed: u8
102                            , format: &Format, work_sheet: &mut WorkSheet) -> Column {
103        let mut col = Column::new(width, outline_level, hidden, collapsed);
104        col.style = Some(work_sheet.add_format(format));
105        col
106    }
107}
108
109/// [`WorkSheetCol`] is a trait for [`WorkSheet`]s that allowing them working with [`Column`]s.
110///
111/// Not only does it support reading and updating cols directly,
112/// but it also provides a set of suggested methods for reading and updating cols swiftly.
113pub trait WorkSheetCol: _Col {
114    //
115    // get methods
116    //
117
118    /// Get the [`Column`]s based on the col range,
119    /// note that the col range starts with 1.
120    /// # Example
121    /// ```
122    /// use edit_xlsx::{Workbook, WorkSheetCol};
123    /// let workbook = Workbook::from_path("./examples/xlsx/accounting.xlsx").unwrap();
124    /// let worksheet = workbook.get_worksheet_by_name("worksheet").unwrap();
125    /// let columns = worksheet.get_columns("B:B").unwrap();
126    /// let first_col = columns.get("B:B").unwrap();
127    /// // Convert to u32 to reduce error
128    /// assert_eq!(first_col.width.unwrap() as u32, 26);
129    /// ```
130    fn get_columns<R: LocationRange>(&self, col_range: R) -> WorkSheetResult<HashMap<String, Column>> {
131        self.list_by_range(col_range)
132    }
133
134    /// Get the [`Column`]s and [`Format`]s of cols based on the col range,
135    /// note that the col range starts with 1.
136    /// # Example
137    /// ```
138    /// use edit_xlsx::{FormatColor, Workbook, WorkSheetCol};
139    /// let workbook = Workbook::from_path("./examples/xlsx/accounting.xlsx").unwrap();
140    /// let worksheet = workbook.get_worksheet_by_name("worksheet").unwrap();
141    /// let columns_with_format = worksheet.get_columns_with_format("M:N").unwrap();
142    /// let (_, format) = columns_with_format.get("M:N").unwrap();
143    /// let format_clone = format.clone();
144    /// assert_eq!(format_clone.unwrap().get_background().fg_color, FormatColor::RGB(255, 0, 0));
145    /// ```
146    fn get_columns_with_format<R: LocationRange>(&self, col_range: R) -> WorkSheetResult<HashMap<String, (Column, Option<Format>)>> {
147        let all = self.list_by_range(col_range)?
148            .iter()
149            .map(|(k, v)| (
150                k.clone(),
151                (*v,
152                 match v.style {
153                     None => None,
154                     Some(style) => Some(self.get_format(style))
155                 })
156            ))
157            .collect();
158        Ok(all)
159    }
160
161    /// Get the custom width of cols based on the col range,
162    /// note that the col range starts with 1.
163    /// # Example
164    /// ```
165    /// use edit_xlsx::{Workbook, WorkSheetCol};
166    /// let workbook = Workbook::from_path("./examples/xlsx/accounting.xlsx").unwrap();
167    /// let worksheet = workbook.get_worksheet_by_name("worksheet").unwrap();
168    /// let widths = worksheet.get_columns_width("A:C").unwrap();
169    /// widths.iter().for_each(|(k, v)|{
170    ///   //Convert to u32 to reduce error
171    ///   let width = v.unwrap() as u32;
172    ///   match k.as_str() {
173    ///     "A:A"|"C:C" => assert_eq!(width, 12),
174    ///     "B:B" => assert_eq!(width, 26),
175    ///     _ => {}
176    ///   }
177    /// });
178    /// ```
179    fn get_columns_width<R: LocationRange>(&self, col_range: R) -> WorkSheetResult<HashMap<String, Option<f64>>> {
180        let columns = self.list_by_range(col_range)?;
181        let widths = columns.iter().map(|(k, v)| (k.clone(), v.width)).collect();
182        Ok(widths)
183    }
184
185    //
186    // set methods
187    //
188
189    /// update columns by [`Column`].
190    ///
191    /// Only not none fields will be updated
192    ///
193    /// # Example
194    /// ```
195    /// use edit_xlsx::{Column, Workbook, WorkSheetCol};
196    /// let mut workbook = Workbook::from_path("./examples/xlsx/accounting.xlsx").unwrap();
197    /// let mut worksheet = workbook.get_worksheet_mut_by_name("worksheet").unwrap();
198    /// let mut col = Column::default();
199    /// col.outline_level = Some(1);
200    /// col.hidden = Some(1);
201    /// worksheet.set_columns("B:E", &col).unwrap();
202    /// workbook.save_as("./examples/col_set_columns.xlsx").unwrap()
203    /// ```
204    fn set_columns<R: LocationRange>(&mut self, col_range: R, column: &Column) -> WorkSheetResult<()> {
205        self.set_by_column(col_range, column)?;
206        Ok(())
207    }
208
209    /// update columns and formats by [`Column`].
210    ///
211    /// Only not none fields will be updated.
212    ///
213    /// **NOTICE**: Changing the [`Column`]'s [`Format`] does not mean that the effect can be seen directly in Excel,
214    /// because the style priority is [`Cell`]>[`Row`]>[`Column`].
215    /// # Example
216    /// ```
217    /// use edit_xlsx::{Column, Format, FormatColor, Workbook, WorkSheetCol};
218    /// let mut workbook = Workbook::from_path("./examples/xlsx/accounting.xlsx").unwrap();
219    /// let mut worksheet = workbook.get_worksheet_mut_by_name("worksheet").unwrap();
220    /// let mut col = Column::default();
221    /// col.outline_level = Some(1);
222    /// col.hidden = Some(1);
223    /// let white_font = Format::default().set_background_color(FormatColor::Index(4)).set_color(FormatColor::RGB(255, 255, 255));
224    /// worksheet.set_columns_with_format("B:E", &col, &white_font).unwrap();
225    /// workbook.save_as("./examples/col_set_columns_with_format.xlsx").unwrap()
226    /// ```
227    fn set_columns_with_format<R: LocationRange>(&mut self, col_range: R, column: &Column, format: &Format) -> WorkSheetResult<()> {
228        let mut col = column.clone();
229        col.style = Some(self.add_format(format));
230        self.set_by_column(col_range, &col)?;
231        Ok(())
232    }
233
234    /// set the width of columns by columns range,
235    /// The effect is the same as
236    /// # Basic Example
237    /// ```
238    /// use edit_xlsx::Column;
239    /// let mut col = Column::default();
240    /// col.width = Some(8.0);
241    /// // worksheet.set_columns("A:C", &col);
242    /// ```
243    fn set_columns_width<R: LocationRange>(&mut self, col_range: R, width: f64) -> WorkSheetResult<()> {
244        let mut col_set = Column::default();
245        col_set.width = Some(width);
246        self.set_by_column(col_range, &col_set)?;
247        Ok(())
248    }
249    fn set_columns_width_pixels<R: LocationRange>(&mut self, col_range: R, width: f64) -> WorkSheetResult<()> {
250        let mut col_set = Column::default();
251        col_set.width = Some(0.5 * width);
252        self.set_by_column(col_range, &col_set)?;
253        Ok(())
254    }
255
256    /// set the width of columns by columns range,
257    /// The effect is the same as
258    /// # Basic Example
259    /// ```
260    /// use edit_xlsx::{Column, Format};
261    /// let mut col = Column::default();
262    /// col.width = Some(8.0);
263    /// let format = Format::default();
264    /// // worksheet.set_columns_with_format("A:C", &col, &format);
265    /// ```
266    fn set_columns_width_with_format<R: LocationRange>(&mut self, col_range: R, width: f64, format: &Format) -> WorkSheetResult<()> {
267        let mut col_set = Column::default();
268        col_set.style = Some(self.add_format(format));
269        col_set.width = Some(width);
270        self.set_by_column(col_range, &col_set)?;
271        Ok(())
272    }
273    fn set_columns_width_pixels_with_format<R: LocationRange>(&mut self, col_range: R, width: f64, format: &Format) -> WorkSheetResult<()> {
274        let mut col_set = Column::default();
275        col_set.style = Some(self.add_format(format));
276        col_set.width = Some(0.5 * width);
277        self.set_by_column(col_range, &col_set)?;
278        Ok(())
279    }
280
281    /// hide columns by column range,
282    /// The effect is the same as
283    /// # Basic Example
284    /// ```
285    /// use edit_xlsx::Column;
286    /// let mut col = Column::default();
287    /// col.hidden = Some(1);
288    /// // worksheet.set_columns("A:C", &col);
289    /// ```
290    fn hide_columns<R: LocationRange>(&mut self, col_range: R) -> WorkSheetResult<()> {
291        let mut col_set = Column::default();
292        col_set.hidden = Some(1);
293        self.set_by_column(col_range, &col_set)?;
294        Ok(())
295    }
296
297    /// set the outline of columns by column range,
298    /// The effect is the same as
299    /// # Basic Example
300    /// ```
301    /// use edit_xlsx::Column;
302    /// let mut col = Column::default();
303    /// col.outline_level = Some(1);
304    /// // worksheet.set_columns("A:C", &col);
305    /// ```
306    fn set_columns_level<R: LocationRange>(&mut self, col_range: R, level: u8) -> WorkSheetResult<()> {
307        let mut col_set = Column::default();
308        col_set.outline_level = Some(level);
309        self.set_by_column(col_range, &col_set)?;
310        Ok(())
311    }
312    /// collapse columns by column range,
313    /// The effect is the same as
314    /// # Basic Example
315    /// ```
316    /// use edit_xlsx::Column;
317    /// let mut col = Column::default();
318    /// col.collapsed = Some(1);
319    /// // worksheet.set_columns("A:C", &col);
320    /// ```
321    fn collapse_columns<R: LocationRange>(&mut self, col_range: R) -> WorkSheetResult<()> {
322        let mut col_set = Column::default();
323        col_set.collapsed = Some(1);
324        self.set_by_column(col_range, &col_set)?;
325        Ok(())
326    }
327}
328
329pub(crate) trait _Col: _Format {
330    fn set_by_column<R: LocationRange>(&mut self, col_range: R, col_set: &Column) -> WorkSheetResult<()>;
331    fn list_by_range<R: LocationRange>(&self, col_range: R) -> WorkSheetResult<HashMap<String, Column>>;
332}
333
334impl _Col for WorkSheet {
335    fn set_by_column<R: LocationRange>(&mut self, col_range: R, col_set: &Column) -> WorkSheetResult<()> {
336        self.worksheet.set_col_by_column(col_range, col_set)?;
337        Ok(())
338    }
339
340    fn list_by_range<R: LocationRange>(&self, col_range: R) -> WorkSheetResult<HashMap<String, Column>> {
341        let columns = self.worksheet.get_col(col_range)?;
342        Ok(columns)
343    }
344}