rust_xlsxwriter/
table.rs

1// table - A module for creating the Excel Table.xml file.
2//
3// SPDX-License-Identifier: MIT OR Apache-2.0
4//
5// Copyright 2022-2025, John McNamara, jmcnamara@cpan.org
6
7#![warn(missing_docs)]
8
9mod tests;
10
11use std::io::Cursor;
12use std::{collections::HashSet, fmt};
13
14use crate::xmlwriter::{
15    xml_data_element_only, xml_declaration, xml_empty_tag, xml_end_tag, xml_start_tag,
16};
17use crate::{utility::ToXmlBoolean, CellRange, Format, Formula, RowNum, XlsxError};
18
19/// The `Table` struct represents a worksheet table.
20///
21/// Tables in Excel are a way of grouping a range of cells into a single entity
22/// that has common formatting or that can be referenced in formulas. Tables
23/// can have column headers, autofilters, total rows, column formulas, and
24/// different formatting styles.
25///
26/// The image below shows a default table in Excel with the default properties
27/// displayed in the ribbon bar.
28///
29/// <img src="https://rustxlsxwriter.github.io/images/table_intro.png">
30///
31/// A table is added to a worksheet via the
32/// [`Worksheet::add_table()`](crate::Worksheet::add_table) method. The headers
33/// and total row of a table should be configured via a `Table` struct, but the
34/// table data can be added using standard
35/// [`Worksheet::write()`](crate::Worksheet::write) methods:
36///
37/// ```
38/// # // This code is available in examples/doc_table_set_columns.rs
39/// #
40/// use rust_xlsxwriter::{Table, TableColumn, TableFunction, Workbook, XlsxError};
41///
42/// fn main() -> Result<(), XlsxError> {
43///     // Create a new Excel file object.
44///     let mut workbook = Workbook::new();
45///
46///     // Add a worksheet to the workbook.
47///     let worksheet = workbook.add_worksheet();
48///
49///     // Some sample data for the table.
50///     let items = ["Apples", "Pears", "Bananas", "Oranges"];
51///     let data = [
52///         [10000, 5000, 8000, 6000],
53///         [2000, 3000, 4000, 5000],
54///         [6000, 6000, 6500, 6000],
55///         [500, 300, 200, 700],
56///     ];
57///
58///     // Write the table data.
59///     worksheet.write_column(3, 1, items)?;
60///     worksheet.write_row_matrix(3, 2, data)?;
61///
62///     // Set the column widths for clarity.
63///     worksheet.set_column_range_width(1, 6, 12)?;
64///
65///     // Create a new table and configure it.
66///     let columns = vec![
67///         TableColumn::new()
68///             .set_header("Product")
69///             .set_total_label("Totals"),
70///         TableColumn::new()
71///             .set_header("Quarter 1")
72///             .set_total_function(TableFunction::Sum),
73///         TableColumn::new()
74///             .set_header("Quarter 2")
75///             .set_total_function(TableFunction::Sum),
76///         TableColumn::new()
77///             .set_header("Quarter 3")
78///             .set_total_function(TableFunction::Sum),
79///         TableColumn::new()
80///             .set_header("Quarter 4")
81///             .set_total_function(TableFunction::Sum),
82///         TableColumn::new()
83///             .set_header("Year")
84///             .set_total_function(TableFunction::Sum)
85///             .set_formula("SUM(Table1[@[Quarter 1]:[Quarter 4]])"),
86///     ];
87///
88///     let table = Table::new().set_columns(&columns).set_total_row(true);
89///
90///     // Add the table to the worksheet.
91///     worksheet.add_table(2, 1, 7, 6, &table)?;
92///
93///     // Save the file to disk.
94///     workbook.save("tables.xlsx")?;
95///
96///     Ok(())
97/// }
98/// ```
99///
100/// Output file:
101///
102/// <img src="https://rustxlsxwriter.github.io/images/table_set_columns.png">
103///
104/// For more information on tables see the Microsoft documentation on [Overview
105/// of Excel tables].
106///
107/// [Overview of Excel tables]:
108///     https://support.microsoft.com/en-us/office/overview-of-excel-tables-7ab0bb7d-3a9e-4b56-a3c9-6c94334e492c
109///
110#[derive(Clone)]
111pub struct Table {
112    pub(crate) writer: Cursor<Vec<u8>>,
113
114    pub(crate) columns: Vec<TableColumn>,
115
116    pub(crate) index: u32,
117    pub(crate) name: String,
118    pub(crate) style: TableStyle,
119
120    pub(crate) cell_range: CellRange,
121
122    pub(crate) show_header_row: bool,
123    pub(crate) show_total_row: bool,
124    pub(crate) show_first_column: bool,
125    pub(crate) show_last_column: bool,
126    pub(crate) show_banded_rows: bool,
127    pub(crate) show_banded_columns: bool,
128    pub(crate) show_autofilter: bool,
129    pub(crate) is_serde_table: bool,
130}
131
132impl Table {
133    // -----------------------------------------------------------------------
134    // Public (and crate public) methods.
135    // -----------------------------------------------------------------------
136
137    /// Create a new Table struct instance.
138    ///
139    /// Create a table that can be added to a data range of a worksheet. The
140    /// headers, totals, formulas, and other properties can be set via the
141    /// `Table::*` methods shown below. The data should be added to the table
142    /// region using the standard
143    /// [`Worksheet::write()`](crate::Worksheet::write) methods.
144    ///
145    /// # Examples
146    ///
147    /// Example of creating a new table and adding it to a worksheet.
148    ///
149    /// ```
150    /// # // This code is available in examples/doc_table_set_header_row2.rs
151    /// #
152    /// use rust_xlsxwriter::{Table, Workbook, XlsxError};
153    ///
154    /// fn main() -> Result<(), XlsxError> {
155    ///     // Create a new Excel file object.
156    ///     let mut workbook = Workbook::new();
157    ///
158    ///     // Add a worksheet to the workbook.
159    ///     let worksheet = workbook.add_worksheet();
160    ///
161    ///     // Some sample data for the table.
162    ///     let items = ["Apples", "Pears", "Bananas", "Oranges"];
163    ///     let data = [
164    ///         [10000, 5000, 8000, 6000],
165    ///         [2000, 3000, 4000, 5000],
166    ///         [6000, 6000, 6500, 6000],
167    ///         [500, 300, 200, 700],
168    ///     ];
169    ///
170    ///     // Write the table data.
171    ///     worksheet.write_column(3, 1, items)?;
172    ///     worksheet.write_row_matrix(3, 2, data)?;
173    ///
174    ///     // Set the column widths for clarity.
175    ///     worksheet.set_column_range_width(1, 6, 12)?;
176    ///
177    ///     // Create a new table.
178    ///     let table = Table::new();
179    ///
180    ///     // Add the table to the worksheet.
181    ///     worksheet.add_table(2, 1, 6, 5, &table)?;
182    ///
183    ///     // Save the file to disk.
184    ///     workbook.save("tables.xlsx")?;
185    ///
186    ///     Ok(())
187    /// }
188    /// ```
189    ///
190    /// Output file:
191    ///
192    /// <img
193    /// src="https://rustxlsxwriter.github.io/images/table_set_header_row2.png">
194    ///
195    ///
196    #[allow(clippy::new_without_default)]
197    pub fn new() -> Table {
198        let writer = Cursor::new(Vec::with_capacity(2048));
199
200        Table {
201            writer,
202            columns: vec![],
203            index: 0,
204            name: String::new(),
205            style: TableStyle::Medium9,
206            cell_range: CellRange::default(),
207            show_first_column: false,
208            show_last_column: false,
209            show_banded_rows: true,
210            show_banded_columns: false,
211            show_autofilter: true,
212            show_header_row: true,
213            show_total_row: false,
214            is_serde_table: false,
215        }
216    }
217
218    /// Turn on/off the header row for a table.
219    ///
220    /// Turn on or off the header row in the table. The header row displays the
221    /// column names and, unless it is turned off, an autofilter. It is on by
222    /// default.
223    ///
224    /// The header row will display default captions such as `Column 1`, `Column
225    /// 2`, etc. These captions can be overridden using the
226    /// [`Table::set_columns()`] method, see the examples below. They shouldn't
227    /// be written or overwritten using standard
228    /// [`Worksheet::write()`](crate::Worksheet::write) methods since that will
229    /// cause a warning when the file is loaded in Excel.
230    ///
231    /// # Parameters
232    ///
233    /// - `enable`: Turn the property on/off. It is on by default.
234    ///
235    /// # Examples
236    ///
237    /// Example of adding a worksheet table with a default header.
238    ///
239    /// ```
240    /// # // This code is available in examples/doc_table_set_header_row2.rs
241    /// #
242    /// # use rust_xlsxwriter::{Table, Workbook, XlsxError};
243    /// #
244    /// # fn main() -> Result<(), XlsxError> {
245    /// #     // Create a new Excel file object.
246    /// #     let mut workbook = Workbook::new();
247    /// #
248    /// #     // Add a worksheet to the workbook.
249    /// #     let worksheet = workbook.add_worksheet();
250    /// #
251    /// #     // Some sample data for the table.
252    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
253    /// #     let data = [
254    /// #         [10000, 5000, 8000, 6000],
255    /// #         [2000, 3000, 4000, 5000],
256    /// #         [6000, 6000, 6500, 6000],
257    /// #         [500, 300, 200, 700],
258    /// #     ];
259    /// #
260    /// #     // Write the table data.
261    /// #     worksheet.write_column(3, 1, items)?;
262    /// #     worksheet.write_row_matrix(3, 2, data)?;
263    /// #
264    /// #     // Set the column widths for clarity.
265    /// #     worksheet.set_column_range_width(1, 6, 12)?;
266    /// #
267    ///     // Create a new table.
268    ///     let table = Table::new();
269    ///
270    ///     // Add the table to the worksheet.
271    ///     worksheet.add_table(2, 1, 6, 5, &table)?;
272    /// #
273    /// #     // Save the file to disk.
274    /// #     workbook.save("tables.xlsx")?;
275    /// #
276    /// #     Ok(())
277    /// # }
278    /// ```
279    ///
280    /// Output file:
281    ///
282    /// <img
283    /// src="https://rustxlsxwriter.github.io/images/table_set_header_row2.png">
284    ///
285    ///
286    /// Example of turning off the default header on a worksheet table. Note,
287    /// that the table range has been adjusted in relation to the previous
288    /// example to account for the missing header.
289    ///
290    /// ```
291    /// # // This code is available in examples/doc_table_set_header_row.rs
292    /// #
293    /// # use rust_xlsxwriter::{Table, Workbook, XlsxError};
294    /// #
295    /// # fn main() -> Result<(), XlsxError> {
296    /// #     // Create a new Excel file object.
297    /// #     let mut workbook = Workbook::new();
298    /// #
299    /// #     // Add a worksheet to the workbook.
300    /// #     let worksheet = workbook.add_worksheet();
301    /// #
302    /// #     // Some sample data for the table.
303    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
304    /// #     let data = [
305    /// #         [10000, 5000, 8000, 6000],
306    /// #         [2000, 3000, 4000, 5000],
307    /// #         [6000, 6000, 6500, 6000],
308    /// #         [500, 300, 200, 700],
309    /// #     ];
310    /// #
311    /// #     // Write the table data.
312    /// #     worksheet.write_column(2, 1, items)?;
313    /// #     worksheet.write_row_matrix(2, 2, data)?;
314    /// #
315    /// #     // Set the column widths for clarity.
316    /// #     worksheet.set_column_range_width(1, 6, 12)?;
317    /// #
318    ///     // Create a new table and configure the header.
319    ///     let table = Table::new().set_header_row(false);
320    ///
321    ///     // Add the table to the worksheet.
322    ///     worksheet.add_table(2, 1, 5, 5, &table)?;
323    /// #
324    /// #     // Save the file to disk.
325    /// #     workbook.save("tables.xlsx")?;
326    /// #
327    /// #     Ok(())
328    /// # }
329    /// ```
330    ///
331    /// Output file:
332    ///
333    /// <img
334    /// src="https://rustxlsxwriter.github.io/images/table_set_header_row.png">
335    ///
336    /// Example of adding a worksheet table with a user defined header captions.
337    ///
338    /// ```
339    /// # // This code is available in examples/doc_table_set_header_row3.rs
340    /// #
341    /// # use rust_xlsxwriter::{Table, TableColumn, Workbook, XlsxError};
342    /// #
343    /// # fn main() -> Result<(), XlsxError> {
344    /// #     // Create a new Excel file object.
345    /// #     let mut workbook = Workbook::new();
346    /// #
347    /// #     // Add a worksheet to the workbook.
348    /// #     let worksheet = workbook.add_worksheet();
349    /// #
350    /// #     // Some sample data for the table.
351    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
352    /// #     let data = [
353    /// #         [10000, 5000, 8000, 6000],
354    /// #         [2000, 3000, 4000, 5000],
355    /// #         [6000, 6000, 6500, 6000],
356    /// #         [500, 300, 200, 700],
357    /// #     ];
358    /// #
359    /// #     // Write the table data.
360    /// #     worksheet.write_column(3, 1, items)?;
361    /// #     worksheet.write_row_matrix(3, 2, data)?;
362    /// #
363    /// #     // Set the column widths for clarity.
364    /// #     worksheet.set_column_range_width(1, 6, 12)?;
365    /// #
366    ///     // Set the captions for the header row.
367    ///     let columns = vec![
368    ///         TableColumn::new().set_header("Product"),
369    ///         TableColumn::new().set_header("Quarter 1"),
370    ///         TableColumn::new().set_header("Quarter 2"),
371    ///         TableColumn::new().set_header("Quarter 3"),
372    ///         TableColumn::new().set_header("Quarter 4"),
373    ///     ];
374    ///
375    ///     // Create a new table and configure the column headers.
376    ///     let table = Table::new().set_columns(&columns);
377    ///
378    ///     // Add the table to the worksheet.
379    ///     worksheet.add_table(2, 1, 6, 5, &table)?;
380    /// #
381    /// #     // Save the file to disk.
382    /// #     workbook.save("tables.xlsx")?;
383    /// #
384    /// #     Ok(())
385    /// # }
386    /// ```
387    ///
388    /// Output file:
389    ///
390    /// <img
391    /// src="https://rustxlsxwriter.github.io/images/table_set_header_row3.png">
392    ///
393    pub fn set_header_row(mut self, enable: bool) -> Table {
394        self.show_header_row = enable;
395
396        // The table autofilter should be off if the header is off so that it
397        // isn't included in the autofit() calculation.
398        if !self.show_header_row {
399            self.show_autofilter = false;
400        }
401
402        self
403    }
404
405    /// Turn on a totals row for a table.
406    ///
407    /// The `set_total_row()` method can be used to turn on the total row in the
408    /// last row of a table. The total row is distinguished from the other rows
409    /// by a different formatting and with dropdown `SUBTOTAL()` functions.
410    ///
411    /// Note, you will need to use [`TableColumn`] methods to populate this row.
412    /// Overwriting the total row cells with `worksheet.write()` calls will
413    /// cause Excel to warn that the table is corrupt when loading the file.
414    ///
415    /// # Parameters
416    ///
417    /// - `enable`: Turn the property on/off. It is off by default.
418    ///
419    ///
420    /// # Examples
421    ///
422    /// Example of turning on the "totals" row at the bottom of a worksheet
423    /// table. Note, this just turns on the total run it doesn't add captions or
424    /// subtotal functions. See the next example below.
425    ///
426    /// ```
427    /// # // This code is available in examples/doc_table_set_total_row.rs
428    /// #
429    /// # use rust_xlsxwriter::{Table, Workbook, XlsxError};
430    /// #
431    /// # fn main() -> Result<(), XlsxError> {
432    /// #     // Create a new Excel file object.
433    /// #     let mut workbook = Workbook::new();
434    /// #
435    /// #     // Add a worksheet to the workbook.
436    /// #     let worksheet = workbook.add_worksheet();
437    /// #
438    /// #     // Some sample data for the table.
439    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
440    /// #     let data = [
441    /// #         [10000, 5000, 8000, 6000],
442    /// #         [2000, 3000, 4000, 5000],
443    /// #         [6000, 6000, 6500, 6000],
444    /// #         [500, 300, 200, 700],
445    /// #     ];
446    /// #
447    /// #     // Write the table data.
448    /// #     worksheet.write_column(3, 1, items)?;
449    /// #     worksheet.write_row_matrix(3, 2, data)?;
450    /// #
451    /// #     // Set the column widths for clarity.
452    /// #     worksheet.set_column_range_width(1, 6, 12)?;
453    /// #
454    ///     // Create a new table and configure the total row.
455    ///     let table = Table::new().set_total_row(true);
456    ///
457    ///     // Add the table to the worksheet.
458    ///     worksheet.add_table(2, 1, 7, 5, &table)?;
459    /// #
460    /// #     // Save the file to disk.
461    /// #     workbook.save("tables.xlsx")?;
462    /// #
463    /// #     Ok(())
464    /// # }
465    /// ```
466    ///
467    /// Output file:
468    ///
469    /// <img
470    /// src="https://rustxlsxwriter.github.io/images/table_set_total_row.png">
471    ///
472    /// Example of turning on the "totals" row at the bottom of a worksheet
473    /// table with captions and subtotal functions.
474    ///
475    /// ```
476    /// # // This code is available in examples/doc_table_set_total_row2.rs
477    /// #
478    /// # use rust_xlsxwriter::{Formula, Table, TableColumn, TableFunction, Workbook, XlsxError};
479    /// #
480    /// # fn main() -> Result<(), XlsxError> {
481    /// #     // Create a new Excel file object.
482    /// #     let mut workbook = Workbook::new();
483    /// #
484    /// #     // Add a worksheet to the workbook.
485    /// #     let worksheet = workbook.add_worksheet();
486    /// #
487    /// #     // Some sample data for the table.
488    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
489    /// #     let data = [
490    /// #         [10000, 5000, 8000, 6000],
491    /// #         [2000, 3000, 4000, 5000],
492    /// #         [6000, 6000, 6500, 6000],
493    /// #         [500, 300, 200, 700],
494    /// #     ];
495    /// #
496    /// #     // Write the table data.
497    /// #     worksheet.write_column(3, 1, items)?;
498    /// #     worksheet.write_row_matrix(3, 2, data)?;
499    /// #
500    /// #     // Set the column widths for clarity.
501    /// #     worksheet.set_column_range_width(1, 6, 12)?;
502    /// #
503    ///     // Set the caption and subtotal in the total row.
504    ///     let columns = vec![
505    ///         TableColumn::new().set_total_label("Totals"),
506    ///         TableColumn::new().set_total_function(TableFunction::Sum),
507    ///         TableColumn::new().set_total_function(TableFunction::Sum),
508    ///         TableColumn::new().set_total_function(TableFunction::Sum),
509    ///         // Use a custom formula to get a similar summation.
510    ///         TableColumn::new()
511    ///             .set_total_function(TableFunction::Custom(Formula::new("SUM([Column5])"))),
512    ///     ];
513    ///
514    ///     // Create a new table and configure the total row.
515    ///     let table = Table::new().set_total_row(true).set_columns(&columns);
516    ///
517    ///     // Add the table to the worksheet.
518    ///     worksheet.add_table(2, 1, 7, 5, &table)?;
519    /// #
520    /// #     // Save the file to disk.
521    /// #     workbook.save("tables.xlsx")?;
522    /// #
523    /// #     Ok(())
524    /// # }
525    /// ```
526    ///
527    /// Output file:
528    ///
529    /// <img
530    /// src="https://rustxlsxwriter.github.io/images/table_set_total_row2.png">
531    ///
532    pub fn set_total_row(mut self, enable: bool) -> Table {
533        self.show_total_row = enable;
534        self
535    }
536
537    /// Turn on/off banded rows for a table.
538    ///
539    /// By default, Excel uses "banded" rows of alternating colors in a table to
540    /// distinguish each data row, like this:
541    ///
542    /// <img
543    /// src="https://rustxlsxwriter.github.io/images/table_set_header_row2.png">
544    ///
545    /// If you prefer not to have this type of formatting, you can turn it off,
546    /// see the example below.
547    ///
548    /// Note, you can also select a table style without banded rows using the
549    /// [`Table::set_style()`] method.
550    ///
551    /// # Parameters
552    ///
553    /// - `enable`: Turn the property on/off. It is on by default.
554    /// # Examples
555    ///
556    /// Example of turning off the banded rows property in a worksheet table.
557    ///
558    /// ```
559    /// # // This code is available in examples/doc_table_set_banded_rows.rs
560    /// #
561    /// # use rust_xlsxwriter::{Table, Workbook, XlsxError};
562    /// #
563    /// # fn main() -> Result<(), XlsxError> {
564    /// #     // Create a new Excel file object.
565    /// #     let mut workbook = Workbook::new();
566    /// #
567    /// #     // Add a worksheet to the workbook.
568    /// #     let worksheet = workbook.add_worksheet();
569    /// #
570    /// #     // Some sample data for the table.
571    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
572    /// #     let data = [
573    /// #         [10000, 5000, 8000, 6000],
574    /// #         [2000, 3000, 4000, 5000],
575    /// #         [6000, 6000, 6500, 6000],
576    /// #         [500, 300, 200, 700],
577    /// #     ];
578    /// #
579    /// #     // Write the table data.
580    /// #     worksheet.write_column(3, 1, items)?;
581    /// #     worksheet.write_row_matrix(3, 2, data)?;
582    /// #
583    /// #     // Set the column widths for clarity.
584    /// #     worksheet.set_column_range_width(1, 6, 12)?;
585    /// #
586    ///     // Create a new table and configure the banded rows.
587    ///     let table = Table::new().set_banded_rows(false);
588    ///
589    ///     // Add the table to the worksheet.
590    ///     worksheet.add_table(2, 1, 6, 5, &table)?;
591    /// #
592    /// #     // Save the file to disk.
593    /// #     workbook.save("tables.xlsx")?;
594    /// #
595    /// #     Ok(())
596    /// # }
597    /// ```
598    ///
599    /// Output file:
600    ///
601    /// <img
602    /// src="https://rustxlsxwriter.github.io/images/table_set_banded_rows.png">
603    ///
604    pub fn set_banded_rows(mut self, enable: bool) -> Table {
605        self.show_banded_rows = enable;
606        self
607    }
608
609    /// Turn on/off banded columns for a table.
610    ///
611    /// By default, Excel uses the same format color for each data column in a
612    /// table but alternates the color of rows. If you wish, you can set "banded"
613    /// columns of alternating colors in a table to distinguish each data column.
614    ///
615    /// # Parameters
616    ///
617    /// - `enable`: Turn the property on/off. It is off by default.
618    ///
619    /// # Examples
620    ///
621    /// Example of turning on the banded columns property in a worksheet table. These
622    /// are normally off by default,
623    ///
624    /// ```
625    /// # // This code is available in examples/doc_table_set_banded_columns.rs
626    /// #
627    /// # use rust_xlsxwriter::{Table, Workbook, XlsxError};
628    /// #
629    /// # fn main() -> Result<(), XlsxError> {
630    /// #     // Create a new Excel file object.
631    /// #     let mut workbook = Workbook::new();
632    /// #
633    /// #     // Add a worksheet to the workbook.
634    /// #     let worksheet = workbook.add_worksheet();
635    /// #
636    /// #     // Some sample data for the table.
637    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
638    /// #     let data = [
639    /// #         [10000, 5000, 8000, 6000],
640    /// #         [2000, 3000, 4000, 5000],
641    /// #         [6000, 6000, 6500, 6000],
642    /// #         [500, 300, 200, 700],
643    /// #     ];
644    /// #
645    /// #     // Write the table data.
646    /// #     worksheet.write_column(3, 1, items)?;
647    /// #     worksheet.write_row_matrix(3, 2, data)?;
648    /// #
649    /// #     // Set the column widths for clarity.
650    /// #     worksheet.set_column_range_width(1, 6, 12)?;
651    /// #
652    ///     // Create a new table and configure the banded columns (but turn off banded
653    ///     // rows for clarity).
654    ///     let table = Table::new().set_banded_columns(true).set_banded_rows(false);
655    ///
656    ///     // Add the table to the worksheet.
657    ///     worksheet.add_table(2, 1, 6, 5, &table)?;
658    /// #
659    /// #     // Save the file to disk.
660    /// #     workbook.save("tables.xlsx")?;
661    /// #
662    /// #     Ok(())
663    /// # }
664    /// ```
665    ///
666    /// Output file:
667    ///
668    /// <img src="https://rustxlsxwriter.github.io/images/table_set_banded_columns.png">
669    ///
670    pub fn set_banded_columns(mut self, enable: bool) -> Table {
671        self.show_banded_columns = enable;
672        self
673    }
674
675    /// Turn on/off the first column highlighting for a table.
676    ///
677    /// The first column of a worksheet table is often used for a list of items,
678    /// whereas the other columns are more commonly used for data. In these
679    /// cases, it is sometimes desirable to highlight the first column differently.
680    ///
681    /// # Parameters
682    ///
683    /// - `enable`: Turn the property on/off. It is off by default.
684    ///
685    /// # Examples
686    ///
687    /// Example of turning on the first column highlighting property in a
688    /// worksheet table. This is normally off by default,
689    ///
690    /// ```
691    /// # // This code is available in examples/doc_table_set_first_column.rs
692    /// #
693    /// # use rust_xlsxwriter::{Table, Workbook, XlsxError};
694    /// #
695    /// # fn main() -> Result<(), XlsxError> {
696    /// #     // Create a new Excel file object.
697    /// #     let mut workbook = Workbook::new();
698    /// #
699    /// #     // Add a worksheet to the workbook.
700    /// #     let worksheet = workbook.add_worksheet();
701    /// #
702    /// #     // Some sample data for the table.
703    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
704    /// #     let data = [
705    /// #         [10000, 5000, 8000, 6000],
706    /// #         [2000, 3000, 4000, 5000],
707    /// #         [6000, 6000, 6500, 6000],
708    /// #         [500, 300, 200, 700],
709    /// #     ];
710    /// #
711    /// #     // Write the table data.
712    /// #     worksheet.write_column(3, 1, items)?;
713    /// #     worksheet.write_row_matrix(3, 2, data)?;
714    /// #
715    /// #     // Set the column widths for clarity.
716    /// #     worksheet.set_column_range_width(1, 6, 12)?;
717    /// #
718    ///     // Create a new table and configure the first column highlighting.
719    ///     let table = Table::new().set_first_column(true);
720    ///
721    ///     // Add the table to the worksheet.
722    ///     worksheet.add_table(2, 1, 6, 5, &table)?;
723    /// #
724    /// #     // Save the file to disk.
725    /// #     workbook.save("tables.xlsx")?;
726    /// #
727    /// #     Ok(())
728    /// # }
729    /// ```
730    ///
731    /// Output file:
732    ///
733    /// <img
734    /// src="https://rustxlsxwriter.github.io/images/table_set_first_column.png">
735    ///
736    pub fn set_first_column(mut self, enable: bool) -> Table {
737        self.show_first_column = enable;
738        self
739    }
740
741    /// Turn on/off the last column highlighting for a table.
742    ///
743    /// The last column of a worksheet table is often used for a `SUM()` or
744    /// other formula operating on the data in the other columns. In these
745    /// cases, it is sometimes required to highlight the last column differently.
746    ///
747    /// # Parameters
748    ///
749    /// - `enable`: Turn the property on/off. It is off by default.
750    ///
751    /// # Examples
752    ///
753    /// Example of turning on the last column highlighting property in a
754    /// worksheet table. This is normally off by default,
755    ///
756    /// ```
757    /// # // This code is available in examples/doc_table_set_last_column.rs
758    /// #
759    /// # use rust_xlsxwriter::{Table, TableColumn, Workbook, XlsxError};
760    /// #
761    /// # fn main() -> Result<(), XlsxError> {
762    /// #     // Create a new Excel file object.
763    /// #     let mut workbook = Workbook::new();
764    /// #
765    /// #     // Add a worksheet to the workbook.
766    /// #     let worksheet = workbook.add_worksheet();
767    /// #
768    /// #     // Some sample data for the table.
769    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
770    /// #     let data = [
771    /// #         [10000, 5000, 8000, 6000],
772    /// #         [2000, 3000, 4000, 5000],
773    /// #         [6000, 6000, 6500, 6000],
774    /// #         [500, 300, 200, 700],
775    /// #     ];
776    /// #
777    /// #     // Write the table data.
778    /// #     worksheet.write_column(3, 1, items)?;
779    /// #     worksheet.write_row_matrix(3, 2, data)?;
780    /// #
781    /// #     // Set the column widths for clarity.
782    /// #     worksheet.set_column_range_width(1, 6, 12)?;
783    /// #
784    ///     // Add a structured reference formula to the last column and set the header
785    ///     // caption. The last column in `add_table()` should be extended to account
786    ///     // for this extra column.
787    ///     let columns = vec![
788    ///         TableColumn::default(),
789    ///         TableColumn::default(),
790    ///         TableColumn::default(),
791    ///         TableColumn::default(),
792    ///         TableColumn::default(),
793    ///         TableColumn::new()
794    ///             .set_header("Totals")
795    ///             .set_formula("SUM(Table1[@[Column2]:[Column5]])"),
796    ///     ];
797    ///
798    ///     // Create a new table and configure the last column highlighting.
799    ///     let table = Table::new().set_last_column(true).set_columns(&columns);
800    ///
801    ///     // Add the table to the worksheet.
802    ///     worksheet.add_table(2, 1, 6, 6, &table)?;
803    /// #
804    /// #     // Save the file to disk.
805    /// #     workbook.save("tables.xlsx")?;
806    /// #
807    /// #     Ok(())
808    /// # }
809    /// ```
810    ///
811    /// Output file:
812    ///
813    /// <img
814    /// src="https://rustxlsxwriter.github.io/images/table_set_last_column.png">
815    ///
816    pub fn set_last_column(mut self, enable: bool) -> Table {
817        self.show_last_column = enable;
818        self
819    }
820
821    /// Turn on/off the autofilter for a table.
822    ///
823    /// By default, Excel adds an autofilter to the header of a table. This
824    /// method can be used to turn it off if necessary.
825    ///
826    /// # Parameters
827    ///
828    /// - `enable`: Turn the property on/off. It is on by default.
829    ///
830    /// # Examples
831    ///
832    /// Example of turning off the autofilter in a worksheet table.
833    ///
834    /// ```
835    /// # // This code is available in examples/doc_table_set_autofilter.rs
836    /// #
837    /// # use rust_xlsxwriter::{Table, Workbook, XlsxError};
838    /// #
839    /// # fn main() -> Result<(), XlsxError> {
840    /// #     // Create a new Excel file object.
841    /// #     let mut workbook = Workbook::new();
842    /// #
843    /// #     // Add a worksheet to the workbook.
844    /// #     let worksheet = workbook.add_worksheet();
845    /// #
846    /// #     // Some sample data for the table.
847    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
848    /// #     let data = [
849    /// #         [10000, 5000, 8000, 6000],
850    /// #         [2000, 3000, 4000, 5000],
851    /// #         [6000, 6000, 6500, 6000],
852    /// #         [500, 300, 200, 700],
853    /// #     ];
854    /// #
855    /// #     // Write the table data.
856    /// #     worksheet.write_column(3, 1, items)?;
857    /// #     worksheet.write_row_matrix(3, 2, data)?;
858    /// #
859    /// #     // Set the column widths for clarity.
860    /// #     worksheet.set_column_range_width(1, 6, 12)?;
861    /// #
862    ///     // Create a new table and configure the autofilter.
863    ///     let table = Table::new().set_autofilter(false);
864    ///
865    ///     // Add the table to the worksheet.
866    ///     worksheet.add_table(2, 1, 6, 5, &table)?;
867    /// #
868    /// #     // Save the file to disk.
869    /// #     workbook.save("tables.xlsx")?;
870    /// #
871    /// #     Ok(())
872    /// # }
873    /// ```
874    ///
875    /// Output file:
876    ///
877    /// <img src="https://rustxlsxwriter.github.io/images/table_set_autofilter.png">
878    ///
879    pub fn set_autofilter(mut self, enable: bool) -> Table {
880        self.show_autofilter = enable;
881        self
882    }
883
884    /// Set properties for the columns in a table.
885    ///
886    /// Set the properties for columns in a worksheet table via an array of
887    /// [`TableColumn`] structs. This can be used to set the following
888    /// properties of a table column:
889    ///
890    /// - The header caption.
891    /// - The total row caption.
892    /// - The total row subtotal function.
893    /// - A formula for the column.
894    ///
895    ///
896    /// # Parameters
897    ///
898    /// - `columns`: An array reference of [`TableColumn`] structs. Use
899    ///   `TableColumn::default()` to get default values.
900    ///
901    ///
902    /// # Examples
903    ///
904    /// Example of creating a worksheet table.
905    ///
906    /// ```
907    /// # // This code is available in examples/doc_table_set_columns.rs
908    /// #
909    /// # use rust_xlsxwriter::{Table, TableColumn, TableFunction, Workbook, XlsxError};
910    /// #
911    /// # fn main() -> Result<(), XlsxError> {
912    /// #     // Create a new Excel file object.
913    /// #     let mut workbook = Workbook::new();
914    /// #
915    /// #     // Add a worksheet to the workbook.
916    /// #     let worksheet = workbook.add_worksheet();
917    /// #
918    /// #     // Some sample data for the table.
919    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
920    /// #     let data = [
921    /// #         [10000, 5000, 8000, 6000],
922    /// #         [2000, 3000, 4000, 5000],
923    /// #         [6000, 6000, 6500, 6000],
924    /// #         [500, 300, 200, 700],
925    /// #     ];
926    /// #
927    /// #     // Write the table data.
928    /// #     worksheet.write_column(3, 1, items)?;
929    /// #     worksheet.write_row_matrix(3, 2, data)?;
930    /// #
931    /// #     // Set the column widths for clarity.
932    /// #     worksheet.set_column_range_width(1, 6, 12)?;
933    /// #
934    ///     // Create a new table and configure it.
935    ///     let columns = vec![
936    ///         TableColumn::new()
937    ///             .set_header("Product")
938    ///             .set_total_label("Totals"),
939    ///         TableColumn::new()
940    ///             .set_header("Quarter 1")
941    ///             .set_total_function(TableFunction::Sum),
942    ///         TableColumn::new()
943    ///             .set_header("Quarter 2")
944    ///             .set_total_function(TableFunction::Sum),
945    ///         TableColumn::new()
946    ///             .set_header("Quarter 3")
947    ///             .set_total_function(TableFunction::Sum),
948    ///         TableColumn::new()
949    ///             .set_header("Quarter 4")
950    ///             .set_total_function(TableFunction::Sum),
951    ///         TableColumn::new()
952    ///             .set_header("Year")
953    ///             .set_total_function(TableFunction::Sum)
954    ///             .set_formula("SUM(Table1[@[Quarter 1]:[Quarter 4]])"),
955    ///     ];
956    ///
957    ///     let table = Table::new().set_columns(&columns).set_total_row(true);
958    ///
959    ///     // Add the table to the worksheet.
960    ///     worksheet.add_table(2, 1, 7, 6, &table)?;
961    /// #
962    /// #     // Save the file to disk.
963    /// #     workbook.save("tables.xlsx")?;
964    /// #
965    /// #     Ok(())
966    /// # }
967    /// ```
968    ///
969    /// Output file:
970    ///
971    /// <img
972    /// src="https://rustxlsxwriter.github.io/images/table_set_columns.png">
973    ///
974    pub fn set_columns(mut self, columns: &[TableColumn]) -> Table {
975        self.columns = columns.to_vec();
976        self
977    }
978
979    /// Set the name for a table.
980    ///
981    /// The name of a worksheet table in Excel is similar to a defined name
982    /// representing a data region, and it can be used in structured reference
983    /// formulas.
984    ///
985    /// By default, Excel and `rust_xlsxwriter` use a `Table1` .. `TableN`
986    /// naming convention for tables in a workbook. If required, you can set a
987    /// user-defined name. However, you need to ensure that this name is unique
988    /// across the workbook; otherwise, you will get a warning when you load the
989    /// file in Excel.
990    ///
991    /// # Parameters
992    ///
993    /// - `name`: The name of the table. It must be unique across the workbook.
994    ///
995    /// # Examples
996    ///
997    /// Example of setting the name of a worksheet table.
998    ///
999    /// ```
1000    /// # // This code is available in examples/doc_table_set_name.rs
1001    /// #
1002    /// # use rust_xlsxwriter::{Table, Workbook, XlsxError};
1003    /// #
1004    /// # fn main() -> Result<(), XlsxError> {
1005    /// #     // Create a new Excel file object.
1006    /// #     let mut workbook = Workbook::new();
1007    /// #
1008    /// #     // Add a worksheet to the workbook.
1009    /// #     let worksheet = workbook.add_worksheet();
1010    /// #
1011    /// #     // Some sample data for the table.
1012    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
1013    /// #     let data = [
1014    /// #         [10000, 5000, 8000, 6000],
1015    /// #         [2000, 3000, 4000, 5000],
1016    /// #         [6000, 6000, 6500, 6000],
1017    /// #         [500, 300, 200, 700],
1018    /// #     ];
1019    /// #
1020    /// #     // Write the table data.
1021    /// #     worksheet.write_column(3, 1, items)?;
1022    /// #     worksheet.write_row_matrix(3, 2, data)?;
1023    /// #
1024    /// #     // Set the column widths for clarity.
1025    /// #     worksheet.set_column_range_width(1, 6, 12)?;
1026    /// #
1027    ///     // Create a new table and set the name.
1028    ///     let table = Table::new().set_name("ProduceSales");
1029    ///
1030    ///     // Add the table to the worksheet.
1031    ///     worksheet.add_table(2, 1, 6, 5, &table)?;
1032    /// #
1033    /// #     // Save the file to disk.
1034    /// #     workbook.save("tables.xlsx")?;
1035    /// #
1036    /// #     Ok(())
1037    /// # }
1038    /// ```
1039    ///
1040    /// Output file:
1041    ///
1042    /// <img src="https://rustxlsxwriter.github.io/images/table_set_name.png">
1043    ///
1044    pub fn set_name(mut self, name: impl Into<String>) -> Table {
1045        self.name = name.into();
1046        self
1047    }
1048
1049    /// Set the style for a table.
1050    ///
1051    /// Excel supports 61 different styles for tables divided into Light, Medium,
1052    /// and Dark categories.
1053    ///
1054    /// <img src="https://rustxlsxwriter.github.io/images/table_styles.png">
1055    ///
1056    /// You can set one of these styles using a [`TableStyle`] enum value. The
1057    /// default table style in Excel is equivalent to [`TableStyle::Medium9`].
1058    ///
1059    /// # Parameters
1060    ///
1061    /// - `style`: a [`TableStyle`] enum value.
1062    ///
1063    /// # Examples
1064    ///
1065    /// Example of setting the style of a worksheet table.
1066    ///
1067    /// ```
1068    /// # // This code is available in examples/doc_table_set_style.rs
1069    /// #
1070    /// # use rust_xlsxwriter::{Table, TableStyle, Workbook, XlsxError};
1071    /// #
1072    /// # fn main() -> Result<(), XlsxError> {
1073    /// #     // Create a new Excel file object.
1074    /// #     let mut workbook = Workbook::new();
1075    /// #
1076    /// #     // Add a worksheet to the workbook.
1077    /// #     let worksheet = workbook.add_worksheet();
1078    /// #
1079    /// #     // Some sample data for the table.
1080    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
1081    /// #     let data = [
1082    /// #         [10000, 5000, 8000, 6000],
1083    /// #         [2000, 3000, 4000, 5000],
1084    /// #         [6000, 6000, 6500, 6000],
1085    /// #         [500, 300, 200, 700],
1086    /// #     ];
1087    /// #
1088    /// #     // Write the table data.
1089    /// #     worksheet.write_column(3, 1, items)?;
1090    /// #     worksheet.write_row_matrix(3, 2, data)?;
1091    /// #
1092    /// #     // Set the column widths for clarity.
1093    /// #     worksheet.set_column_range_width(1, 6, 12)?;
1094    /// #
1095    ///     // Create a new table and set the style.
1096    ///     let table = Table::new().set_style(TableStyle::Medium10);
1097    ///
1098    ///     // Add the table to the worksheet.
1099    ///     worksheet.add_table(2, 1, 6, 5, &table)?;
1100    /// #
1101    /// #     // Save the file to disk.
1102    /// #     workbook.save("tables.xlsx")?;
1103    /// #
1104    /// #     Ok(())
1105    /// # }
1106    /// ```
1107    ///
1108    /// Output file:
1109    ///
1110    /// <img src="https://rustxlsxwriter.github.io/images/table_set_style.png">
1111    ///
1112    pub fn set_style(mut self, style: TableStyle) -> Table {
1113        self.style = style;
1114        self
1115    }
1116
1117    /// Check if the table has a header row.
1118    ///
1119    /// This method is mainly used by polars_excel_writer and hidden from the
1120    /// general documentation.
1121    ///
1122    #[doc(hidden)]
1123    pub fn has_header_row(&self) -> bool {
1124        self.show_header_row
1125    }
1126
1127    /// Check if the table has a totals row.
1128    ///
1129    /// This method is mainly used by polars_excel_writer and hidden from the
1130    /// general documentation.
1131    ///
1132    #[doc(hidden)]
1133    pub fn has_total_row(&self) -> bool {
1134        self.show_total_row
1135    }
1136
1137    // Truncate or extend (with defaults) the table columns.
1138    pub(crate) fn initialize_columns(
1139        &mut self,
1140        default_headers: &[String],
1141    ) -> Result<(), XlsxError> {
1142        let mut seen_column_names = HashSet::new();
1143        let num_columns = self.cell_range.last_col - self.cell_range.first_col + 1;
1144
1145        self.columns
1146            .resize_with(num_columns as usize, TableColumn::default);
1147
1148        // Set the column header names,
1149        for (index, column) in self.columns.iter_mut().enumerate() {
1150            if column.name.is_empty() {
1151                column.name.clone_from(&default_headers[index]);
1152            }
1153
1154            if seen_column_names.contains(&column.name.to_lowercase()) {
1155                return Err(XlsxError::TableError(format!(
1156                    "Column name '{}' already exists in Table at {}",
1157                    column.name,
1158                    self.cell_range.to_error_string()
1159                )));
1160            }
1161
1162            seen_column_names.insert(column.name.to_lowercase().clone());
1163        }
1164
1165        Ok(())
1166    }
1167
1168    // Get the first row that can be used to write data.
1169    pub(crate) fn first_data_row(&self) -> RowNum {
1170        if self.show_header_row {
1171            self.cell_range.first_row + 1
1172        } else {
1173            self.cell_range.first_row
1174        }
1175    }
1176
1177    // Get the last row that can be used to write data.
1178    pub(crate) fn last_data_row(&self) -> RowNum {
1179        if self.show_total_row {
1180            self.cell_range.last_row - 1
1181        } else {
1182            self.cell_range.last_row
1183        }
1184    }
1185
1186    // -----------------------------------------------------------------------
1187    // XML assembly methods.
1188    // -----------------------------------------------------------------------
1189
1190    // Assemble and generate the XML file.
1191    pub(crate) fn assemble_xml_file(&mut self) {
1192        xml_declaration(&mut self.writer);
1193
1194        // Write the table element.
1195        self.write_table();
1196
1197        if self.show_autofilter && self.show_header_row {
1198            // Write the autoFilter element.
1199            self.write_auto_filter();
1200        }
1201
1202        // Write the tableColumns element.
1203        self.write_columns();
1204
1205        // Write the tableStyleInfo element.
1206        self.write_table_style_info();
1207
1208        // Close the table tag.
1209        xml_end_tag(&mut self.writer, "table");
1210    }
1211
1212    // Write the <table> element.
1213    fn write_table(&mut self) {
1214        let schema = "http://schemas.openxmlformats.org/spreadsheetml/2006/main".to_string();
1215        let range = self.cell_range.to_range_string();
1216        let name = if self.name.is_empty() {
1217            format!("Table{}", self.index)
1218        } else {
1219            self.name.clone()
1220        };
1221
1222        let mut attributes = vec![
1223            ("xmlns", schema),
1224            ("id", self.index.to_string()),
1225            ("name", name.clone()),
1226            ("displayName", name),
1227            ("ref", range),
1228        ];
1229
1230        if !self.show_header_row {
1231            attributes.push(("headerRowCount", "0".to_string()));
1232        }
1233
1234        if self.show_total_row {
1235            attributes.push(("totalsRowCount", "1".to_string()));
1236        } else {
1237            attributes.push(("totalsRowShown", "0".to_string()));
1238        }
1239
1240        xml_start_tag(&mut self.writer, "table", &attributes);
1241    }
1242
1243    // Write the <autoFilter> element.
1244    fn write_auto_filter(&mut self) {
1245        let mut autofilter_range = self.cell_range.clone();
1246
1247        if self.show_total_row {
1248            autofilter_range.last_row -= 1;
1249        }
1250
1251        let attributes = vec![("ref", autofilter_range.to_range_string())];
1252
1253        xml_empty_tag(&mut self.writer, "autoFilter", &attributes);
1254    }
1255
1256    // Write the <tableColumns> element.
1257    fn write_columns(&mut self) {
1258        let attributes = vec![("count", self.columns.len().to_string())];
1259
1260        xml_start_tag(&mut self.writer, "tableColumns", &attributes);
1261
1262        for (index, column) in self.columns.clone().iter().enumerate() {
1263            // Write the tableColumn element.
1264            self.write_column(index + 1, column);
1265        }
1266
1267        xml_end_tag(&mut self.writer, "tableColumns");
1268    }
1269
1270    // Write the <tableColumn> element.
1271    fn write_column(&mut self, index: usize, column: &TableColumn) {
1272        let mut attributes = vec![("id", index.to_string()), ("name", column.name.clone())];
1273
1274        if !column.total_label.is_empty() {
1275            attributes.push(("totalsRowLabel", column.total_label.clone()));
1276        } else if column.total_function != TableFunction::None {
1277            attributes.push(("totalsRowFunction", column.total_function.to_string()));
1278        }
1279
1280        if let Some(format) = &column.format {
1281            attributes.push(("dataDxfId", format.dxf_index.to_string()));
1282        }
1283
1284        if column.formula.is_some() || matches!(&column.total_function, TableFunction::Custom(_)) {
1285            xml_start_tag(&mut self.writer, "tableColumn", &attributes);
1286
1287            if let Some(formula) = &column.formula {
1288                // Write the calculatedColumnFormula element.
1289                self.write_calculated_column_formula(&formula.formula_string);
1290            }
1291
1292            if let TableFunction::Custom(formula) = &column.total_function {
1293                // Write the totalsRowFormula element.
1294                self.write_totals_row_formula(&formula.formula_string);
1295            }
1296
1297            xml_end_tag(&mut self.writer, "tableColumn");
1298        } else {
1299            xml_empty_tag(&mut self.writer, "tableColumn", &attributes);
1300        }
1301    }
1302
1303    // Write the <calculatedColumnFormula> element.
1304    fn write_calculated_column_formula(&mut self, formula: &str) {
1305        xml_data_element_only(&mut self.writer, "calculatedColumnFormula", formula);
1306    }
1307
1308    // Write the <totalsRowFormula> element.
1309    fn write_totals_row_formula(&mut self, formula: &str) {
1310        xml_data_element_only(&mut self.writer, "totalsRowFormula", formula);
1311    }
1312
1313    // Write the <tableStyleInfo> element.
1314    fn write_table_style_info(&mut self) {
1315        let mut attributes = vec![];
1316
1317        if self.style != TableStyle::None {
1318            attributes.push(("name", self.style.to_string()));
1319        }
1320
1321        attributes.push(("showFirstColumn", self.show_first_column.to_xml_bool()));
1322        attributes.push(("showLastColumn", self.show_last_column.to_xml_bool()));
1323        attributes.push(("showRowStripes", self.show_banded_rows.to_xml_bool()));
1324        attributes.push(("showColumnStripes", self.show_banded_columns.to_xml_bool()));
1325
1326        xml_empty_tag(&mut self.writer, "tableStyleInfo", &attributes);
1327    }
1328}
1329
1330#[derive(Clone)]
1331/// The `TableColumn` struct represents a table column.
1332///
1333/// The `TableColumn` struct is used to set the properties for columns in a
1334/// worksheet [`Table`]. This can be used to set the following properties of a
1335/// table column:
1336///
1337/// - The header caption.
1338/// - The total row caption.
1339/// - The total row subtotal function.
1340/// - A formula for the column.
1341///
1342/// This struct is used in conjunction with the [`Table::set_columns()`] method.
1343///
1344/// # Examples
1345///
1346/// Example of creating a worksheet table.
1347///
1348/// ```
1349/// # // This code is available in examples/doc_table_set_columns.rs
1350/// #
1351/// use rust_xlsxwriter::{Table, TableColumn, TableFunction, Workbook, XlsxError};
1352///
1353/// fn main() -> Result<(), XlsxError> {
1354///     // Create a new Excel file object.
1355///     let mut workbook = Workbook::new();
1356///
1357///     // Add a worksheet to the workbook.
1358///     let worksheet = workbook.add_worksheet();
1359///
1360///     // Some sample data for the table.
1361///     let items = ["Apples", "Pears", "Bananas", "Oranges"];
1362///     let data = [
1363///         [10000, 5000, 8000, 6000],
1364///         [2000, 3000, 4000, 5000],
1365///         [6000, 6000, 6500, 6000],
1366///         [500, 300, 200, 700],
1367///     ];
1368///
1369///     // Write the table data.
1370///     worksheet.write_column(3, 1, items)?;
1371///     worksheet.write_row_matrix(3, 2, data)?;
1372///
1373///     // Set the column widths for clarity.
1374///     worksheet.set_column_range_width(1, 6, 12)?;
1375///
1376///     // Create a new table and configure it.
1377///     let columns = vec![
1378///         TableColumn::new()
1379///             .set_header("Product")
1380///             .set_total_label("Totals"),
1381///         TableColumn::new()
1382///             .set_header("Quarter 1")
1383///             .set_total_function(TableFunction::Sum),
1384///         TableColumn::new()
1385///             .set_header("Quarter 2")
1386///             .set_total_function(TableFunction::Sum),
1387///         TableColumn::new()
1388///             .set_header("Quarter 3")
1389///             .set_total_function(TableFunction::Sum),
1390///         TableColumn::new()
1391///             .set_header("Quarter 4")
1392///             .set_total_function(TableFunction::Sum),
1393///         TableColumn::new()
1394///             .set_header("Year")
1395///             .set_total_function(TableFunction::Sum)
1396///             .set_formula("SUM(Table1[@[Quarter 1]:[Quarter 4]])"),
1397///     ];
1398///
1399///     let table = Table::new().set_columns(&columns).set_total_row(true);
1400///
1401///     // Add the table to the worksheet.
1402///     worksheet.add_table(2, 1, 7, 6, &table)?;
1403///
1404///     // Save the file to disk.
1405///     workbook.save("tables.xlsx")?;
1406///
1407///     Ok(())
1408/// }
1409/// ```
1410///
1411/// Output file:
1412///
1413/// <img src="https://rustxlsxwriter.github.io/images/table_set_columns.png">
1414///
1415///
1416pub struct TableColumn {
1417    pub(crate) name: String,
1418    pub(crate) total_function: TableFunction,
1419    pub(crate) total_label: String,
1420    pub(crate) formula: Option<Formula>,
1421    pub(crate) format: Option<Format>,
1422    pub(crate) header_format: Option<Format>,
1423}
1424
1425impl TableColumn {
1426    /// Create a new `TableColumn` to configure a Table column.
1427    ///
1428    pub fn new() -> TableColumn {
1429        TableColumn {
1430            name: String::new(),
1431            total_function: TableFunction::None,
1432            total_label: String::new(),
1433            formula: None,
1434            format: None,
1435            header_format: None,
1436        }
1437    }
1438
1439    /// Set the header caption for a table column.
1440    ///
1441    /// Excel uses default captions such as `Column 1`, `Column 2`, etc., for
1442    /// the headers on a worksheet table. These can be set to a user-defined
1443    /// value using the `set_header()` method.
1444    ///
1445    /// The column header names in a table must be different from each other.
1446    /// Non-unique names will raise a validation error when using
1447    /// [`Worksheet::add_table()`](crate::Worksheet::add_table).
1448    ///
1449    /// # Parameters
1450    ///
1451    /// - `caption`: The caption/name of the column header. It must be unique
1452    ///   for the table.
1453    ///
1454    /// # Examples
1455    ///
1456    /// Example of adding a worksheet table with a user defined header captions.
1457    ///
1458    /// ```
1459    /// # // This code is available in examples/doc_table_set_header_row3.rs
1460    /// #
1461    /// # use rust_xlsxwriter::{Table, TableColumn, Workbook, XlsxError};
1462    /// #
1463    /// # fn main() -> Result<(), XlsxError> {
1464    /// #     // Create a new Excel file object.
1465    /// #     let mut workbook = Workbook::new();
1466    /// #
1467    /// #     // Add a worksheet to the workbook.
1468    /// #     let worksheet = workbook.add_worksheet();
1469    /// #
1470    /// #     // Some sample data for the table.
1471    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
1472    /// #     let data = [
1473    /// #         [10000, 5000, 8000, 6000],
1474    /// #         [2000, 3000, 4000, 5000],
1475    /// #         [6000, 6000, 6500, 6000],
1476    /// #         [500, 300, 200, 700],
1477    /// #     ];
1478    /// #
1479    /// #     // Write the table data.
1480    /// #     worksheet.write_column(3, 1, items)?;
1481    /// #     worksheet.write_row_matrix(3, 2, data)?;
1482    /// #
1483    /// #     // Set the column widths for clarity.
1484    /// #     worksheet.set_column_range_width(1, 6, 12)?;
1485    /// #
1486    ///     // Set the captions for the header row.
1487    ///     let columns = vec![
1488    ///         TableColumn::new().set_header("Product"),
1489    ///         TableColumn::new().set_header("Quarter 1"),
1490    ///         TableColumn::new().set_header("Quarter 2"),
1491    ///         TableColumn::new().set_header("Quarter 3"),
1492    ///         TableColumn::new().set_header("Quarter 4"),
1493    ///     ];
1494    ///
1495    ///     // Create a new table and configure the column headers.
1496    ///     let table = Table::new().set_columns(&columns);
1497    ///
1498    ///     // Add the table to the worksheet.
1499    ///     worksheet.add_table(2, 1, 6, 5, &table)?;
1500    /// #
1501    /// #     // Save the file to disk.
1502    /// #     workbook.save("tables.xlsx")?;
1503    /// #
1504    /// #     Ok(())
1505    /// # }
1506    /// ```
1507    ///
1508    /// Output file:
1509    ///
1510    /// <img
1511    /// src="https://rustxlsxwriter.github.io/images/table_set_header_row3.png">
1512    ///
1513    pub fn set_header(mut self, caption: impl Into<String>) -> TableColumn {
1514        self.name = caption.into();
1515        self
1516    }
1517
1518    /// Set the total function for the total row of a table column.
1519    ///
1520    /// Set the `SUBTOTAL()` function for the "totals" row of a table column.
1521    ///
1522    /// The standard Excel subtotal functions are available via the
1523    /// [`TableFunction`] enum values. The Excel functions are:
1524    ///
1525    /// - Average
1526    /// - Count
1527    /// - Count Numbers
1528    /// - Maximum
1529    /// - Minimum
1530    /// - Sum
1531    /// - Standard Deviation
1532    /// - Variance
1533    /// - Custom - User-defined function or formula
1534    ///
1535    /// Note, overwriting the total row cells with `worksheet.write()` calls
1536    /// will cause Excel to warn that the table is corrupt when loading the
1537    /// file.
1538    ///
1539    /// # Parameters
1540    ///
1541    /// - `function`: A [`TableFunction`] enum value equivalent to one of the
1542    ///   available Excel `SUBTOTAL()` options.
1543    ///
1544    /// # Examples
1545    ///
1546    /// Example of turning on the "totals" row at the bottom of a worksheet
1547    /// table with captions and subtotal functions.
1548    ///
1549    /// ```
1550    /// # // This code is available in examples/doc_table_set_total_row2.rs
1551    /// #
1552    /// # use rust_xlsxwriter::{Formula, Table, TableColumn, TableFunction, Workbook, XlsxError};
1553    /// #
1554    /// # fn main() -> Result<(), XlsxError> {
1555    /// #     // Create a new Excel file object.
1556    /// #     let mut workbook = Workbook::new();
1557    /// #
1558    /// #     // Add a worksheet to the workbook.
1559    /// #     let worksheet = workbook.add_worksheet();
1560    /// #
1561    /// #     // Some sample data for the table.
1562    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
1563    /// #     let data = [
1564    /// #         [10000, 5000, 8000, 6000],
1565    /// #         [2000, 3000, 4000, 5000],
1566    /// #         [6000, 6000, 6500, 6000],
1567    /// #         [500, 300, 200, 700],
1568    /// #     ];
1569    /// #
1570    /// #     // Write the table data.
1571    /// #     worksheet.write_column(3, 1, items)?;
1572    /// #     worksheet.write_row_matrix(3, 2, data)?;
1573    /// #
1574    /// #     // Set the column widths for clarity.
1575    /// #     worksheet.set_column_range_width(1, 6, 12)?;
1576    /// #
1577    ///     // Set the caption and subtotal in the total row.
1578    ///     let columns = vec![
1579    ///         TableColumn::new().set_total_label("Totals"),
1580    ///         TableColumn::new().set_total_function(TableFunction::Sum),
1581    ///         TableColumn::new().set_total_function(TableFunction::Sum),
1582    ///         TableColumn::new().set_total_function(TableFunction::Sum),
1583    ///         // Use a custom formula to get a similar summation.
1584    ///         TableColumn::new()
1585    ///             .set_total_function(TableFunction::Custom(Formula::new("SUM([Column5])"))),
1586    ///     ];
1587    ///
1588    ///     // Create a new table and configure the total row.
1589    ///     let table = Table::new().set_total_row(true).set_columns(&columns);
1590    ///
1591    ///     // Add the table to the worksheet.
1592    ///     worksheet.add_table(2, 1, 7, 5, &table)?;
1593    /// #
1594    /// #     // Save the file to disk.
1595    /// #     workbook.save("tables.xlsx")?;
1596    /// #
1597    /// #     Ok(())
1598    /// # }
1599    /// ```
1600    ///
1601    /// Output file:
1602    ///
1603    /// <img
1604    /// src="https://rustxlsxwriter.github.io/images/table_set_total_row2.png">
1605    ///
1606    pub fn set_total_function(mut self, function: TableFunction) -> TableColumn {
1607        self.total_function = function;
1608        self
1609    }
1610
1611    /// Set a label for the total row of a table column.
1612    ///
1613    /// It is possible to set a label for the totals row of a column instead of
1614    /// a subtotal function. This is most often used to set a caption like
1615    /// "Totals," as in the example above.
1616    ///
1617    /// Note, overwriting the total row cells with `worksheet.write()` calls
1618    /// will cause Excel to warn that the table is corrupt when loading the
1619    /// file.
1620    ///
1621    /// # Parameters
1622    ///
1623    /// - `label`: The label/caption of the total row of the column.
1624    ///
1625    pub fn set_total_label(mut self, label: impl Into<String>) -> TableColumn {
1626        self.total_label = label.into();
1627        self
1628    }
1629
1630    /// Set the formula for a table column.
1631    ///
1632    /// It is a common use case to add a summation column as the last column in a
1633    /// table. These are constructed with a special class of Excel formulas
1634    /// called [Structured References], which can refer to an entire table or
1635    /// rows or columns of data within the table. For example, to sum the data
1636    /// for several columns in a single row, you might use a formula like
1637    /// this: `SUM(Table1[@[Quarter 1]:[Quarter 4]])`.
1638    ///
1639    /// [Structured References]:
1640    ///     https://support.microsoft.com/en-us/office/using-structured-references-with-excel-tables-f5ed2452-2337-4f71-bed3-c8ae6d2b276e
1641    ///
1642    /// # Parameters
1643    ///
1644    /// - `formula`: The formula to be applied to the column as a string or
1645    ///   [`Formula`].
1646    ///
1647    /// # Examples
1648    ///
1649    /// Example of adding a formula to a column in a worksheet table.
1650    ///
1651    /// ```
1652    /// # // This code is available in examples/doc_tablecolumn_set_formula.rs
1653    /// #
1654    /// # use rust_xlsxwriter::{Table, TableColumn, Workbook, XlsxError};
1655    /// #
1656    /// # fn main() -> Result<(), XlsxError> {
1657    /// #     // Create a new Excel file object.
1658    /// #     let mut workbook = Workbook::new();
1659    /// #
1660    /// #     // Add a worksheet to the workbook.
1661    /// #     let worksheet = workbook.add_worksheet();
1662    /// #
1663    /// #     // Some sample data for the table.
1664    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
1665    /// #     let data = [
1666    /// #         [10000, 5000, 8000, 6000],
1667    /// #         [2000, 3000, 4000, 5000],
1668    /// #         [6000, 6000, 6500, 6000],
1669    /// #         [500, 300, 200, 700],
1670    /// #     ];
1671    /// #
1672    /// #     // Write the table data.
1673    /// #     worksheet.write_column(3, 1, items)?;
1674    /// #     worksheet.write_row_matrix(3, 2, data)?;
1675    /// #
1676    /// #     // Set the column widths for clarity.
1677    /// #     worksheet.set_column_range_width(1, 6, 12)?;
1678    /// #
1679    ///     // Add a structured reference formula to the last column and set the header
1680    ///     // caption.
1681    ///     let columns = vec![
1682    ///         TableColumn::new().set_header("Product"),
1683    ///         TableColumn::new().set_header("Quarter 1"),
1684    ///         TableColumn::new().set_header("Quarter 2"),
1685    ///         TableColumn::new().set_header("Quarter 3"),
1686    ///         TableColumn::new().set_header("Quarter 4"),
1687    ///         TableColumn::new()
1688    ///             .set_header("Totals")
1689    ///             .set_formula("SUM(Table1[@[Quarter 1]:[Quarter 4]])"),
1690    ///     ];
1691    ///
1692    ///     // Create a new table and configure the columns.
1693    ///     let table = Table::new().set_columns(&columns);
1694    ///
1695    ///     // Add the table to the worksheet.
1696    ///     worksheet.add_table(2, 1, 6, 6, &table)?;
1697    /// #
1698    /// #     // Save the file to disk.
1699    /// #     workbook.save("tables.xlsx")?;
1700    /// #
1701    /// #     Ok(())
1702    /// # }
1703    /// ```
1704    ///
1705    /// Output file:
1706    ///
1707    /// <img
1708    /// src="https://rustxlsxwriter.github.io/images/tablecolumn_set_formula.png">
1709    ///
1710    pub fn set_formula(mut self, formula: impl Into<Formula>) -> TableColumn {
1711        let mut formula = formula.into();
1712        formula = formula.clone().escape_table_functions();
1713        self.formula = Some(formula);
1714        self
1715    }
1716
1717    /// Set the format for a table column.
1718    ///
1719    /// It is sometimes required to format the data in the columns of a table.
1720    /// This can be done using the standard
1721    /// [`Worksheet::write_with_format()`](crate::Worksheet::write_with_format) method,
1722    /// but the format can also be applied separately using
1723    /// `TableColumn.set_format()`.
1724    ///
1725    /// The most common format property to set for a table column is the [number
1726    /// format](Format::set_num_format), see the example below.
1727    ///
1728    /// # Parameters
1729    ///
1730    /// - `format`: The [`Format`] property for the data cells in the column.
1731    ///
1732    /// # Examples
1733    ///
1734    /// Example of adding a format to a column in a worksheet table.
1735    ///
1736    /// ```
1737    /// # // This code is available in examples/doc_tablecolumn_set_format.rs
1738    /// #
1739    /// # use rust_xlsxwriter::{Format, Table, TableColumn, Workbook, XlsxError};
1740    /// #
1741    /// # fn main() -> Result<(), XlsxError> {
1742    /// #     // Create a new Excel file object.
1743    /// #     let mut workbook = Workbook::new();
1744    /// #
1745    /// #     // Add a worksheet to the workbook.
1746    /// #     let worksheet = workbook.add_worksheet();
1747    /// #
1748    /// #     // Some sample data for the table.
1749    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
1750    /// #     let data = [
1751    /// #         [10000, 5000, 8000, 6000],
1752    /// #         [2000, 3000, 4000, 5000],
1753    /// #         [6000, 6000, 6500, 6000],
1754    /// #         [500, 300, 200, 700],
1755    /// #     ];
1756    /// #
1757    /// #     // Write the table data.
1758    /// #     worksheet.write_column(3, 1, items)?;
1759    /// #     worksheet.write_row_matrix(3, 2, data)?;
1760    /// #
1761    /// #     // Set the column widths for clarity.
1762    /// #     worksheet.set_column_range_width(1, 6, 12)?;
1763    /// #
1764    ///     // Create a number format for number columns in the table.
1765    ///     let format = Format::new().set_num_format("$#,##0.00");
1766    ///
1767    ///     // Add a format to the number/currency columns.
1768    ///     let columns = vec![
1769    ///         TableColumn::new().set_header("Product"),
1770    ///         TableColumn::new().set_header("Q1").set_format(&format),
1771    ///         TableColumn::new().set_header("Q2").set_format(&format),
1772    ///         TableColumn::new().set_header("Q3").set_format(&format),
1773    ///         TableColumn::new().set_header("Q4").set_format(&format),
1774    ///     ];
1775    ///
1776    ///     // Create a new table and configure the columns.
1777    ///     let table = Table::new().set_columns(&columns);
1778    ///
1779    ///     // Add the table to the worksheet.
1780    ///     worksheet.add_table(2, 1, 6, 5, &table)?;
1781    /// #
1782    /// #     // Save the file to disk.
1783    /// #     workbook.save("tables.xlsx")?;
1784    /// #
1785    /// #     Ok(())
1786    /// # }
1787    /// ```
1788    ///
1789    /// Output file:
1790    ///
1791    /// <img src="https://rustxlsxwriter.github.io/images/tablecolumn_set_format.png">
1792    ///
1793    pub fn set_format(mut self, format: impl Into<Format>) -> TableColumn {
1794        self.format = Some(format.into());
1795        self
1796    }
1797
1798    /// Set the format for the header of the table column.
1799    ///
1800    /// The `set_header_format` method can be used to set the format for the
1801    /// column header in a worksheet table.
1802    ///
1803    /// # Parameters
1804    ///
1805    /// - `format`: The [`Format`] property for the column header.
1806    ///
1807    /// # Examples
1808    ///
1809    /// Example of adding a header format to a column in a worksheet table.
1810    ///
1811    /// ```
1812    /// # // This code is available in examples/doc_tablecolumn_set_header_format.rs
1813    /// #
1814    /// # use rust_xlsxwriter::{Format, Table, TableColumn, Workbook, XlsxError};
1815    /// #
1816    /// # fn main() -> Result<(), XlsxError> {
1817    /// #     // Create a new Excel file object.
1818    /// #     let mut workbook = Workbook::new();
1819    /// #
1820    /// #     // Add a worksheet to the workbook.
1821    /// #     let worksheet = workbook.add_worksheet();
1822    /// #
1823    /// #     // Some sample data for the table.
1824    /// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
1825    /// #     let data = [
1826    /// #         [10000, 5000, 8000, 6000],
1827    /// #         [2000, 3000, 4000, 5000],
1828    /// #         [6000, 6000, 6500, 6000],
1829    /// #         [500, 300, 200, 700],
1830    /// #     ];
1831    /// #
1832    /// #     // Write the table data.
1833    /// #     worksheet.write_column(3, 1, items)?;
1834    /// #     worksheet.write_row_matrix(3, 2, data)?;
1835    /// #
1836    /// #     // Set the column widths for clarity.
1837    /// #     worksheet.set_column_range_width(1, 6, 12)?;
1838    /// #
1839    /// #     // Create formats for the columns headers.
1840    ///     let format1 = Format::new().set_font_color("#FF0000");
1841    ///     let format2 = Format::new().set_font_color("#00FF00");
1842    ///     let format3 = Format::new().set_font_color("#0000FF");
1843    ///     let format4 = Format::new().set_font_color("#FFFF00");
1844    ///
1845    ///     // Add a format to the columns headers.
1846    ///     let columns = vec![
1847    ///         TableColumn::new().set_header("Product"),
1848    ///         TableColumn::new()
1849    ///             .set_header("Quarter 1")
1850    ///             .set_header_format(format1),
1851    ///         TableColumn::new()
1852    ///             .set_header("Quarter 2")
1853    ///             .set_header_format(format2),
1854    ///         TableColumn::new()
1855    ///             .set_header("Quarter 3")
1856    ///             .set_header_format(format3),
1857    ///         TableColumn::new()
1858    ///             .set_header("Quarter 4")
1859    ///             .set_header_format(format4),
1860    ///     ];
1861    ///
1862    ///     // Create a new table and configure the columns.
1863    ///     let table = Table::new().set_columns(&columns);
1864    ///
1865    ///     // Add the table to the worksheet.
1866    ///     worksheet.add_table(2, 1, 6, 5, &table)?;
1867    /// #
1868    /// #     // Save the file to disk.
1869    /// #     workbook.save("tables.xlsx")?;
1870    /// #
1871    /// #     Ok(())
1872    /// # }
1873    /// ```
1874    ///
1875    /// Output file:
1876    ///
1877    /// <img src="https://rustxlsxwriter.github.io/images/tablecolumn_set_header_format.png">
1878    ///
1879    pub fn set_header_format(mut self, format: impl Into<Format>) -> TableColumn {
1880        self.header_format = Some(format.into());
1881        self
1882    }
1883
1884    // Convert the SUBTOTAL type to a worksheet formula.
1885    pub(crate) fn total_function(&self) -> Formula {
1886        let column_name = self
1887            .name
1888            .replace('\'', "''")
1889            .replace('#', "'#")
1890            .replace(']', "']")
1891            .replace('[', "'[");
1892
1893        match &self.total_function {
1894            TableFunction::None => Formula::new(""),
1895            TableFunction::Max => Formula::new(format!("SUBTOTAL(104,[{column_name}])")),
1896            TableFunction::Min => Formula::new(format!("SUBTOTAL(105,[{column_name}])")),
1897            TableFunction::Sum => Formula::new(format!("SUBTOTAL(109,[{column_name}])")),
1898            TableFunction::Var => Formula::new(format!("SUBTOTAL(110,[{column_name}])")),
1899            TableFunction::Count => Formula::new(format!("SUBTOTAL(103,[{column_name}])")),
1900            TableFunction::StdDev => Formula::new(format!("SUBTOTAL(107,[{column_name}])")),
1901            TableFunction::Average => Formula::new(format!("SUBTOTAL(101,[{column_name}])")),
1902            TableFunction::CountNumbers => Formula::new(format!("SUBTOTAL(102,[{column_name}])")),
1903            TableFunction::Custom(formula) => formula.clone(),
1904        }
1905    }
1906}
1907
1908impl Default for TableColumn {
1909    fn default() -> Self {
1910        Self::new()
1911    }
1912}
1913
1914/// The `TableFunction` enum defines functions for worksheet table total rows.
1915///
1916/// The `TableFunction` enum contains definitions for the standard Excel
1917/// "SUBTOTAL" functions that are available via the dropdown in the total row of
1918/// an Excel table. It also supports custom user defined functions or formulas.
1919///
1920/// # Examples
1921///
1922/// Example of turning on the totals row at the bottom of a worksheet table with
1923/// subtotal functions.
1924///
1925/// ```
1926/// # // This code is available in examples/doc_table_set_total_row2.rs
1927/// #
1928/// # use rust_xlsxwriter::{Formula, Table, TableColumn, TableFunction, Workbook, XlsxError};
1929/// #
1930/// # fn main() -> Result<(), XlsxError> {
1931/// #     // Create a new Excel file object.
1932/// #     let mut workbook = Workbook::new();
1933/// #
1934/// #     // Add a worksheet to the workbook.
1935/// #     let worksheet = workbook.add_worksheet();
1936/// #
1937/// #     // Some sample data for the table.
1938/// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
1939/// #     let data = [
1940/// #         [10000, 5000, 8000, 6000],
1941/// #         [2000, 3000, 4000, 5000],
1942/// #         [6000, 6000, 6500, 6000],
1943/// #         [500, 300, 200, 700],
1944/// #     ];
1945/// #
1946/// #     // Write the table data.
1947/// #     worksheet.write_column(3, 1, items)?;
1948/// #     worksheet.write_row_matrix(3, 2, data)?;
1949/// #
1950/// #     // Set the column widths for clarity.
1951/// #     worksheet.set_column_range_width(1, 6, 12)?;
1952/// #
1953///     // Set the caption and subtotal in the total row.
1954///     let columns = vec![
1955///         TableColumn::new().set_total_label("Totals"),
1956///         TableColumn::new().set_total_function(TableFunction::Sum),
1957///         TableColumn::new().set_total_function(TableFunction::Sum),
1958///         TableColumn::new().set_total_function(TableFunction::Sum),
1959///         // Use a custom formula to get a similar summation.
1960///         TableColumn::new()
1961///             .set_total_function(TableFunction::Custom(Formula::new("SUM([Column5])"))),
1962///     ];
1963///
1964///     // Create a new table and configure the total row.
1965///     let table = Table::new().set_total_row(true).set_columns(&columns);
1966///
1967///     // Add the table to the worksheet.
1968///     worksheet.add_table(2, 1, 7, 5, &table)?;
1969///
1970/// #     // Save the file to disk.
1971/// #     workbook.save("tables.xlsx")?;
1972/// #
1973/// #     Ok(())
1974/// # }
1975/// ```
1976///
1977/// Output file:
1978///
1979/// <img src="https://rustxlsxwriter.github.io/images/table_set_total_row2.png">
1980///
1981#[derive(Clone, PartialEq)]
1982pub enum TableFunction {
1983    /// The "total row" option is enable but there is no total function.
1984    None,
1985
1986    /// Use the average function as the table total.
1987    Average,
1988
1989    /// Use the count function as the table total.
1990    Count,
1991
1992    /// Use the count numbers function as the table total.
1993    CountNumbers,
1994
1995    /// Use the max function as the table total.
1996    Max,
1997
1998    /// Use the min function as the table total.
1999    Min,
2000
2001    /// Use the sum function as the table total.
2002    Sum,
2003
2004    /// Use the standard deviation function as the table total.
2005    StdDev,
2006
2007    /// Use the var function as the table total.
2008    Var,
2009
2010    /// Use a custom/user specified function or formula.
2011    Custom(Formula),
2012}
2013
2014impl fmt::Display for TableFunction {
2015    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2016        match self {
2017            Self::Max => write!(f, "max"),
2018            Self::Min => write!(f, "min"),
2019            Self::Sum => write!(f, "sum"),
2020            Self::Var => write!(f, "var"),
2021            Self::None => write!(f, "None"),
2022            Self::Count => write!(f, "count"),
2023            Self::StdDev => write!(f, "stdDev"),
2024            Self::Average => write!(f, "average"),
2025            Self::CountNumbers => write!(f, "countNums"),
2026            Self::Custom(_) => write!(f, "custom"),
2027        }
2028    }
2029}
2030
2031/// The `TableStyle` enum defines the worksheet table styles.
2032///
2033/// Excel supports 61 different styles for tables divided into Light, Medium and
2034/// Dark categories. You can set one of these styles using a `TableStyle` enum
2035/// value.
2036///
2037/// <img src="https://rustxlsxwriter.github.io/images/table_styles.png">
2038///
2039/// The style is set via the [`Table::set_style()`] method. The default table
2040/// style in Excel is equivalent to [`TableStyle::Medium9`].
2041///
2042/// # Examples
2043///
2044/// Example of setting the style of a worksheet table.
2045///
2046/// ```
2047/// # // This code is available in examples/doc_table_set_style.rs
2048/// #
2049/// # use rust_xlsxwriter::{Table, TableStyle, Workbook, XlsxError};
2050/// #
2051/// # fn main() -> Result<(), XlsxError> {
2052/// #     // Create a new Excel file object.
2053/// #     let mut workbook = Workbook::new();
2054/// #
2055/// #     // Add a worksheet to the workbook.
2056/// #     let worksheet = workbook.add_worksheet();
2057/// #
2058/// #     // Some sample data for the table.
2059/// #     let items = ["Apples", "Pears", "Bananas", "Oranges"];
2060/// #     let data = [
2061/// #         [10000, 5000, 8000, 6000],
2062/// #         [2000, 3000, 4000, 5000],
2063/// #         [6000, 6000, 6500, 6000],
2064/// #         [500, 300, 200, 700],
2065/// #     ];
2066/// #
2067/// #     // Write the table data.
2068/// #     worksheet.write_column(3, 1, items)?;
2069/// #     worksheet.write_row_matrix(3, 2, data)?;
2070/// #
2071/// #     // Set the column widths for clarity.
2072/// #     worksheet.set_column_range_width(1, 6, 12)?;
2073/// #
2074///     // Create a new table and set the style.
2075///     let table = Table::new().set_style(TableStyle::Medium10);
2076///
2077///     // Add the table to the worksheet.
2078///     worksheet.add_table(2, 1, 6, 5, &table)?;
2079///
2080/// #     // Save the file to disk.
2081/// #     workbook.save("tables.xlsx")?;
2082/// #
2083/// #     Ok(())
2084/// # }
2085/// ```
2086///
2087/// Output file:
2088///
2089/// <img src="https://rustxlsxwriter.github.io/images/table_set_style.png">
2090///
2091#[derive(Clone, Copy, PartialEq, Eq)]
2092pub enum TableStyle {
2093    /// No table style.
2094    None,
2095
2096    /// Table Style Light 1, White.
2097    Light1,
2098
2099    /// Table Style Light 2, Light Blue.
2100    Light2,
2101
2102    /// Table Style Light 3, Light Orange.
2103    Light3,
2104
2105    /// Table Style Light 4, White.
2106    Light4,
2107
2108    /// Table Style Light 5, Light Yellow.
2109    Light5,
2110
2111    /// Table Style Light 6, Light Blue.
2112    Light6,
2113
2114    /// Table Style Light 7, Light Green.
2115    Light7,
2116
2117    /// Table Style Light 8, White.
2118    Light8,
2119
2120    /// Table Style Light 9, Blue.
2121    Light9,
2122
2123    /// Table Style Light 10, Orange.
2124    Light10,
2125
2126    /// Table Style Light 11, White.
2127    Light11,
2128
2129    /// Table Style Light 12, Gold.
2130    Light12,
2131
2132    /// Table Style Light 13, Blue.
2133    Light13,
2134
2135    /// Table Style Light 14, Green.
2136    Light14,
2137
2138    /// Table Style Light 15, White.
2139    Light15,
2140
2141    /// Table Style Light 16, Light Blue.
2142    Light16,
2143
2144    /// Table Style Light 17, Light Orange.
2145    Light17,
2146
2147    /// Table Style Light 18, White.
2148    Light18,
2149
2150    /// Table Style Light 19, Light Yellow.
2151    Light19,
2152
2153    /// Table Style Light 20, Light Blue.
2154    Light20,
2155
2156    /// Table Style Light 21, Light Green.
2157    Light21,
2158
2159    /// Table Style Medium 1, White.
2160    Medium1,
2161
2162    /// Table Style Medium 2, Blue.
2163    Medium2,
2164
2165    /// Table Style Medium 3, Orange.
2166    Medium3,
2167
2168    /// Table Style Medium 4, White.
2169    Medium4,
2170
2171    /// Table Style Medium 5, Gold.
2172    Medium5,
2173
2174    /// Table Style Medium 6, Blue.
2175    Medium6,
2176
2177    /// Table Style Medium 7, Green.
2178    Medium7,
2179
2180    /// Table Style Medium 8, Light Grey.
2181    Medium8,
2182
2183    /// Table Style Medium 9, Blue.
2184    Medium9,
2185
2186    /// Table Style Medium 10, Orange.
2187    Medium10,
2188
2189    /// Table Style Medium 11, Light Grey.
2190    Medium11,
2191
2192    /// Table Style Medium 12, Gold.
2193    Medium12,
2194
2195    /// Table Style Medium 13, Blue.
2196    Medium13,
2197
2198    /// Table Style Medium 14, Green.
2199    Medium14,
2200
2201    /// Table Style Medium 15, White.
2202    Medium15,
2203
2204    /// Table Style Medium 16, Blue.
2205    Medium16,
2206
2207    /// Table Style Medium 17, Orange.
2208    Medium17,
2209
2210    /// Table Style Medium 18, White.
2211    Medium18,
2212
2213    /// Table Style Medium 19, Gold.
2214    Medium19,
2215
2216    /// Table Style Medium 20, Blue.
2217    Medium20,
2218
2219    /// Table Style Medium 21, Green.
2220    Medium21,
2221
2222    /// Table Style Medium 22, Light Grey.
2223    Medium22,
2224
2225    /// Table Style Medium 23, Light Blue.
2226    Medium23,
2227
2228    /// Table Style Medium 24, Light Orange.
2229    Medium24,
2230
2231    /// Table Style Medium 25, Light Grey.
2232    Medium25,
2233
2234    /// Table Style Medium 26, Light Yellow.
2235    Medium26,
2236
2237    /// Table Style Medium 27, Light Blue.
2238    Medium27,
2239
2240    /// Table Style Medium 28, Light Green.
2241    Medium28,
2242
2243    /// Table Style Dark 1, Dark Grey.
2244    Dark1,
2245
2246    /// Table Style Dark 2, Dark Blue.
2247    Dark2,
2248
2249    /// Table Style Dark 3, Brown.
2250    Dark3,
2251
2252    /// Table Style Dark 4, Grey.
2253    Dark4,
2254
2255    /// Table Style Dark 5, Dark Yellow.
2256    Dark5,
2257
2258    /// Table Style Dark 6, Blue.
2259    Dark6,
2260
2261    /// Table Style Dark 7, Dark Green.
2262    Dark7,
2263
2264    /// Table Style Dark 8, Light Grey.
2265    Dark8,
2266
2267    /// Table Style Dark 9, Light Orange.
2268    Dark9,
2269
2270    /// Table Style Dark 10, Gold.
2271    Dark10,
2272
2273    /// Table Style Dark 11, Green.
2274    Dark11,
2275}
2276
2277impl fmt::Display for TableStyle {
2278    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2279        match self {
2280            Self::None => write!(f, "TableStyleNone"),
2281            Self::Light1 => write!(f, "TableStyleLight1"),
2282            Self::Light2 => write!(f, "TableStyleLight2"),
2283            Self::Light3 => write!(f, "TableStyleLight3"),
2284            Self::Light4 => write!(f, "TableStyleLight4"),
2285            Self::Light5 => write!(f, "TableStyleLight5"),
2286            Self::Light6 => write!(f, "TableStyleLight6"),
2287            Self::Light7 => write!(f, "TableStyleLight7"),
2288            Self::Light8 => write!(f, "TableStyleLight8"),
2289            Self::Light9 => write!(f, "TableStyleLight9"),
2290            Self::Light10 => write!(f, "TableStyleLight10"),
2291            Self::Light11 => write!(f, "TableStyleLight11"),
2292            Self::Light12 => write!(f, "TableStyleLight12"),
2293            Self::Light13 => write!(f, "TableStyleLight13"),
2294            Self::Light14 => write!(f, "TableStyleLight14"),
2295            Self::Light15 => write!(f, "TableStyleLight15"),
2296            Self::Light16 => write!(f, "TableStyleLight16"),
2297            Self::Light17 => write!(f, "TableStyleLight17"),
2298            Self::Light18 => write!(f, "TableStyleLight18"),
2299            Self::Light19 => write!(f, "TableStyleLight19"),
2300            Self::Light20 => write!(f, "TableStyleLight20"),
2301            Self::Light21 => write!(f, "TableStyleLight21"),
2302            Self::Medium1 => write!(f, "TableStyleMedium1"),
2303            Self::Medium2 => write!(f, "TableStyleMedium2"),
2304            Self::Medium3 => write!(f, "TableStyleMedium3"),
2305            Self::Medium4 => write!(f, "TableStyleMedium4"),
2306            Self::Medium5 => write!(f, "TableStyleMedium5"),
2307            Self::Medium6 => write!(f, "TableStyleMedium6"),
2308            Self::Medium7 => write!(f, "TableStyleMedium7"),
2309            Self::Medium8 => write!(f, "TableStyleMedium8"),
2310            Self::Medium9 => write!(f, "TableStyleMedium9"),
2311            Self::Medium10 => write!(f, "TableStyleMedium10"),
2312            Self::Medium11 => write!(f, "TableStyleMedium11"),
2313            Self::Medium12 => write!(f, "TableStyleMedium12"),
2314            Self::Medium13 => write!(f, "TableStyleMedium13"),
2315            Self::Medium14 => write!(f, "TableStyleMedium14"),
2316            Self::Medium15 => write!(f, "TableStyleMedium15"),
2317            Self::Medium16 => write!(f, "TableStyleMedium16"),
2318            Self::Medium17 => write!(f, "TableStyleMedium17"),
2319            Self::Medium18 => write!(f, "TableStyleMedium18"),
2320            Self::Medium19 => write!(f, "TableStyleMedium19"),
2321            Self::Medium20 => write!(f, "TableStyleMedium20"),
2322            Self::Medium21 => write!(f, "TableStyleMedium21"),
2323            Self::Medium22 => write!(f, "TableStyleMedium22"),
2324            Self::Medium23 => write!(f, "TableStyleMedium23"),
2325            Self::Medium24 => write!(f, "TableStyleMedium24"),
2326            Self::Medium25 => write!(f, "TableStyleMedium25"),
2327            Self::Medium26 => write!(f, "TableStyleMedium26"),
2328            Self::Medium27 => write!(f, "TableStyleMedium27"),
2329            Self::Medium28 => write!(f, "TableStyleMedium28"),
2330            Self::Dark1 => write!(f, "TableStyleDark1"),
2331            Self::Dark2 => write!(f, "TableStyleDark2"),
2332            Self::Dark3 => write!(f, "TableStyleDark3"),
2333            Self::Dark4 => write!(f, "TableStyleDark4"),
2334            Self::Dark5 => write!(f, "TableStyleDark5"),
2335            Self::Dark6 => write!(f, "TableStyleDark6"),
2336            Self::Dark7 => write!(f, "TableStyleDark7"),
2337            Self::Dark8 => write!(f, "TableStyleDark8"),
2338            Self::Dark9 => write!(f, "TableStyleDark9"),
2339            Self::Dark10 => write!(f, "TableStyleDark10"),
2340            Self::Dark11 => write!(f, "TableStyleDark11"),
2341        }
2342    }
2343}
2344
2345/// Convert a [`Table`] ref to a [`Table`] object.
2346///
2347/// This is used as a syntactic shortcut for serialize APIs to allow either
2348/// `&Table` or `Table`.
2349///
2350impl From<&Table> for Table {
2351    fn from(value: &Table) -> Table {
2352        (*value).clone()
2353    }
2354}