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}