Skip to main content

xlsx_protection/
xlsx_protection.rs

1//! Excel protection: sheet (cell-editing) protection, workbook structure
2//! protection, write-protection ("read-only recommended"), and a named
3//! protected range that stays editable inside an otherwise locked sheet.
4//! One tab per feature.
5//!
6//! Run with: `cargo run -p office-toolkit --example xlsx_protection`
7
8use std::path::{Path, PathBuf};
9
10use office_toolkit::SaveToFile;
11use office_toolkit::excel::{
12    ProtectedRange, Sheet, SheetProtection, WorkbookProtection, WriteProtection,
13};
14use office_toolkit::prelude::*;
15
16fn main() -> office_toolkit::Result<()> {
17    let path = output_path("xlsx_protection.xlsx");
18
19    let sheet_protection_sheet = Sheet::new("Sheet protection")
20        .with_row(Row::new().with_text("Locked: this sheet is protected with a password."))
21        .with_protection(SheetProtection::with_password("secret"));
22
23    let protected_range_sheet = Sheet::new("Protected range")
24        .with_row(
25            Row::new()
26                .with_text("A1 is protected; B1 stays editable via a named unprotected range."),
27        )
28        .with_protection(SheetProtection::locked())
29        .with_protected_range(ProtectedRange::new("EditableArea", "B1:B1").with_password("secret"));
30
31    let workbook = Workbook::new()
32        .with_write_protection(
33            WriteProtection::recommended()
34                .with_user_name("Author")
35                .with_password("secret"),
36        )
37        .with_sheet(sheet_protection_sheet)
38        .with_sheet(protected_range_sheet);
39
40    // `Workbook.protection` (structure protection: locking sheet
41    // add/rename/hide/reorder/delete) has no `with_*` builder — it's set
42    // directly, like any other public field.
43    let workbook = Workbook {
44        protection: Some(WorkbookProtection::locked().with_lock_windows(true)),
45        ..workbook
46    };
47
48    workbook.save_to_file(&path)?;
49    println!("Wrote {}", path.display());
50    Ok(())
51}
52
53/// Every example in this directory writes its output under
54/// `tests-data/output/`, resolved relative to this crate's own manifest so
55/// it works no matter what directory `cargo run` was invoked from.
56fn output_path(filename: &str) -> PathBuf {
57    Path::new(env!("CARGO_MANIFEST_DIR"))
58        .join("../../tests-data/output")
59        .join(filename)
60}