docx_rs/documents/elements/
level.rs

1use crate::documents::*;
2use crate::types::*;
3use crate::xml_builder::*;
4
5use serde::Serialize;
6
7#[derive(Debug, Clone, PartialEq, Serialize)]
8#[serde(rename_all = "camelCase")]
9pub struct Level {
10    pub level: usize,
11    pub start: Start,
12    pub format: NumberFormat,
13    pub text: LevelText,
14    pub jc: LevelJc,
15    pub paragraph_property: ParagraphProperty,
16    pub run_property: RunProperty,
17    pub suffix: LevelSuffixType,
18    pub pstyle: Option<String>,
19    pub level_restart: Option<LevelRestart>,
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub is_lgl: Option<IsLgl>,
22}
23
24impl Level {
25    pub fn new(
26        level: usize,
27        start: Start,
28        format: NumberFormat,
29        text: LevelText,
30        jc: LevelJc,
31    ) -> Level {
32        Self {
33            level,
34            start,
35            format,
36            text,
37            jc,
38            paragraph_property: ParagraphProperty::new(),
39            run_property: RunProperty::new(),
40            suffix: LevelSuffixType::Tab,
41            pstyle: None,
42            level_restart: None,
43            is_lgl: None,
44        }
45    }
46
47    pub fn indent(
48        mut self,
49        left: Option<i32>,
50        special_indent: Option<SpecialIndentType>,
51        end: Option<i32>,
52        start_chars: Option<i32>,
53    ) -> Self {
54        self.paragraph_property =
55            self.paragraph_property
56                .indent(left, special_indent, end, start_chars);
57        self
58    }
59
60    pub fn paragraph_style(mut self, style_id: impl Into<String>) -> Self {
61        self.pstyle = Some(style_id.into());
62        self
63    }
64
65    pub fn suffix(mut self, s: LevelSuffixType) -> Self {
66        self.suffix = s;
67        self
68    }
69
70    // run property
71    pub fn size(mut self, size: usize) -> Self {
72        self.run_property = self.run_property.size(size);
73        self
74    }
75
76    pub fn spacing(mut self, v: i32) -> Self {
77        self.run_property = self.run_property.spacing(v);
78        self
79    }
80
81    pub fn color(mut self, color: impl Into<String>) -> Self {
82        self.run_property = self.run_property.color(color);
83        self
84    }
85
86    pub fn highlight(mut self, color: impl Into<String>) -> Self {
87        self.run_property = self.run_property.highlight(color);
88        self
89    }
90
91    pub fn bold(mut self) -> Self {
92        self.run_property = self.run_property.bold();
93        self
94    }
95
96    pub fn italic(mut self) -> Self {
97        self.run_property = self.run_property.italic();
98        self
99    }
100
101    pub fn underline(mut self, line_type: impl Into<String>) -> Self {
102        self.run_property = self.run_property.underline(line_type);
103        self
104    }
105
106    pub fn vanish(mut self) -> Self {
107        self.run_property = self.run_property.vanish();
108        self
109    }
110
111    pub fn fonts(mut self, f: RunFonts) -> Self {
112        self.run_property = self.run_property.fonts(f);
113        self
114    }
115
116    pub fn level_restart(mut self, v: u32) -> Self {
117        self.level_restart = Some(LevelRestart::new(v));
118        self
119    }
120
121    pub fn is_lgl(mut self) -> Self {
122        self.is_lgl = Some(IsLgl::new());
123        self
124    }
125}
126
127impl BuildXML for Level {
128    fn build(&self) -> Vec<u8> {
129        let mut b = XMLBuilder::new()
130            .open_level(&format!("{}", self.level))
131            .add_child(&self.start)
132            .add_child(&self.format)
133            .add_child(&self.text)
134            .add_child(&self.jc)
135            .add_child(&self.paragraph_property)
136            .add_child(&self.run_property)
137            .add_optional_child(&self.level_restart)
138            .add_optional_child(&self.is_lgl);
139
140        if self.suffix != LevelSuffixType::Tab {
141            b = b.suffix(&self.suffix.to_string());
142        }
143
144        b.close().build()
145    }
146}
147
148#[cfg(test)]
149mod tests {
150
151    use super::*;
152    #[cfg(test)]
153    use pretty_assertions::assert_eq;
154    use std::str;
155
156    #[test]
157    fn test_level() {
158        let b = Level::new(
159            1,
160            Start::new(1),
161            NumberFormat::new("decimal"),
162            LevelText::new("%4."),
163            LevelJc::new("left"),
164        )
165        .build();
166        assert_eq!(
167            str::from_utf8(&b).unwrap(),
168            r#"<w:lvl w:ilvl="1"><w:start w:val="1" /><w:numFmt w:val="decimal" /><w:lvlText w:val="%4." /><w:lvlJc w:val="left" /><w:pPr><w:rPr /></w:pPr><w:rPr /></w:lvl>"#
169        );
170    }
171
172    #[test]
173    fn test_level_indent() {
174        let b = Level::new(
175            1,
176            Start::new(1),
177            NumberFormat::new("decimal"),
178            LevelText::new("%4."),
179            LevelJc::new("left"),
180        )
181        .indent(Some(320), Some(SpecialIndentType::Hanging(200)), None, None)
182        .build();
183        assert_eq!(
184            str::from_utf8(&b).unwrap(),
185            r#"<w:lvl w:ilvl="1"><w:start w:val="1" /><w:numFmt w:val="decimal" /><w:lvlText w:val="%4." /><w:lvlJc w:val="left" /><w:pPr><w:rPr /><w:ind w:left="320" w:right="0" w:hanging="200" /></w:pPr><w:rPr /></w:lvl>"#
186        );
187    }
188    #[test]
189    fn test_level_with_suff() {
190        let b = Level::new(
191            1,
192            Start::new(1),
193            NumberFormat::new("decimal"),
194            LevelText::new("%4."),
195            LevelJc::new("left"),
196        )
197        .suffix(LevelSuffixType::Space)
198        .build();
199        assert_eq!(
200            str::from_utf8(&b).unwrap(),
201            r#"<w:lvl w:ilvl="1"><w:start w:val="1" /><w:numFmt w:val="decimal" /><w:lvlText w:val="%4." /><w:lvlJc w:val="left" /><w:pPr><w:rPr /></w:pPr><w:rPr /><w:suff w:val="space" />
202</w:lvl>"#
203        );
204    }
205}