From f8cb0c59fab4e243b205b1e6be72ee23a4482297 Mon Sep 17 00:00:00 2001 From: John McNamara Date: Fri, 12 Jul 2024 00:41:08 +0100 Subject: [PATCH] data validation: add documentation Feature #97 --- examples/app_data_validation.rs | 231 ++++ examples/doc_data_validation_allow_custom.rs | 26 + examples/doc_data_validation_allow_date.rs | 28 + ...oc_data_validation_allow_decimal_number.rs | 26 + ...validation_allow_decimal_number_formula.rs | 28 + .../doc_data_validation_allow_list_formula.rs | 30 + .../doc_data_validation_allow_list_strings.rs | 26 + ...doc_data_validation_allow_list_strings2.rs | 31 + .../doc_data_validation_allow_text_length.rs | 26 + examples/doc_data_validation_allow_time.rs | 28 + .../doc_data_validation_allow_whole_number.rs | 26 + ...a_validation_allow_whole_number_formula.rs | 28 + ..._validation_allow_whole_number_formula2.rs | 28 + examples/doc_data_validation_intro1.rs | 30 + .../doc_data_validation_set_error_message.rs | 28 + .../doc_data_validation_set_error_title.rs | 27 + .../doc_data_validation_set_input_message.rs | 28 + src/data_validation.rs | 1122 +++++++++++++++-- src/data_validation/tests.rs | 49 +- src/lib.rs | 6 +- src/worksheet.rs | 110 +- 21 files changed, 1814 insertions(+), 148 deletions(-) create mode 100644 examples/app_data_validation.rs create mode 100644 examples/doc_data_validation_allow_custom.rs create mode 100644 examples/doc_data_validation_allow_date.rs create mode 100644 examples/doc_data_validation_allow_decimal_number.rs create mode 100644 examples/doc_data_validation_allow_decimal_number_formula.rs create mode 100644 examples/doc_data_validation_allow_list_formula.rs create mode 100644 examples/doc_data_validation_allow_list_strings.rs create mode 100644 examples/doc_data_validation_allow_list_strings2.rs create mode 100644 examples/doc_data_validation_allow_text_length.rs create mode 100644 examples/doc_data_validation_allow_time.rs create mode 100644 examples/doc_data_validation_allow_whole_number.rs create mode 100644 examples/doc_data_validation_allow_whole_number_formula.rs create mode 100644 examples/doc_data_validation_allow_whole_number_formula2.rs create mode 100644 examples/doc_data_validation_intro1.rs create mode 100644 examples/doc_data_validation_set_error_message.rs create mode 100644 examples/doc_data_validation_set_error_title.rs create mode 100644 examples/doc_data_validation_set_input_message.rs diff --git a/examples/app_data_validation.rs b/examples/app_data_validation.rs new file mode 100644 index 00000000..ec7384c9 --- /dev/null +++ b/examples/app_data_validation.rs @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright 2022-2024, John McNamara, jmcnamara@cpan.org + +//! Example of how to add data validation and dropdown lists using the +//! rust_xlsxwriter library. +//! +//! Data validation is a feature of Excel which allows you to restrict the data +//! that a user enters in a cell and to display help and warning messages. It +//! also allows you to restrict input to values in a drop down list. + +use rust_xlsxwriter::{ + DataValidation, DataValidationErrorStyle, DataValidationRule, ExcelDateTime, Format, + FormatAlign, FormatBorder, Formula, Workbook, XlsxError, +}; + +fn main() -> Result<(), XlsxError> { + // Create a new Excel file object. + let mut workbook = Workbook::new(); + + // Add a worksheet to the workbook. + let worksheet = workbook.add_worksheet(); + + // Add a format for the header cells. + let header_format = Format::new() + .set_background_color("C6EFCE") + .set_border(FormatBorder::Thin) + .set_bold() + .set_indent(1) + .set_text_wrap() + .set_align(FormatAlign::VerticalCenter); + + // Set up layout of the worksheet. + worksheet.set_column_width(0, 68)?; + worksheet.set_column_width(1, 15)?; + worksheet.set_column_width(3, 15)?; + worksheet.set_row_height(0, 36)?; + + // Write the header cells and some data that will be used in the examples. + let heading1 = "Some examples of data validations"; + let heading2 = "Enter values in this column"; + let heading3 = "Sample Data"; + + worksheet.write_with_format(0, 0, heading1, &header_format)?; + worksheet.write_with_format(0, 1, heading2, &header_format)?; + worksheet.write_with_format(0, 3, heading3, &header_format)?; + + worksheet.write(2, 3, "Integers")?; + worksheet.write(2, 4, 1)?; + worksheet.write(2, 5, 10)?; + + worksheet.write_row(3, 3, ["List data", "open", "high", "close"])?; + + worksheet.write(4, 3, "Formula")?; + worksheet.write(4, 4, Formula::new("=AND(F5=50,G5=60)"))?; + worksheet.write(4, 5, 50)?; + worksheet.write(4, 6, 60)?; + + // ----------------------------------------------------------------------- + // Example 1. Limiting input to an integer in a fixed range. + // ----------------------------------------------------------------------- + let text = "Enter an integer between 1 and 10"; + worksheet.write(2, 0, text)?; + + let data_validation = + DataValidation::new().allow_whole_number(DataValidationRule::Between(1, 10)); + + worksheet.add_data_validation(2, 1, 2, 1, &data_validation)?; + + // ----------------------------------------------------------------------- + // Example 2. Limiting input to an integer outside a fixed range. + // ----------------------------------------------------------------------- + let text = "Enter an integer that is not between 1 and 10 (using cell references)"; + worksheet.write(4, 0, text)?; + + let data_validation = DataValidation::new() + .allow_whole_number_formula(DataValidationRule::NotBetween("=E3".into(), "=F3".into())); + + worksheet.add_data_validation(4, 1, 4, 1, &data_validation)?; + + // ----------------------------------------------------------------------- + // Example 3. Limiting input to an integer greater than a fixed value. + // ----------------------------------------------------------------------- + let text = "Enter an integer greater than 0"; + worksheet.write(6, 0, text)?; + + let data_validation = + DataValidation::new().allow_whole_number(DataValidationRule::GreaterThan(0)); + + worksheet.add_data_validation(6, 1, 6, 1, &data_validation)?; + + // ----------------------------------------------------------------------- + // Example 4. Limiting input to an integer less than a fixed value. + // ----------------------------------------------------------------------- + let text = "Enter an integer less than 10"; + worksheet.write(8, 0, text)?; + + let data_validation = + DataValidation::new().allow_whole_number(DataValidationRule::LessThan(10)); + + worksheet.add_data_validation(8, 1, 8, 1, &data_validation)?; + + // ----------------------------------------------------------------------- + // Example 5. Limiting input to a decimal in a fixed range. + // ----------------------------------------------------------------------- + let text = "Enter a decimal between 0.1 and 0.5"; + worksheet.write(10, 0, text)?; + + let data_validation = + DataValidation::new().allow_decimal_number(DataValidationRule::Between(0.1, 0.5)); + + worksheet.add_data_validation(10, 1, 10, 1, &data_validation)?; + + // ----------------------------------------------------------------------- + // Example 6. Limiting input to a value in a dropdown list. + // ----------------------------------------------------------------------- + let text = "Select a value from a drop down list"; + worksheet.write(12, 0, text)?; + + let data_validation = DataValidation::new().allow_list_strings(&["open", "high", "close"])?; + + worksheet.add_data_validation(12, 1, 12, 1, &data_validation)?; + + // ----------------------------------------------------------------------- + // Example 7. Limiting input to a value in a dropdown list. + // ----------------------------------------------------------------------- + let text = "Select a value from a drop down list (using a cell range)"; + worksheet.write(14, 0, text)?; + + let data_validation = DataValidation::new().allow_list_formula("=$E$4:$G$4".into()); + + worksheet.add_data_validation(14, 1, 14, 1, &data_validation)?; + + // ----------------------------------------------------------------------- + // Example 8. Limiting input to a date in a fixed range. + // ----------------------------------------------------------------------- + let text = "Enter a date between 1/1/2025 and 12/12/2025"; + worksheet.write(16, 0, text)?; + + let data_validation = DataValidation::new().allow_date(DataValidationRule::Between( + ExcelDateTime::parse_from_str("2025-01-01")?, + ExcelDateTime::parse_from_str("2025-12-12")?, + )); + + worksheet.add_data_validation(16, 1, 16, 1, &data_validation)?; + + // ----------------------------------------------------------------------- + // Example 9. Limiting input to a time in a fixed range. + // ----------------------------------------------------------------------- + let text = "Enter a time between 6:00 and 12:00"; + worksheet.write(18, 0, text)?; + + let data_validation = DataValidation::new().allow_time(DataValidationRule::Between( + ExcelDateTime::parse_from_str("6:00")?, + ExcelDateTime::parse_from_str("12:00")?, + )); + + worksheet.add_data_validation(18, 1, 18, 1, &data_validation)?; + + // ----------------------------------------------------------------------- + // Example 10. Limiting input to a string greater than a fixed length. + // ----------------------------------------------------------------------- + let text = "Enter a string longer than 3 characters"; + worksheet.write(20, 0, text)?; + + let data_validation = + DataValidation::new().allow_text_length(DataValidationRule::GreaterThan(3)); + + worksheet.add_data_validation(20, 1, 20, 1, &data_validation)?; + + // ----------------------------------------------------------------------- + // Example 11. Limiting input based on a formula. + // ----------------------------------------------------------------------- + let text = "Enter a value if the following is true '=AND(F5=50,G5=60)'"; + worksheet.write(22, 0, text)?; + + let data_validation = DataValidation::new().allow_custom("=AND(F5=50,G5=60)".into()); + + worksheet.add_data_validation(22, 1, 22, 1, &data_validation)?; + + // ----------------------------------------------------------------------- + // Example 12. Displaying and modifying data validation messages. + // ----------------------------------------------------------------------- + let text = "Displays a message when you select the cell"; + worksheet.write(24, 0, text)?; + + let data_validation = DataValidation::new() + .allow_whole_number(DataValidationRule::Between(1, 100)) + .set_input_title("Enter an integer:") + .set_input_message("between 1 and 100"); + + worksheet.add_data_validation(24, 1, 24, 1, &data_validation)?; + + // ----------------------------------------------------------------------- + // Example 13. Displaying and modifying data validation messages. + // ----------------------------------------------------------------------- + let text = "Display a custom error message when integer isn't between 1 and 100"; + worksheet.write(26, 0, text)?; + + let data_validation = DataValidation::new() + .allow_whole_number(DataValidationRule::Between(1, 100)) + .set_input_title("Enter an integer:") + .set_input_message("between 1 and 100") + .set_error_title("Input value is not valid!") + .set_error_message("It should be an integer between 1 and 100"); + + worksheet.add_data_validation(26, 1, 26, 1, &data_validation)?; + + // ----------------------------------------------------------------------- + // Example 14. Displaying and modifying data validation messages. + // ----------------------------------------------------------------------- + let text = "Display a custom info message when integer isn't between 1 and 100"; + worksheet.write(28, 0, text)?; + + let data_validation = DataValidation::new() + .allow_whole_number(DataValidationRule::Between(1, 100)) + .set_input_title("Enter an integer:") + .set_input_message("between 1 and 100") + .set_error_title("Input value is not valid!") + .set_error_message("It should be an integer between 1 and 100") + .set_error_style(DataValidationErrorStyle::Information); + + worksheet.add_data_validation(28, 1, 28, 1, &data_validation)?; + + // ----------------------------------------------------------------------- + // Save and close the file. + // ----------------------------------------------------------------------- + workbook.save("data_validation.xlsx")?; + + Ok(()) +} diff --git a/examples/doc_data_validation_allow_custom.rs b/examples/doc_data_validation_allow_custom.rs new file mode 100644 index 00000000..76a5d2ed --- /dev/null +++ b/examples/doc_data_validation_allow_custom.rs @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright 2022-2024, John McNamara, jmcnamara@cpan.org + +//! Example of adding a data validation to a worksheet cell. This validation +//! restricts input to text/strings that are uppercase. + +use rust_xlsxwriter::{DataValidation, Workbook, XlsxError}; + +fn main() -> Result<(), XlsxError> { + // Create a new Excel file object. + let mut workbook = Workbook::new(); + let worksheet = workbook.add_worksheet(); + + worksheet.write(1, 0, "Enter uppercase string in D2:")?; + + let data_validation = + DataValidation::new().allow_custom("=AND(ISTEXT(D2), EXACT(D2, UPPER(D2)))".into()); + + worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + + // Save the file. + workbook.save("data_validation.xlsx")?; + + Ok(()) +} diff --git a/examples/doc_data_validation_allow_date.rs b/examples/doc_data_validation_allow_date.rs new file mode 100644 index 00000000..13a16fca --- /dev/null +++ b/examples/doc_data_validation_allow_date.rs @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright 2022-2024, John McNamara, jmcnamara@cpan.org + +//! Example of adding a data validation to a worksheet cell. This validation +//! restricts input to date values in a fixed range. + +use rust_xlsxwriter::{DataValidation, DataValidationRule, ExcelDateTime, Workbook, XlsxError}; + +fn main() -> Result<(), XlsxError> { + // Create a new Excel file object. + let mut workbook = Workbook::new(); + let worksheet = workbook.add_worksheet(); + + worksheet.write(1, 0, "Enter value in cell D2:")?; + + let data_validation = DataValidation::new().allow_date(DataValidationRule::Between( + ExcelDateTime::parse_from_str("2025-01-01")?, + ExcelDateTime::parse_from_str("2025-12-12")?, + )); + + worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + + // Save the file. + workbook.save("data_validation.xlsx")?; + + Ok(()) +} diff --git a/examples/doc_data_validation_allow_decimal_number.rs b/examples/doc_data_validation_allow_decimal_number.rs new file mode 100644 index 00000000..9b565aca --- /dev/null +++ b/examples/doc_data_validation_allow_decimal_number.rs @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright 2022-2024, John McNamara, jmcnamara@cpan.org + +//! Example of adding a data validation to a worksheet cell. This validation +//! restricts input to floating point values in a fixed range. + +use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + +fn main() -> Result<(), XlsxError> { + // Create a new Excel file object. + let mut workbook = Workbook::new(); + let worksheet = workbook.add_worksheet(); + + worksheet.write(1, 0, "Enter value in cell D2:")?; + + let data_validation = + DataValidation::new().allow_decimal_number(DataValidationRule::Between(-9.9, 9.9)); + + worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + + // Save the file. + workbook.save("data_validation.xlsx")?; + + Ok(()) +} diff --git a/examples/doc_data_validation_allow_decimal_number_formula.rs b/examples/doc_data_validation_allow_decimal_number_formula.rs new file mode 100644 index 00000000..7bd2c8db --- /dev/null +++ b/examples/doc_data_validation_allow_decimal_number_formula.rs @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright 2022-2024, John McNamara, jmcnamara@cpan.org + +//! Example of adding a data validation to a worksheet cell. This validation +//! restricts input to floating point values based on a value from another cell. + +use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + +fn main() -> Result<(), XlsxError> { + // Create a new Excel file object. + let mut workbook = Workbook::new(); + let worksheet = workbook.add_worksheet(); + + worksheet.write(0, 0, "Upper limit:")?; + worksheet.write(0, 3, 99.9)?; + worksheet.write(1, 0, "Enter value in cell D2:")?; + + let data_validation = DataValidation::new() + .allow_decimal_number_formula(DataValidationRule::LessThanOrEqualTo("=D1".into())); + + worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + + // Save the file. + workbook.save("data_validation.xlsx")?; + + Ok(()) +} diff --git a/examples/doc_data_validation_allow_list_formula.rs b/examples/doc_data_validation_allow_list_formula.rs new file mode 100644 index 00000000..c3dcf861 --- /dev/null +++ b/examples/doc_data_validation_allow_list_formula.rs @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright 2022-2024, John McNamara, jmcnamara@cpan.org + +//! Example of adding a data validation to a worksheet cell. This validation +//! restricts users to a selection of values from a dropdown list. The list data +//! is provided from a cell range. + +use rust_xlsxwriter::{DataValidation, Workbook, XlsxError}; + +fn main() -> Result<(), XlsxError> { + // Create a new Excel file object. + let mut workbook = Workbook::new(); + let worksheet = workbook.add_worksheet(); + + worksheet.write(1, 0, "Select value in cell D2:")?; + + // Write the string list data to some cells. + let string_list = ["Pass", "Fail", "Incomplete"]; + worksheet.write_column(1, 5, string_list)?; + + let data_validation = DataValidation::new().allow_list_formula("F2:F4".into()); + + worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + + // Save the file. + workbook.save("data_validation.xlsx")?; + + Ok(()) +} diff --git a/examples/doc_data_validation_allow_list_strings.rs b/examples/doc_data_validation_allow_list_strings.rs new file mode 100644 index 00000000..8a259a36 --- /dev/null +++ b/examples/doc_data_validation_allow_list_strings.rs @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright 2022-2024, John McNamara, jmcnamara@cpan.org + +//! Example of adding a data validation to a worksheet cell. This validation +//! restricts users to a selection of values from a dropdown list. + +use rust_xlsxwriter::{DataValidation, Workbook, XlsxError}; + +fn main() -> Result<(), XlsxError> { + // Create a new Excel file object. + let mut workbook = Workbook::new(); + let worksheet = workbook.add_worksheet(); + + worksheet.write(1, 0, "Select value in cell D2:")?; + + let data_validation = + DataValidation::new().allow_list_strings(&["Pass", "Fail", "Incomplete"])?; + + worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + + // Save the file. + workbook.save("data_validation.xlsx")?; + + Ok(()) +} diff --git a/examples/doc_data_validation_allow_list_strings2.rs b/examples/doc_data_validation_allow_list_strings2.rs new file mode 100644 index 00000000..cd67aac4 --- /dev/null +++ b/examples/doc_data_validation_allow_list_strings2.rs @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright 2022-2024, John McNamara, jmcnamara@cpan.org + +//! Example of adding a data validation to a worksheet cell. This validation +//! restricts users to a selection of values from a dropdown list. This example +//! shows how to pre-populate a default choice. + +use rust_xlsxwriter::{DataValidation, Workbook, XlsxError}; + +fn main() -> Result<(), XlsxError> { + // Create a new Excel file object. + let mut workbook = Workbook::new(); + let worksheet = workbook.add_worksheet(); + + worksheet.write(1, 0, "Select value in cell D2:")?; + + let data_validation = + DataValidation::new().allow_list_strings(&["Pass", "Fail", "Incomplete"])?; + + worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + + // Add a default string to the cell with the data validation + // to pre-populate a default choice. + worksheet.write(1, 3, "Pass")?; + + // Save the file. + workbook.save("data_validation.xlsx")?; + + Ok(()) +} diff --git a/examples/doc_data_validation_allow_text_length.rs b/examples/doc_data_validation_allow_text_length.rs new file mode 100644 index 00000000..b6217403 --- /dev/null +++ b/examples/doc_data_validation_allow_text_length.rs @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright 2022-2024, John McNamara, jmcnamara@cpan.org + +//! Example of adding a data validation to a worksheet cell. This validation +//! restricts input to strings whose lengths is in a fixed range. + +use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + +fn main() -> Result<(), XlsxError> { + // Create a new Excel file object. + let mut workbook = Workbook::new(); + let worksheet = workbook.add_worksheet(); + + worksheet.write(1, 0, "Enter value in cell D2:")?; + + let data_validation = + DataValidation::new().allow_text_length(DataValidationRule::Between(4, 8)); + + worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + + // Save the file. + workbook.save("data_validation.xlsx")?; + + Ok(()) +} diff --git a/examples/doc_data_validation_allow_time.rs b/examples/doc_data_validation_allow_time.rs new file mode 100644 index 00000000..71a903ab --- /dev/null +++ b/examples/doc_data_validation_allow_time.rs @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright 2022-2024, John McNamara, jmcnamara@cpan.org + +//! Example of adding a data validation to a worksheet cell. This validation +//! restricts input to time values in a fixed range. + +use rust_xlsxwriter::{DataValidation, DataValidationRule, ExcelDateTime, Workbook, XlsxError}; + +fn main() -> Result<(), XlsxError> { + // Create a new Excel file object. + let mut workbook = Workbook::new(); + let worksheet = workbook.add_worksheet(); + + worksheet.write(1, 0, "Enter value in cell D2:")?; + + let data_validation = DataValidation::new().allow_time(DataValidationRule::Between( + ExcelDateTime::parse_from_str("6:00")?, + ExcelDateTime::parse_from_str("12:00")?, + )); + + worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + + // Save the file. + workbook.save("data_validation.xlsx")?; + + Ok(()) +} diff --git a/examples/doc_data_validation_allow_whole_number.rs b/examples/doc_data_validation_allow_whole_number.rs new file mode 100644 index 00000000..7cc37933 --- /dev/null +++ b/examples/doc_data_validation_allow_whole_number.rs @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright 2022-2024, John McNamara, jmcnamara@cpan.org + +//! Example of adding a data validation to a worksheet cell. This validation +//! restricts input to integer values in a fixed range. + +use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + +fn main() -> Result<(), XlsxError> { + // Create a new Excel file object. + let mut workbook = Workbook::new(); + let worksheet = workbook.add_worksheet(); + + worksheet.write(1, 0, "Enter value in cell D2:")?; + + let data_validation = + DataValidation::new().allow_whole_number(DataValidationRule::Between(1, 10)); + + worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + + // Save the file. + workbook.save("data_validation.xlsx")?; + + Ok(()) +} diff --git a/examples/doc_data_validation_allow_whole_number_formula.rs b/examples/doc_data_validation_allow_whole_number_formula.rs new file mode 100644 index 00000000..ee7d4dea --- /dev/null +++ b/examples/doc_data_validation_allow_whole_number_formula.rs @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright 2022-2024, John McNamara, jmcnamara@cpan.org + +//! Example of adding a data validation to a worksheet cell. This validation +//! restricts input to integer values based on a value from another cell. + +use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + +fn main() -> Result<(), XlsxError> { + // Create a new Excel file object. + let mut workbook = Workbook::new(); + let worksheet = workbook.add_worksheet(); + + worksheet.write(0, 0, "Upper limit:")?; + worksheet.write(0, 3, 10)?; + worksheet.write(1, 0, "Enter value in cell D2:")?; + + let data_validation = DataValidation::new() + .allow_whole_number_formula(DataValidationRule::LessThanOrEqualTo("=D1".into())); + + worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + + // Save the file. + workbook.save("data_validation.xlsx")?; + + Ok(()) +} diff --git a/examples/doc_data_validation_allow_whole_number_formula2.rs b/examples/doc_data_validation_allow_whole_number_formula2.rs new file mode 100644 index 00000000..1f32c505 --- /dev/null +++ b/examples/doc_data_validation_allow_whole_number_formula2.rs @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright 2022-2024, John McNamara, jmcnamara@cpan.org + +//! Example of adding a data validation to a worksheet cell. This validation +//! restricts input to integer values based on a value from another cell. + +use rust_xlsxwriter::{DataValidation, DataValidationRule, Formula, Workbook, XlsxError}; + +fn main() -> Result<(), XlsxError> { + // Create a new Excel file object. + let mut workbook = Workbook::new(); + let worksheet = workbook.add_worksheet(); + + worksheet.write(0, 0, "Upper limit:")?; + worksheet.write(0, 3, 10)?; + worksheet.write(1, 0, "Enter value in cell D2:")?; + + let data_validation = DataValidation::new() + .allow_whole_number_formula(DataValidationRule::LessThanOrEqualTo(Formula::new("=D1"))); + + worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + + // Save the file. + workbook.save("data_validation.xlsx")?; + + Ok(()) +} diff --git a/examples/doc_data_validation_intro1.rs b/examples/doc_data_validation_intro1.rs new file mode 100644 index 00000000..d3b0afbc --- /dev/null +++ b/examples/doc_data_validation_intro1.rs @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright 2022-2024, John McNamara, jmcnamara@cpan.org + +//! Example of adding a data validation to a worksheet cell. This validation +//! uses an input message to explain to the user what type of input is required. + +use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + +fn main() -> Result<(), XlsxError> { + // Create a new Excel file object. + let mut workbook = Workbook::new(); + let worksheet = workbook.add_worksheet(); + + worksheet.write(1, 0, "Enter rating in cell D2:")?; + + let data_validation = DataValidation::new() + .allow_whole_number(DataValidationRule::Between(1, 5)) + .set_input_title("Enter a star rating!") + .set_input_message("Enter rating 1-5.\nWhole numbers only.") + .set_error_title("Value outside allowed range") + .set_error_message("The input value must be an integer in the range 1-5."); + + worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + + // Save the file. + workbook.save("data_validation.xlsx")?; + + Ok(()) +} diff --git a/examples/doc_data_validation_set_error_message.rs b/examples/doc_data_validation_set_error_message.rs new file mode 100644 index 00000000..9d2bd7e0 --- /dev/null +++ b/examples/doc_data_validation_set_error_message.rs @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright 2022-2024, John McNamara, jmcnamara@cpan.org + +//! Example of adding a data validation to a worksheet cell. This validation +//! shows a custom error message. + +use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + +fn main() -> Result<(), XlsxError> { + // Create a new Excel file object. + let mut workbook = Workbook::new(); + let worksheet = workbook.add_worksheet(); + + worksheet.write(1, 0, "Enter value in cell D2:")?; + + let data_validation = DataValidation::new() + .allow_whole_number(DataValidationRule::Between(1, 10)) + .set_error_title("Value outside allowed range") + .set_error_message("The input value must be an integer in the range 1-10."); + + worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + + // Save the file. + workbook.save("data_validation.xlsx")?; + + Ok(()) +} diff --git a/examples/doc_data_validation_set_error_title.rs b/examples/doc_data_validation_set_error_title.rs new file mode 100644 index 00000000..fab8853f --- /dev/null +++ b/examples/doc_data_validation_set_error_title.rs @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright 2022-2024, John McNamara, jmcnamara@cpan.org + +//! Example of adding a data validation to a worksheet cell. This validation +//! shows a custom error title. + +use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + +fn main() -> Result<(), XlsxError> { + // Create a new Excel file object. + let mut workbook = Workbook::new(); + let worksheet = workbook.add_worksheet(); + + worksheet.write(1, 0, "Enter value in cell D2:")?; + + let data_validation = DataValidation::new() + .allow_whole_number(DataValidationRule::Between(1, 10)) + .set_error_title("Danger, Will Robinson!"); + + worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + + // Save the file. + workbook.save("data_validation.xlsx")?; + + Ok(()) +} diff --git a/examples/doc_data_validation_set_input_message.rs b/examples/doc_data_validation_set_input_message.rs new file mode 100644 index 00000000..61c90e5f --- /dev/null +++ b/examples/doc_data_validation_set_input_message.rs @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright 2022-2024, John McNamara, jmcnamara@cpan.org + +//! Example of adding a data validation to a worksheet cell. This validation +//! uses an input message to explain to the user what type of input is required. + +use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + +fn main() -> Result<(), XlsxError> { + // Create a new Excel file object. + let mut workbook = Workbook::new(); + let worksheet = workbook.add_worksheet(); + + worksheet.write(1, 0, "Enter rating in cell D2:")?; + + let data_validation = DataValidation::new() + .allow_whole_number(DataValidationRule::Between(1, 5)) + .set_input_title("Enter a star rating!") + .set_input_message("Enter rating 1-5.\nWhole numbers only."); + + worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + + // Save the file. + workbook.save("data_validation.xlsx")?; + + Ok(()) +} diff --git a/src/data_validation.rs b/src/data_validation.rs index b3f616a5..b21e229b 100644 --- a/src/data_validation.rs +++ b/src/data_validation.rs @@ -4,10 +4,6 @@ // // Copyright 2022-2024, John McNamara, jmcnamara@cpan.org -//! # Working with Data Validation -//! -//! TODO - #![warn(missing_docs)] mod tests; @@ -22,9 +18,162 @@ use std::fmt; // DataValidation // ----------------------------------------------------------------------- -/// The `DataValidation` struct represents a Cell conditional format. +/// The `DataValidation` struct represents a cell Data Validation. +/// +/// `DataValidation` is used in conjunction with the +/// [`Worksheet::add_data_validation()`](crate::Worksheet::add_data_validation) +/// method. +/// +/// # Working with Data Validation +/// +/// Data validation is a feature of Excel that allows you to restrict the data +/// that a user enters in a cell and to display associated help and warning +/// messages. It also allows you to restrict input to values in a dropdown list. +/// +/// A typical use case might be to restrict data in a cell to integer values in +/// a certain range, to provide a help message to indicate the required value, +/// and to issue a warning if the input data doesn't meet the stated criteria. +/// +/// +/// +/// This example was created with the following code: +/// +/// ``` +/// # // This code is available in examples/doc_data_validation_intro1.rs +/// # +/// use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; +/// +/// fn main() -> Result<(), XlsxError> { +/// // Create a new Excel file object. +/// let mut workbook = Workbook::new(); +/// let worksheet = workbook.add_worksheet(); +/// +/// worksheet.write(1, 0, "Enter rating in cell D2:")?; +/// +/// let data_validation = DataValidation::new() +/// .allow_whole_number(DataValidationRule::Between(1, 5)) +/// .set_input_title("Enter a star rating!") +/// .set_input_message("Enter rating 1-5.\nWhole numbers only.") +/// .set_error_title("Value outside allowed range") +/// .set_error_message("The input value must be an integer in the range 1-5."); +/// +/// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; +/// +/// // Save the file. +/// workbook.save("data_validation.xlsx")?; +/// +/// Ok(()) +/// } +/// ``` +/// +/// Another common data validation task is to limit input to values on a +/// dropdown list. +/// +/// +/// +/// This example was created with the following code: +/// +/// ``` +/// # // This code is available in examples/doc_data_validation_allow_list_strings.rs +/// # +/// use rust_xlsxwriter::{DataValidation, Workbook, XlsxError}; +/// +/// fn main() -> Result<(), XlsxError> { +/// // Create a new Excel file object. +/// let mut workbook = Workbook::new(); +/// let worksheet = workbook.add_worksheet(); +/// +/// worksheet.write(1, 0, "Select value in cell D2:")?; +/// +/// let data_validation = +/// DataValidation::new().allow_list_strings(&["Pass", "Fail", "Incomplete"])?; +/// +/// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; +/// +/// // Save the file. +/// workbook.save("data_validation.xlsx")?; +/// +/// Ok(()) +/// } +/// ``` +/// +/// For more information and examples see the API documentation below. +/// +/// +/// ## Using cell references in Data Validations +/// +/// Excel allows the values for data validation to be either a "literal" number, +/// date or time value or a cell reference such as `=D1`. In the `DataValidation` +/// interfaces these are represented using a [`Formula`] value, like this: +/// +/// ``` +/// # // This code is available in examples/doc_data_validation_allow_whole_number_formula2.rs +/// # +/// # use rust_xlsxwriter::{DataValidation, DataValidationRule, Formula, Workbook, XlsxError}; +/// # +/// # fn main() -> Result<(), XlsxError> { +/// # // Create a new Excel file object. +/// # let mut workbook = Workbook::new(); +/// # let worksheet = workbook.add_worksheet(); +/// # +/// # worksheet.write(0, 0, "Upper limit:")?; +/// # worksheet.write(0, 3, 10)?; +/// # worksheet.write(1, 0, "Enter value in cell D2:")?; +/// # +/// let data_validation = DataValidation::new() +/// .allow_whole_number_formula( +/// DataValidationRule::LessThanOrEqualTo(Formula::new("=D1"))); +/// # +/// # worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; +/// # +/// # // Save the file. +/// # workbook.save("data_validation.xlsx")?; +/// # +/// # Ok(()) +/// # } +/// ``` +/// In Excel this creates the following data validation: +/// +/// +/// +/// As a syntactic shorthand you can also use `into()` like this: /// -/// TODO +/// ``` +/// # // This code is available in examples/doc_data_validation_allow_whole_number_formula.rs +/// # +/// # use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; +/// # +/// # fn main() -> Result<(), XlsxError> { +/// # // Create a new Excel file object. +/// # let mut workbook = Workbook::new(); +/// # let worksheet = workbook.add_worksheet(); +/// # +/// # worksheet.write(0, 0, "Upper limit:")?; +/// # worksheet.write(0, 3, 10)?; +/// # worksheet.write(1, 0, "Enter value in cell D2:")?; +/// # +/// let data_validation = DataValidation::new() +/// .allow_whole_number_formula(DataValidationRule::LessThanOrEqualTo("=D1".into())); +/// # +/// # worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; +/// # +/// # // Save the file. +/// # workbook.save("data_validation.xlsx")?; +/// # +/// # Ok(()) +/// # } +/// ``` +/// +/// APIs that use [`Formula`] can also take Excel formulas, where that makes +/// sense. +/// +/// **Note**: the contents of the `Formula` aren't validated by +/// `rust_xlsxwriter` so you should take care to ensure that the ranges or +/// formulas are valid in Excel if you are using anything other than a simple +/// range. /// #[derive(Clone)] pub struct DataValidation { @@ -42,7 +191,12 @@ pub struct DataValidation { } impl DataValidation { - /// Create a new Cell conditional format struct. + /// Create a new cell Data Validation struct. + /// + /// The default type of a new data validation is equivalent to Excel's "Any" + /// data validation. Refer to the `allow_TYPE()` functions below to + /// constrain the data validation to defined types and apply rules. + /// #[allow(clippy::new_without_default)] pub fn new() -> DataValidation { DataValidation { @@ -60,19 +214,56 @@ impl DataValidation { } } - /// Set the TODO + /// Set a data validation to limit input to integers using defined rules. /// - /// TODO + /// Set a data validation rule to restrict cell input to integers based on + /// [`DataValidationRule`] rules such as "between" or "less than". Excel + /// refers to this data validation type as "Whole number" but it equates to + /// any Rust type that can convert [`Into`] a [`i32`] (`i64/u64` values + /// aren't supported by Excel). /// - pub fn allow_any_value(mut self) -> DataValidation { - self.rule = DataValidationRuleInternal::EqualTo(String::new()); - self.validation_type = DataValidationType::Any; - self - } - - /// Set the TODO + /// # Parameters + /// + /// * `rule` - A [`DataValidationRule`] with [`i32`] values. + /// + /// # Examples + /// + /// Example of adding a data validation to a worksheet cell. This validation + /// restricts input to integer values in a fixed range. + /// + /// ``` + /// # // This code is available in examples/doc_data_validation_allow_whole_number.rs + /// # + /// # use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + /// # + /// # fn main() -> Result<(), XlsxError> { + /// # // Create a new Excel file object. + /// # let mut workbook = Workbook::new(); + /// # let worksheet = workbook.add_worksheet(); + /// # + /// # worksheet.write(1, 0, "Enter value in cell D2:")?; + /// # + /// let data_validation = + /// DataValidation::new().allow_whole_number(DataValidationRule::Between(1, 10)); + /// + /// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + /// # + /// # // Save the file. + /// # workbook.save("data_validation.xlsx")?; + /// # + /// # Ok(()) + /// # } + /// ``` /// - /// TODO + /// Output file: + /// + /// + /// + /// The Excel Data Validation dialog for this file should look something like this: + /// + /// /// pub fn allow_whole_number(mut self, rule: DataValidationRule) -> DataValidation { self.rule = rule.to_internal_rule(); @@ -80,9 +271,59 @@ impl DataValidation { self } - /// Set the TODO + /// Set a data validation to limit input to integers using defined rules and + /// a cell reference. + /// + /// Set a data validation rule to restrict cell input to integers based on + /// [`DataValidationRule`] rules such as "between" or "less than". Excel + /// refers to this data validation type as "Whole number". The values used + /// for the rules should be a cell reference represented by a [`Formula`], + /// see [Using cell references in Data Validations] and the example below. + /// + /// # Parameters + /// + /// * `rule` - A [`DataValidationRule`] with cell references using + /// [`Formula`] values. See [Using cell references in Data Validations]. + /// + /// [Using cell references in Data Validations]: + /// #using-cell-references-in-data-validations /// - /// TODO + /// # Examples + /// + /// Example of adding a data validation to a worksheet cell. This validation + /// restricts input to integer values based on a value from another cell. + /// + /// ``` + /// # // This code is available in examples/doc_data_validation_allow_whole_number_formula.rs + /// # + /// # use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + /// # + /// # fn main() -> Result<(), XlsxError> { + /// # // Create a new Excel file object. + /// # let mut workbook = Workbook::new(); + /// # let worksheet = workbook.add_worksheet(); + /// # + /// # worksheet.write(0, 0, "Upper limit:")?; + /// # worksheet.write(0, 3, 10)?; + /// # worksheet.write(1, 0, "Enter value in cell D2:")?; + /// # + /// let data_validation = DataValidation::new() + /// .allow_whole_number_formula(DataValidationRule::LessThanOrEqualTo("=D1".into())); + /// + /// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + /// # + /// # // Save the file. + /// # workbook.save("data_validation.xlsx")?; + /// # + /// # Ok(()) + /// # } + /// ``` + /// + /// The Excel Data Validation dialog for the output file should look + /// something like this: + /// + /// /// pub fn allow_whole_number_formula( mut self, @@ -93,9 +334,56 @@ impl DataValidation { self } - /// Set the TODO + /// Set a data validation to limit input to floating point numbers using + /// defined rules. + /// + /// Set a data validation rule to restrict cell input to floating point + /// numbers based on [`DataValidationRule`] rules such as "between" or "less + /// than". Excel refers to this data validation type as "Decimal" but it + /// equates to the Rust type [`f64`]. /// - /// TODO + /// # Parameters + /// + /// * `rule` - A [`DataValidationRule`] with [`f64`] values. + /// + /// # Examples + /// + /// Example of adding a data validation to a worksheet cell. This validation + /// restricts input to floating point values in a fixed range. + /// + /// ``` + /// # // This code is available in examples/doc_data_validation_allow_decimal_number.rs + /// # + /// # use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + /// # + /// # fn main() -> Result<(), XlsxError> { + /// # // Create a new Excel file object. + /// # let mut workbook = Workbook::new(); + /// # let worksheet = workbook.add_worksheet(); + /// # + /// # worksheet.write(1, 0, "Enter value in cell D2:")?; + /// # + /// let data_validation = + /// DataValidation::new().allow_decimal_number(DataValidationRule::Between(-9.9, 9.9)); + /// + /// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + /// # + /// # // Save the file. + /// # workbook.save("data_validation.xlsx")?; + /// # + /// # Ok(()) + /// # } + /// ``` + /// + /// Output file: + /// + /// + /// + /// The Excel Data Validation dialog for this file should look something like this: + /// + /// /// pub fn allow_decimal_number(mut self, rule: DataValidationRule) -> DataValidation { self.rule = rule.to_internal_rule(); @@ -103,9 +391,60 @@ impl DataValidation { self } - /// Set the TODO + /// Set a data validation to limit input to floating point numbers using + /// defined rules and a cell reference. + /// + /// Set a data validation rule to restrict cell input to floating point + /// numbers based on [`DataValidationRule`] rules such as "between" or "less + /// than". Excel refers to this data validation type as "Decimal". The + /// values used for the rules should be a cell reference represented by a + /// [`Formula`], see [Using cell references in Data Validations] and the + /// example below. + /// + /// # Parameters + /// + /// * `rule` - A [`DataValidationRule`] with cell references using + /// [`Formula`] values. See [Using cell references in Data Validations]. + /// + /// [Using cell references in Data Validations]: + /// #using-cell-references-in-data-validations + /// + /// # Examples + /// + /// Example of adding a data validation to a worksheet cell. This validation + /// restricts input to floating point values based on a value from another + /// cell. /// - /// TODO + /// ``` + /// # // This code is available in examples/doc_data_validation_allow_decimal_number_formula.rs + /// # + /// # use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + /// # + /// # fn main() -> Result<(), XlsxError> { + /// # // Create a new Excel file object. + /// # let mut workbook = Workbook::new(); + /// # let worksheet = workbook.add_worksheet(); + /// # + /// # worksheet.write(0, 0, "Upper limit:")?; + /// # worksheet.write(0, 3, 99.9)?; + /// # worksheet.write(1, 0, "Enter value in cell D2:")?; + /// # + /// let data_validation = DataValidation::new() + /// .allow_decimal_number_formula(DataValidationRule::LessThanOrEqualTo("=D1".into())); + /// + /// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + /// # + /// # // Save the file. + /// # workbook.save("data_validation.xlsx")?; + /// # + /// # Ok(()) + /// # } + /// ``` + /// + /// The Excel Data Validation dialog for the output file should look something like this: + /// + /// /// pub fn allow_decimal_number_formula( mut self, @@ -116,12 +455,98 @@ impl DataValidation { self } - /// Set the TODO + /// Set a data validation rule to restrict cell input to a selection of + /// strings via a dropdown menu. + /// + /// **Note**: Excel has a 255 character limit to the the string used to + /// store the comma-separated list of strings, including the commas. An + /// example of the comma-separated string is shown in the Excel Data + /// Validation dialog below. This limit makes it unsuitable for long lists + /// such as a list of provinces or states. For longer lists it is better to + /// place the string values somewhere in the Excel workbook and refer to + /// them using a range formula via the + /// [`DataValidation::allow_list_formula()`] method shown below. /// - /// TODO + /// # Parameters + /// + /// * `list` - A list of string like objects. /// /// # Errors /// + /// * [`XlsxError::DataValidationError`] - The length of the accumulated + /// comma-separated list of strings, including commas, exceeds Excel's + /// limit of 255 characters, see the note above. + /// + /// # Examples + /// + /// Example of adding a data validation to a worksheet cell. This validation + /// restricts users to a selection of values from a dropdown list. + /// + /// ``` + /// # // This code is available in examples/doc_data_validation_allow_list_strings.rs + /// # + /// # use rust_xlsxwriter::{DataValidation, Workbook, XlsxError}; + /// # + /// # fn main() -> Result<(), XlsxError> { + /// # // Create a new Excel file object. + /// # let mut workbook = Workbook::new(); + /// # let worksheet = workbook.add_worksheet(); + /// # + /// # worksheet.write(1, 0, "Select value in cell D2:")?; + /// # + /// let data_validation = + /// DataValidation::new().allow_list_strings(&["Pass", "Fail", "Incomplete"])?; + /// + /// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + /// # + /// # // Save the file. + /// # workbook.save("data_validation.xlsx")?; + /// # + /// # Ok(()) + /// # } + /// ``` + /// + /// Output file: + /// + /// + /// + /// The Excel Data Validation dialog for this file should look something + /// like this: + /// + /// + /// + /// The following is a similar example but it demonstrates how to + /// pre-populate a default choice. + /// + /// ``` + /// # // This code is available in examples/doc_data_validation_allow_list_strings2.rs + /// # + /// # use rust_xlsxwriter::{DataValidation, Workbook, XlsxError}; + /// # + /// # fn main() -> Result<(), XlsxError> { + /// # // Create a new Excel file object. + /// # let mut workbook = Workbook::new(); + /// # let worksheet = workbook.add_worksheet(); + /// # + /// # worksheet.write(1, 0, "Select value in cell D2:")?; + /// # + /// let data_validation = + /// DataValidation::new().allow_list_strings(&["Pass", "Fail", "Incomplete"])?; + /// + /// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + /// + /// // Add a default string to the cell with the data validation + /// // to pre-populate a default choice. + /// worksheet.write(1, 3, "Pass")?; + /// # + /// # // Save the file. + /// # workbook.save("data_validation.xlsx")?; + /// # + /// # Ok(()) + /// # } + /// ``` pub fn allow_list_strings( mut self, list: &[impl AsRef], @@ -146,20 +571,125 @@ impl DataValidation { Ok(self) } - /// Set the TODO + /// Set a data validation rule to restrict cell input to a selection of + /// strings via a dropdown menu and a cell range reference. /// - /// TODO + /// The strings for the dropdown should be placed somewhere in the + /// worksheet/workbook and should be referred to via a cell range reference + /// represented by a [`Formula`], see [Using cell references in Data + /// Validations] and the example below. /// - pub fn allow_list_formula(mut self, rule: Formula) -> DataValidation { - let formula = rule.expand_formula(true).to_string(); + /// # Parameters + /// * `list` - A cell range reference such as `=B1:B9`, `=$B$1:$B$9` or + /// `=Sheet2!B1:B9` using a [`Formula`]. See [Using cell references in + /// Data Validations]. + /// + /// [Using cell references in Data Validations]: + /// #using-cell-references-in-data-validations + /// + /// # Examples + /// + /// Example of adding a data validation to a worksheet cell. This validation + /// restricts users to a selection of values from a dropdown list. The list data + /// is provided from a cell range. + /// + /// ``` + /// # // This code is available in examples/doc_data_validation_allow_list_formula.rs + /// # + /// # use rust_xlsxwriter::{DataValidation, Workbook, XlsxError}; + /// # + /// # fn main() -> Result<(), XlsxError> { + /// # // Create a new Excel file object. + /// # let mut workbook = Workbook::new(); + /// # let worksheet = workbook.add_worksheet(); + /// # + /// # worksheet.write(1, 0, "Select value in cell D2:")?; + /// # + /// // Write the string list data to some cells. + /// let string_list = ["Pass", "Fail", "Incomplete"]; + /// worksheet.write_column(1, 5, string_list)?; + /// + /// let data_validation = DataValidation::new().allow_list_formula("F2:F4".into()); + /// + /// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + /// # + /// # // Save the file. + /// # workbook.save("data_validation.xlsx")?; + /// # + /// # Ok(()) + /// # } + /// ``` + /// + /// Output file: + /// + /// + /// + /// The Excel Data Validation dialog for this file should look something + /// like this: + /// + /// + /// + pub fn allow_list_formula(mut self, list: Formula) -> DataValidation { + let formula = list.expand_formula(true).to_string(); self.rule = DataValidationRuleInternal::ListSource(formula); self.validation_type = DataValidationType::List; self } - /// Set the TODO + /// Set a data validation to limit input to dates using defined rules. + /// + /// Set a data validation rule to restrict cell input to date values based + /// on [`DataValidationRule`] rules such as "between" or "less than". Excel + /// refers to this data validation type as "Date". + /// + /// The method uses dates that implement [`IntoExcelDateTime`]. The main + /// date type supported is [`ExcelDateTime`]. If the `chrono` feature is + /// enabled you can use [`chrono::NaiveDate`]. + /// + /// [`chrono::NaiveDate`]: + /// https://docs.rs/chrono/latest/chrono/naive/struct.NaiveDate.html + /// + /// # Parameters + /// + /// * `rule` - A [`DataValidationRule`] with [`IntoExcelDateTime`] values. + /// + /// # Examples /// - /// TODO + /// Example of adding a data validation to a worksheet cell. This validation + /// restricts input to date values in a fixed range. + /// + /// ``` + /// # // This code is available in examples/doc_data_validation_allow_date.rs + /// # + /// # use rust_xlsxwriter::{DataValidation, DataValidationRule, ExcelDateTime, Workbook, XlsxError}; + /// # + /// # fn main() -> Result<(), XlsxError> { + /// # // Create a new Excel file object. + /// # let mut workbook = Workbook::new(); + /// # let worksheet = workbook.add_worksheet(); + /// # + /// # worksheet.write(1, 0, "Enter value in cell D2:")?; + /// # + /// let data_validation = DataValidation::new().allow_date(DataValidationRule::Between( + /// ExcelDateTime::parse_from_str("2025-01-01")?, + /// ExcelDateTime::parse_from_str("2025-12-12")?, + /// )); + /// + /// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + /// # + /// # // Save the file. + /// # workbook.save("data_validation.xlsx")?; + /// # + /// # Ok(()) + /// # } + /// ``` + /// + /// The Excel Data Validation dialog for this file should look something + /// like this: + /// + /// /// pub fn allow_date( mut self, @@ -170,9 +700,24 @@ impl DataValidation { self } - /// Set the TODO + /// Set a data validation to limit input to dates using defined rules and a + /// cell reference. + /// + /// Set a data validation rule to restrict cell input to date values based + /// on [`DataValidationRule`] rules such as "between" or "less than". Excel + /// refers to this data validation type as "Date". + /// + /// The values used for the rules should be a cell reference represented by + /// a [`Formula`], see [Using cell references in Data Validations] and the + /// `allow_TYPE_formula()` examples above. + /// + /// # Parameters + /// + /// * `rule` - A [`DataValidationRule`] with cell references using + /// [`Formula`] values. See [Using cell references in Data Validations]. /// - /// TODO + /// [Using cell references in Data Validations]: + /// #using-cell-references-in-data-validations /// pub fn allow_date_formula(mut self, rule: DataValidationRule) -> DataValidation { self.rule = rule.to_internal_rule(); @@ -180,9 +725,59 @@ impl DataValidation { self } - /// Set the TODO + /// Set a data validation to limit input to time values using defined rules. + /// + /// Set a data validation rule to restrict cell input to time values based + /// on [`DataValidationRule`] rules such as "between" or "less than". Excel + /// refers to this data validation type as "Time". + /// + /// The method uses time types that implement [`IntoExcelDateTime`]. The + /// main time type supported is [`ExcelDateTime`]. If the `chrono` feature + /// is enabled you can use [`chrono::NaiveTime`]. + /// + /// [`chrono::NaiveTime`]: + /// https://docs.rs/chrono/latest/chrono/naive/struct.NaiveTime.html + /// + /// # Parameters + /// + /// * `rule` - A [`DataValidationRule`] with [`IntoExcelDateTime`] values. /// - /// TODO + /// # Examples + /// + /// Example of adding a data validation to a worksheet cell. This validation + /// restricts input to time values in a fixed range. + /// + /// ``` + /// # // This code is available in examples/doc_data_validation_allow_time.rs + /// # + /// # use rust_xlsxwriter::{DataValidation, DataValidationRule, ExcelDateTime, Workbook, XlsxError}; + /// # + /// # fn main() -> Result<(), XlsxError> { + /// # // Create a new Excel file object. + /// # let mut workbook = Workbook::new(); + /// # let worksheet = workbook.add_worksheet(); + /// # + /// # worksheet.write(1, 0, "Enter value in cell D2:")?; + /// # + /// let data_validation = DataValidation::new().allow_time(DataValidationRule::Between( + /// ExcelDateTime::parse_from_str("6:00")?, + /// ExcelDateTime::parse_from_str("12:00")?, + /// )); + /// + /// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + /// # + /// # // Save the file. + /// # workbook.save("data_validation.xlsx")?; + /// # + /// # Ok(()) + /// # } + /// ``` + /// + /// The Excel Data Validation dialog for this file should look something + /// like this: + /// + /// /// pub fn allow_time( mut self, @@ -193,9 +788,24 @@ impl DataValidation { self } - /// Set the TODO + /// Set a data validation to limit input to time values using defined rules + /// and a cell reference. + /// + /// Set a data validation rule to restrict cell input to time values based + /// on [`DataValidationRule`] rules such as "between" or "less than". Excel + /// refers to this data validation type as "Time". /// - /// TODO + /// The values used for the rules should be a cell reference represented by + /// a [`Formula`], see [Using cell references in Data Validations] and the + /// `allow_TYPE_formula()` examples above. + /// + /// # Parameters + /// + /// * `rule` - A [`DataValidationRule`] with cell references using + /// [`Formula`] values. See [Using cell references in Data Validations]. + /// + /// [Using cell references in Data Validations]: + /// #using-cell-references-in-data-validations /// pub fn allow_time_formula(mut self, rule: DataValidationRule) -> DataValidation { self.rule = rule.to_internal_rule(); @@ -203,9 +813,53 @@ impl DataValidation { self } - /// Set the TODO + /// Set a data validation to limit input to string lengths using defined + /// rules. + /// + /// Set a data validation rule to restrict cell input to string lengths + /// based on [`DataValidationRule`] rules such as "between" or "less than". + /// Excel refers to this data validation type as "Text length" but it + /// equates to any Rust type that can convert [`Into`] a [`u32`] (`u64` + /// values or strings of that length aren't supported by Excel). + /// + /// # Parameters + /// + /// * `rule` - A [`DataValidationRule`] with [`u32`] values. + /// + /// # Examples + /// + /// Example of adding a data validation to a worksheet cell. This validation + /// restricts input to strings whose lengths is in a fixed range. /// - /// TODO + /// ``` + /// # // This code is available in examples/doc_data_validation_allow_text_length.rs + /// # + /// # use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + /// # + /// # fn main() -> Result<(), XlsxError> { + /// # // Create a new Excel file object. + /// # let mut workbook = Workbook::new(); + /// # let worksheet = workbook.add_worksheet(); + /// # + /// # worksheet.write(1, 0, "Enter value in cell D2:")?; + /// # + /// let data_validation = + /// DataValidation::new().allow_text_length(DataValidationRule::Between(4, 8)); + /// + /// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + /// # + /// # // Save the file. + /// # workbook.save("data_validation.xlsx")?; + /// # + /// # Ok(()) + /// # } + /// ``` + /// + /// The Excel Data Validation dialog for this file should look something + /// like this: + /// + /// /// pub fn allow_text_length(mut self, rule: DataValidationRule) -> DataValidation { self.rule = rule.to_internal_rule(); @@ -213,9 +867,24 @@ impl DataValidation { self } - /// Set the TODO + /// Set a data validation to limit input to string lengths using defined + /// rules and a cell reference. + /// + /// Set a data validation rule to restrict cell input to string lengths + /// based on [`DataValidationRule`] rules such as "between" or "less than". + /// Excel refers to this data validation type as "Text length". + /// + /// The values used for the rules should be a cell reference represented by + /// a [`Formula`], see [Using cell references in Data Validations] and the + /// `allow_TYPE_formula()` examples above. + /// + /// # Parameters /// - /// TODO + /// * `rule` - A [`DataValidationRule`] with cell references using + /// [`Formula`] values. See [Using cell references in Data Validations]. + /// + /// [Using cell references in Data Validations]: + /// #using-cell-references-in-data-validations /// pub fn allow_text_length_formula( mut self, @@ -226,47 +895,130 @@ impl DataValidation { self } - /// Set the TODO + /// Set a data validation to limit input based on a custom formula. + /// + /// Set a data validation rule to restrict cell input based on an Excel + /// formula that returns a boolean value. Excel refers to this data + /// validation type as "Custom". + /// + /// # Parameters + /// + /// * `rule` - A [`Formula`] value. You should ensure that the formula is + /// valid in Excel. + /// + /// # Examples + /// + /// Example of adding a data validation to a worksheet cell. This validation + /// restricts input to text/strings that are uppercase. + /// + /// ``` + /// # // This code is available in examples/doc_data_validation_allow_custom.rs + /// # + /// # use rust_xlsxwriter::{DataValidation, Workbook, XlsxError}; + /// # + /// # fn main() -> Result<(), XlsxError> { + /// # // Create a new Excel file object. + /// # let mut workbook = Workbook::new(); + /// # let worksheet = workbook.add_worksheet(); + /// # + /// # worksheet.write(1, 0, "Enter uppercase string in D2:")?; + /// # + /// let data_validation = + /// DataValidation::new().allow_custom("=AND(ISTEXT(D2), EXACT(D2, UPPER(D2)))".into()); /// - /// TODO + /// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + /// # + /// # // Save the file. + /// # workbook.save("data_validation.xlsx")?; + /// # + /// # Ok(()) + /// # } + /// ``` /// - pub fn allow_custom_formula(mut self, rule: Formula) -> DataValidation { + /// The Excel Data Validation dialog for this file should look something + /// like this: + /// + /// + /// + pub fn allow_custom(mut self, rule: Formula) -> DataValidation { let formula = rule.expand_formula(true).to_string(); self.rule = DataValidationRuleInternal::CustomFormula(formula); self.validation_type = DataValidationType::Custom; self } - /// Set the TODO + /// Set a data validation to allow any input data. /// - /// TODO + /// The "Any" data validation type doesn't restrict data input and is mainly + /// used allow access to the "Input Message" dialog when a user enters data + /// in a cell. + /// + /// This is the default validation type for [`DataValidation`] if no other + /// `allow_TYPE()` method is used. Situations where this type of data + /// validation are required are uncommon. + /// + pub fn allow_any_value(mut self) -> DataValidation { + self.rule = DataValidationRuleInternal::EqualTo(String::new()); + self.validation_type = DataValidationType::Any; + self + } + + /// Set the data validation option that defines how blank cells are handled. + /// + /// By default Excel data validations have an "Ignore blank" option turned + /// on. This allows the user to optionally leave the cell blank and not + /// enter any value. This is generally the best default option since it + /// allows users to exit the cell without inputting any data. + /// + /// + /// + /// If you need to ensure that the user inserts some information then you + /// can use `ignore_blank()` to turn this option off. + /// + /// # Parameters + /// + /// * `enable` - Turn the property on/off. It is on by default. /// pub fn ignore_blank(mut self, enable: bool) -> DataValidation { self.ignore_blank = enable; self } - /// Set the TODO + /// Toggle option to show an input message when the cell is entered. /// - /// TODO + /// This function is used to toggle the option that controls whether an + /// input message is shown when a data validation cell is entered. + /// + /// The option only has an effect if there is an input message, so for the + /// majority of use cases it isn't required. + /// + /// See also [`DataValidation::set_input_message()`] below. + /// + /// # Parameters + /// + /// * `enable` - Turn the property on/off. It is on by default. /// pub fn show_input_message(mut self, enable: bool) -> DataValidation { self.show_input_message = enable; self } - /// Set the TODO + /// Set the title for the input message when the cell is entered. /// - /// TODO + /// This option is used to set a title in bold for the input message when a + /// data validation cell is entered. /// - pub fn show_error_message(mut self, enable: bool) -> DataValidation { - self.show_error_message = enable; - self - } - - /// Set the TODO + /// The title is only visible if there is also an input message. See the + /// [`DataValidation::set_input_message()`] example below. + /// + /// Note, Excel limits the title to 32 characters. /// - /// TODO + /// # Parameters + /// + /// * `text` - Title string. Must be less than or equal to the Excel limit + /// of 32 characters. /// pub fn set_input_title(mut self, text: impl Into) -> DataValidation { let text = text.into(); @@ -283,9 +1035,56 @@ impl DataValidation { self } - /// Set the TODO + /// Set the input message when a data validation cell is entered. + /// + /// This option is used to set an input message when a data validation cell + /// is entered. This can we used to explain to the user what the data + /// validation rules are for the cell. + /// + /// Note, Excel limits the message text to 255 characters. + /// + /// # Parameters + /// + /// * `text` - Message string. Must be less than or equal to the Excel limit + /// of 255 characters. The string can contain newlines to split it over + /// several lines. + /// + /// # Examples + /// + /// Example of adding a data validation to a worksheet cell. This validation + /// uses an input message to explain to the user what type of input is + /// required. + /// + /// ``` + /// # // This code is available in examples/doc_data_validation_set_input_message.rs + /// # + /// # use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + /// # + /// # fn main() -> Result<(), XlsxError> { + /// # // Create a new Excel file object. + /// # let mut workbook = Workbook::new(); + /// # let worksheet = workbook.add_worksheet(); + /// # + /// # worksheet.write(1, 0, "Enter rating in cell D2:")?; + /// # + /// let data_validation = DataValidation::new() + /// .allow_whole_number(DataValidationRule::Between(1, 5)) + /// .set_input_title("Enter a star rating!") + /// .set_input_message("Enter rating 1-5.\nWhole numbers only."); + /// + /// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + /// # + /// # // Save the file. + /// # workbook.save("data_validation.xlsx")?; + /// # + /// # Ok(()) + /// # } + /// ``` + /// + /// Output file: /// - /// TODO + /// /// pub fn set_input_message(mut self, text: impl Into) -> DataValidation { let text = text.into(); @@ -302,9 +1101,69 @@ impl DataValidation { self } - /// Set the TODO + /// Toggle option to show an error message when there is a validation error. + /// + /// This function is used to toggle the option that controls whether an + /// error message is shown when there is a validation error. + /// + /// If this option is toggled off then any data can be entered in a cell and + /// an error message will not be raised, which has limited practical + /// applications for a data validation. + /// + /// # Parameters + /// + /// * `enable` - Turn the property on/off. It is on by default. + /// + pub fn show_error_message(mut self, enable: bool) -> DataValidation { + self.show_error_message = enable; + self + } + + /// Set the title for the error message when there is a validation error. + /// + /// This option is used to set a title in bold for the error message when + /// there is a validation error. + /// + /// Note, Excel limits the title to 32 characters. + /// + /// # Parameters /// - /// TODO + /// * `text` - Title string. Must be less than or equal to the Excel limit + /// of 32 characters. + /// + /// # Examples + /// + /// Example of adding a data validation to a worksheet cell. This validation + /// shows a custom error title. + /// + /// ``` + /// # // This code is available in examples/doc_data_validation_set_error_title.rs + /// # + /// # use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + /// # + /// # fn main() -> Result<(), XlsxError> { + /// # // Create a new Excel file object. + /// # let mut workbook = Workbook::new(); + /// # let worksheet = workbook.add_worksheet(); + /// # + /// # worksheet.write(1, 0, "Enter value in cell D2:")?; + /// # + /// let data_validation = DataValidation::new() + /// .allow_whole_number(DataValidationRule::Between(1, 10)) + /// .set_error_title("Danger, Will Robinson!"); + /// + /// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + /// + /// # // Save the file. + /// # workbook.save("data_validation.xlsx")?; + /// # + /// # Ok(()) + /// # } + /// ``` + /// + /// Output file: + /// + /// /// pub fn set_error_title(mut self, text: impl Into) -> DataValidation { let text = text.into(); @@ -321,9 +1180,54 @@ impl DataValidation { self } - /// Set the TODO + /// Set the error message when a data validation cell is entered. + /// + /// This option is used to set an error message when a data validation cell + /// is entered. This can we used to explain to the user what the data + /// validation rules are for the cell. + /// + /// Note, Excel limits the message text to 255 characters. + /// + /// # Parameters + /// + /// * `text` - Message string. Must be less than or equal to the Excel limit + /// of 255 characters. The string can contain newlines to split it over + /// several lines. + /// + /// # Examples + /// + /// Example of adding a data validation to a worksheet cell. This validation + /// shows a custom error message. + /// + /// ``` + /// # // This code is available in examples/doc_data_validation_set_error_message.rs + /// # + /// # use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + /// # + /// # fn main() -> Result<(), XlsxError> { + /// # // Create a new Excel file object. + /// # let mut workbook = Workbook::new(); + /// # let worksheet = workbook.add_worksheet(); + /// # + /// # worksheet.write(1, 0, "Enter value in cell D2:")?; + /// # + /// let data_validation = DataValidation::new() + /// .allow_whole_number(DataValidationRule::Between(1, 10)) + /// .set_error_title("Value outside allowed range") + /// .set_error_message("The input value must be an integer in the range 1-10."); /// - /// TODO + /// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + /// + /// # // Save the file. + /// # workbook.save("data_validation.xlsx")?; + /// # + /// # Ok(()) + /// # } + /// ``` + /// + /// Output file: + /// + /// /// pub fn set_error_message(mut self, text: impl Into) -> DataValidation { let text = text.into(); @@ -340,42 +1244,38 @@ impl DataValidation { self } - /// Set the TODO + /// Set the style of the error dialog type for a data validation. + /// + /// Set the error dialog to be either "Stop" (the default), "Warning" or + /// "Information". This option only has an effect on Windows. /// - /// TODO + /// # Parameters + /// + /// * `error_style` - A [`DataValidationErrorStyle`] enum value. /// pub fn set_error_style(mut self, error_style: DataValidationErrorStyle) -> DataValidation { self.error_style = error_style; self } - /// Set an additional multi-cell range for the conditional format. + /// Set an additional multi-cell range for the data validation. /// - /// The `set_multi_range()` method is used to extend a conditional - /// format over non-contiguous ranges like `"B3:D6 I3:K6 B9:D12 - /// I9:K12"`. - /// - /// See [Selecting a non-contiguous - /// range](crate::conditional_format#selecting-a-non-contiguous-range) - /// for more information. + /// The `set_multi_range()` method is used to extend a data validation + /// over non-contiguous ranges like `"B3 I3 B9:D12 I9:K12"`. /// /// # Parameters /// /// * `range` - A string like type representing an Excel range. /// - /// Note, you can use an Excel range like `"$B$3:$D$6,$I$3:$K$6"` or - /// omit the `$` anchors and replace the commas with spaces to have a - /// clearer range like `"B3:D6 I3:K6"`. The documentation and examples - /// use the latter format for clarity but it you are copying and - /// pasting from Excel you can use the first format. - /// - /// Note, if the range is invalid then Excel will omit it silently. - /// pub fn set_multi_range(mut self, range: impl Into) -> DataValidation { self.multi_range = range.into().replace('$', "").replace(',', " "); self } + // ----------------------------------------------------------------------- + // Crate level helper methods. + // ----------------------------------------------------------------------- + // The "Any" validation type should be ignored if it doesn't have any input // or error titles or messages. This is the same rule as Excel. pub(crate) fn is_invalid_any(&mut self) -> bool { @@ -389,12 +1289,12 @@ impl DataValidation { /// Trait to map rust types into data validation types /// -/// The `IntoDataValidationValue` trait is used to map Rust types like -/// strings, numbers, dates, times and formulas into a generic type that can be -/// used to replicate Excel data types used in Data Validation. TODO +/// The `IntoDataValidationValue` trait is used to map Rust types like numbers, +/// dates, times and formulas into a generic type that can be used to replicate +/// Excel data types used in Data Validation. /// pub trait IntoDataValidationValue { - /// Function to turn types into a TODO enum value. + /// Function to turn types into a string value. fn to_string_value(&self) -> String; } @@ -482,41 +1382,27 @@ impl IntoDataValidationValue for &NaiveTime { } } -//#[cfg(feature = "chrono")] -//#[cfg_attr(docsrs, doc(cfg(feature = "chrono")))] -//data_validation_value_from_type!(&NaiveDate & NaiveDateTime & NaiveTime); - // ----------------------------------------------------------------------- // DataValidationType // ----------------------------------------------------------------------- -/// The `DataValidationType` enum defines TODO -/// -/// +/// The `DataValidationType` enum defines the type of data validation. #[derive(Clone, Eq, PartialEq)] -pub enum DataValidationType { - /// TODO +pub(crate) enum DataValidationType { Whole, - /// TODO Decimal, - /// TODO Date, - /// TODO Time, - /// TODO TextLength, - /// TODO Custom, - /// TODO List, - /// TODO Any, } @@ -539,34 +1425,35 @@ impl fmt::Display for DataValidationType { // DataValidationRule // ----------------------------------------------------------------------- -/// The `DataValidationRule` enum defines the conditional format rule for +/// The `DataValidationRule` enum defines the data validation rule for /// [`DataValidation`]. /// -/// #[derive(Clone)] pub enum DataValidationRule { - /// TODO. + /// Restrict cell input to values that are equal to the target value. EqualTo(T), - /// TODO. + /// Restrict cell input to values that are not equal to the target value. NotEqualTo(T), - /// TODO. + /// Restrict cell input to values that are greater than the target value. GreaterThan(T), - /// TODO. + /// Restrict cell input to values that are greater than or equal to the + /// target value. GreaterThanOrEqualTo(T), - /// TODO. + /// Restrict cell input to values that are less than the target value. LessThan(T), - /// TODO. + /// Restrict cell input to values that are less than or equal to the target + /// value. LessThanOrEqualTo(T), - /// TODO. + /// Restrict cell input to values that are between the target values. Between(T, T), - /// TODO. + /// Restrict cell input to values that are not between the target values. NotBetween(T, T), } @@ -606,7 +1493,8 @@ impl DataValidationRule { // DataValidationRuleInternal // ----------------------------------------------------------------------- -// TODO +// This is a variation on `DataValidationRule` that is used for internal storage +// of the validation rule. It only uses the String type. #[derive(Clone)] pub(crate) enum DataValidationRuleInternal { EqualTo(String), @@ -651,18 +1539,18 @@ impl fmt::Display for DataValidationRuleInternal { // DataValidationErrorStyle // ----------------------------------------------------------------------- -/// The `DataValidationErrorStyle` enum defines TODO -/// +/// The `DataValidationErrorStyle` enum defines the type of error dialog that is +/// shown when there is and error in a data validation. /// #[derive(Clone)] pub enum DataValidationErrorStyle { - /// TODO + /// Show a "Stop" dialog. This is the default. Stop, - /// TODO + /// Show a "Warning" dialog. Warning, - /// TODO + /// Show an "Information" dialog. Information, } diff --git a/src/data_validation/tests.rs b/src/data_validation/tests.rs index cf3d03ff..2455ff79 100644 --- a/src/data_validation/tests.rs +++ b/src/data_validation/tests.rs @@ -942,7 +942,7 @@ mod data_validation_tests { let mut worksheet = Worksheet::new(); worksheet.set_selected(true); - let data_validation = DataValidation::new().allow_custom_formula(Formula::new("=6")); + let data_validation = DataValidation::new().allow_custom(Formula::new("=6")); worksheet.add_data_validation(0, 0, 0, 0, &data_validation)?; @@ -981,7 +981,7 @@ mod data_validation_tests { let mut worksheet = Worksheet::new(); worksheet.set_selected(true); - let data_validation = DataValidation::new().allow_custom_formula("6".into()); + let data_validation = DataValidation::new().allow_custom("6".into()); worksheet.add_data_validation(0, 0, 0, 0, &data_validation)?; @@ -1097,6 +1097,49 @@ mod data_validation_tests { Ok(()) } + #[test] + fn data_validation_16_3() -> Result<(), XlsxError> { + let mut worksheet = Worksheet::new(); + worksheet.set_selected(true); + + let data_validation = DataValidation::new().allow_list_strings(&[ + &String::from("Foo"), + &String::from("Bar"), + &String::from("Baz"), + ])?; + + worksheet.add_data_validation(0, 0, 0, 0, &data_validation)?; + + worksheet.assemble_xml_file(); + + let got = worksheet.writer.read_to_str(); + let got = xml_to_vec(got); + + let expected = xml_to_vec( + r#" + + + + + + + + + + + "Foo,Bar,Baz" + + + + + "#, + ); + + assert_eq!(expected, got); + + Ok(()) + } + #[test] fn data_validation_17_1() -> Result<(), XlsxError> { let mut worksheet = Worksheet::new(); @@ -1450,7 +1493,7 @@ mod data_validation_tests { .allow_text_length_formula(DataValidationRule::GreaterThan("B6".into())); worksheet.add_data_validation(5, 0, 5, 0, &data_validation)?; - let data_validation = DataValidation::new().allow_custom_formula("B7".into()); + let data_validation = DataValidation::new().allow_custom("B7".into()); worksheet.add_data_validation(6, 0, 6, 0, &data_validation)?; worksheet.assemble_xml_file(); diff --git a/src/lib.rs b/src/lib.rs index 2e367f1e..1236f126 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -186,6 +186,7 @@ mod app; mod content_types; mod core; mod custom; +mod data_validation; mod datetime; mod drawing; mod error; @@ -219,7 +220,6 @@ pub mod changelog; pub mod chart; pub mod conditional_format; pub mod cookbook; -pub mod data_validation; pub mod sparkline; pub mod tutorial; pub mod utility; @@ -230,6 +230,7 @@ pub mod worksheet; mod test_functions; // Re-export the public APIs. +pub use data_validation::*; pub use datetime::*; pub use error::*; pub use filter::*; @@ -247,9 +248,6 @@ pub use chart::*; #[doc(hidden)] pub use conditional_format::*; -#[doc(hidden)] -pub use data_validation::*; - #[doc(hidden)] pub use sparkline::*; diff --git a/src/worksheet.rs b/src/worksheet.rs index 5dcc5791..e839f437 100644 --- a/src/worksheet.rs +++ b/src/worksheet.rs @@ -6422,17 +6422,15 @@ impl Worksheet { Ok(self) } - /// Add a TODO. + /// Add a data validation to one or more cells to restrict user input based + /// on types and rules. /// - /// Conditional formatting is a feature of Excel which allows you to apply a - /// format to a cell or a range of cells based on certain criteria. This is - /// generally used to highlight particular values in a range of data. - /// - /// + /// Data validation is a feature of Excel which allows you to restrict the + /// data that a user enters in a cell and to display associated help and + /// warning messages. It also allows you to restrict input to values in a + /// dropdown list. /// - /// The [`ConditionalFormat`](crate::data_validation) variants are used to represent the types of - /// conditional format that can be applied in Excel. + /// See [`DataValidation`] for more information and examples. /// /// # Errors /// @@ -6440,8 +6438,6 @@ impl Worksheet { /// worksheet limits. /// * [`XlsxError::RowColumnOrderError`] - First row larger than the last /// row. - /// * [`XlsxError::ConditionalFormatError`] - A general error that is raised - /// when a conditional formatting parameter is incorrect or missing. /// /// # Parameters /// @@ -6449,8 +6445,75 @@ impl Worksheet { /// * `first_col` - The first row of the range. /// * `last_row` - The last row of the range. /// * `last_col` - The last row of the range. - /// * `data_validation` - A conditional format instance that implements - /// the [`ConditionalFormat`] trait. TODO + /// * `data_validation` - A [`DataValidation`] data validation instance. + /// + /// # Examples + /// + /// Example of adding a data validation to a worksheet cell. This validation + /// uses an input message to explain to the user what type of input is required. + /// + /// ``` + /// # // This code is available in examples/doc_data_validation_intro1.rs + /// # + /// use rust_xlsxwriter::{DataValidation, DataValidationRule, Workbook, XlsxError}; + /// + /// fn main() -> Result<(), XlsxError> { + /// // Create a new Excel file object. + /// let mut workbook = Workbook::new(); + /// let worksheet = workbook.add_worksheet(); + /// + /// worksheet.write(1, 0, "Enter rating in cell D2:")?; + /// + /// let data_validation = DataValidation::new() + /// .allow_whole_number(DataValidationRule::Between(1, 5)) + /// .set_input_title("Enter a star rating!") + /// .set_input_message("Enter rating 1-5.\nWhole numbers only.") + /// .set_error_title("Value outside allowed range") + /// .set_error_message("The input value must be an integer in the range 1-5."); + /// + /// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + /// + /// // Save the file. + /// workbook.save("data_validation.xlsx")?; + /// + /// Ok(()) + /// } + /// ``` + /// + /// Output file: + /// + /// + /// + /// Example of adding a data validation to a worksheet cell. This validation + /// restricts users to a selection of values from a dropdown list. + /// + /// ``` + /// # // This code is available in examples/doc_data_validation_allow_list_strings.rs + /// # + /// use rust_xlsxwriter::{DataValidation, Workbook, XlsxError}; + /// + /// fn main() -> Result<(), XlsxError> { + /// // Create a new Excel file object. + /// let mut workbook = Workbook::new(); + /// let worksheet = workbook.add_worksheet(); + /// + /// worksheet.write(1, 0, "Select value in cell D2:")?; + /// + /// let data_validation = + /// DataValidation::new().allow_list_strings(&["Pass", "Fail", "Incomplete"])?; + /// + /// worksheet.add_data_validation(1, 3, 1, 3, &data_validation)?; + /// + /// // Save the file. + /// workbook.save("data_validation.xlsx")?; + /// + /// Ok(()) + /// } + /// ``` + /// + /// Output file: + /// + /// /// pub fn add_data_validation( &mut self, @@ -6486,7 +6549,6 @@ impl Worksheet { cell_range.clone_from(&data_validation.multi_range); } - self.data_validations.insert(cell_range, data_validation); Ok(self) @@ -13385,16 +13447,16 @@ impl Worksheet { DataValidationErrorStyle::Stop => {} } - match &data_validation.rule { - &DataValidationRuleInternal::Between(_, _) - | DataValidationRuleInternal::CustomFormula(_) - | DataValidationRuleInternal::ListSource(_) => { - // Excel doesn't use an operator for these types. - } - _ => { - attributes.push(("operator", data_validation.rule.to_string())); - } - }; + match &data_validation.rule { + &DataValidationRuleInternal::Between(_, _) + | DataValidationRuleInternal::CustomFormula(_) + | DataValidationRuleInternal::ListSource(_) => { + // Excel doesn't use an operator for these types. + } + _ => { + attributes.push(("operator", data_validation.rule.to_string())); + } + }; if data_validation.ignore_blank { attributes.push(("allowBlank", "1".to_string()));