docx_rs/documents/elements/
level.rs

1use crate::documents::*;
2use crate::types::*;
3use crate::xml_builder::*;
4use std::io::Write;
5
6use serde::Serialize;
7
8#[derive(Debug, Clone, PartialEq, Serialize)]
9#[serde(rename_all = "camelCase")]
10pub struct Level {
11    pub level: usize,
12    pub start: Start,
13    pub format: NumberFormat,
14    pub text: LevelText,
15    pub jc: LevelJc,
16    pub paragraph_property: ParagraphProperty,
17    pub run_property: RunProperty,
18    pub suffix: LevelSuffixType,
19    pub pstyle: Option<ParagraphStyle>,
20    pub level_restart: Option<LevelRestart>,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub is_lgl: Option<IsLgl>,
23}
24
25impl Level {
26    pub fn new(
27        level: usize,
28        start: Start,
29        format: NumberFormat,
30        text: LevelText,
31        jc: LevelJc,
32    ) -> Level {
33        Self {
34            level,
35            start,
36            format,
37            text,
38            jc,
39            paragraph_property: ParagraphProperty::new(),
40            run_property: RunProperty::new(),
41            suffix: LevelSuffixType::Tab,
42            pstyle: None,
43            level_restart: None,
44            is_lgl: None,
45        }
46    }
47
48    pub fn indent(
49        mut self,
50        left: Option<i32>,
51        special_indent: Option<SpecialIndentType>,
52        end: Option<i32>,
53        start_chars: Option<i32>,
54    ) -> Self {
55        self.paragraph_property =
56            self.paragraph_property
57                .indent(left, special_indent, end, start_chars);
58        self
59    }
60
61    pub fn paragraph_style(mut self, style_id: impl Into<String>) -> Self {
62        self.pstyle = Some(ParagraphStyle::new(Some(style_id.into())));
63        self
64    }
65
66    pub fn suffix(mut self, s: LevelSuffixType) -> Self {
67        self.suffix = s;
68        self
69    }
70
71    // run property
72    pub fn size(mut self, size: usize) -> Self {
73        self.run_property = self.run_property.size(size);
74        self
75    }
76
77    pub fn spacing(mut self, v: i32) -> Self {
78        self.run_property = self.run_property.spacing(v);
79        self
80    }
81
82    pub fn color(mut self, color: impl Into<String>) -> Self {
83        self.run_property = self.run_property.color(color);
84        self
85    }
86
87    pub fn highlight(mut self, color: impl Into<String>) -> Self {
88        self.run_property = self.run_property.highlight(color);
89        self
90    }
91
92    pub fn bold(mut self) -> Self {
93        self.run_property = self.run_property.bold();
94        self
95    }
96
97    pub fn disable_bold(mut self) -> Self {
98        self.run_property = self.run_property.disable_bold();
99        self
100    }
101
102    pub fn italic(mut self) -> Self {
103        self.run_property = self.run_property.italic();
104        self
105    }
106
107    pub fn disable_italic(mut self) -> Self {
108        self.run_property = self.run_property.disable_italic();
109        self
110    }
111
112    pub fn strike(mut self) -> Self {
113        self.run_property = self.run_property.strike();
114        self
115    }
116
117    pub fn disable_strike(mut self) -> Self {
118        self.run_property = self.run_property.disable_strike();
119        self
120    }
121
122    pub fn dstrike(mut self) -> Self {
123        self.run_property = self.run_property.dstrike();
124        self
125    }
126
127    pub fn disable_dstrike(mut self) -> Self {
128        self.run_property = self.run_property.disable_dstrike();
129        self
130    }
131
132    pub fn underline(mut self, line_type: impl Into<String>) -> Self {
133        self.run_property = self.run_property.underline(line_type);
134        self
135    }
136
137    pub fn vanish(mut self) -> Self {
138        self.run_property = self.run_property.vanish();
139        self
140    }
141
142    pub fn fonts(mut self, f: RunFonts) -> Self {
143        self.run_property = self.run_property.fonts(f);
144        self
145    }
146
147    pub fn level_restart(mut self, v: u32) -> Self {
148        self.level_restart = Some(LevelRestart::new(v));
149        self
150    }
151
152    pub fn is_lgl(mut self) -> Self {
153        self.is_lgl = Some(IsLgl::new());
154        self
155    }
156}
157
158impl BuildXML for Level {
159    fn build_to<W: Write>(
160        &self,
161        stream: xml::writer::EventWriter<W>,
162    ) -> xml::writer::Result<xml::writer::EventWriter<W>> {
163        XMLBuilder::from(stream)
164            .open_level(&format!("{}", self.level))?
165            .add_child(&self.start)?
166            .add_child(&self.format)?
167            .add_child(&self.text)?
168            .add_child(&self.jc)?
169            .add_child(&self.paragraph_property)?
170            .add_child(&self.run_property)?
171            .add_optional_child(&self.pstyle)?
172            .add_optional_child(&self.level_restart)?
173            .add_optional_child(&self.is_lgl)?
174            .apply_if(self.suffix != LevelSuffixType::Tab, |b| {
175                b.suffix(&self.suffix.to_string())
176            })?
177            .close()?
178            .into_inner()
179    }
180}
181
182#[cfg(test)]
183mod tests {
184
185    use super::*;
186    #[cfg(test)]
187    use pretty_assertions::assert_eq;
188    use std::str;
189
190    #[test]
191    fn test_level() {
192        let b = Level::new(
193            1,
194            Start::new(1),
195            NumberFormat::new("decimal"),
196            LevelText::new("%4."),
197            LevelJc::new("left"),
198        )
199        .build();
200        assert_eq!(
201            str::from_utf8(&b).unwrap(),
202            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>"#
203        );
204    }
205
206    #[test]
207    fn test_level_indent() {
208        let b = Level::new(
209            1,
210            Start::new(1),
211            NumberFormat::new("decimal"),
212            LevelText::new("%4."),
213            LevelJc::new("left"),
214        )
215        .indent(Some(320), Some(SpecialIndentType::Hanging(200)), None, None)
216        .build();
217        assert_eq!(
218            str::from_utf8(&b).unwrap(),
219            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>"#
220        );
221    }
222    #[test]
223    fn test_level_with_suff() {
224        let b = Level::new(
225            1,
226            Start::new(1),
227            NumberFormat::new("decimal"),
228            LevelText::new("%4."),
229            LevelJc::new("left"),
230        )
231        .suffix(LevelSuffixType::Space)
232        .build();
233        assert_eq!(
234            str::from_utf8(&b).unwrap(),
235            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" /></w:lvl>"#
236        );
237    }
238    #[test]
239    fn test_level_with_pstyle() {
240        let b = Level::new(
241            1,
242            Start::new(1),
243            NumberFormat::new("decimal"),
244            LevelText::new("%4."),
245            LevelJc::new("left"),
246        )
247        .paragraph_style("a-style")
248        .build();
249        assert_eq!(
250            str::from_utf8(&b).unwrap(),
251            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:pStyle w:val="a-style" /></w:lvl>"#
252        );
253    }
254}