docx_rs/documents/elements/
section_property.rs

1use super::*;
2use crate::documents::BuildXML;
3use crate::types::*;
4use crate::xml_builder::*;
5use crate::{Footer, Header};
6use std::io::Write;
7
8use serde::Serialize;
9
10#[derive(Debug, Clone, PartialEq, Serialize)]
11#[serde(rename_all = "camelCase")]
12pub struct SectionProperty {
13    pub page_size: PageSize,
14    pub page_margin: PageMargin,
15    pub columns: usize,
16    pub space: usize,
17    pub title_pg: bool,
18    pub text_direction: String,
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub doc_grid: Option<DocGrid>,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub header_reference: Option<HeaderReference>,
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub header: Option<Header>,
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub first_header_reference: Option<HeaderReference>,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub first_header: Option<Header>,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub even_header_reference: Option<HeaderReference>,
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub even_header: Option<Header>,
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub footer_reference: Option<FooterReference>,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub footer: Option<Footer>,
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub first_footer_reference: Option<FooterReference>,
39    #[serde(skip_serializing_if = "Option::is_none")]
40    pub first_footer: Option<Footer>,
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub even_footer_reference: Option<FooterReference>,
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub even_footer: Option<Footer>,
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub section_type: Option<SectionType>,
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub page_num_type: Option<PageNumType>,
49}
50
51impl SectionProperty {
52    pub fn new() -> SectionProperty {
53        Default::default()
54    }
55
56    pub fn page_size(mut self, size: PageSize) -> Self {
57        self.page_size = size;
58        self
59    }
60
61    pub fn page_margin(mut self, margin: PageMargin) -> Self {
62        self.page_margin = margin;
63        self
64    }
65
66    pub fn page_orient(mut self, o: PageOrientationType) -> Self {
67        self.page_size = self.page_size.orient(o);
68        self
69    }
70
71    pub fn doc_grid(mut self, doc_grid: DocGrid) -> Self {
72        self.doc_grid = Some(doc_grid);
73        self
74    }
75
76    pub fn text_direction(mut self, direction: String) -> Self {
77        self.text_direction = direction;
78        self
79    }
80
81    pub fn title_pg(mut self) -> Self {
82        self.title_pg = true;
83        self
84    }
85
86    pub fn header(mut self, h: Header, rid: &str) -> Self {
87        self.header_reference = Some(HeaderReference::new("default", rid));
88        self.header = Some(h);
89        self
90    }
91
92    pub fn first_header(mut self, h: Header, rid: &str) -> Self {
93        self.first_header_reference = Some(HeaderReference::new("first", rid));
94        self.first_header = Some(h);
95        self.title_pg = true;
96        self
97    }
98
99    pub fn first_header_without_title_pg(mut self, h: Header, rid: &str) -> Self {
100        self.first_header_reference = Some(HeaderReference::new("first", rid));
101        self.first_header = Some(h);
102        self
103    }
104
105    pub fn even_header(mut self, h: Header, rid: &str) -> Self {
106        self.even_header_reference = Some(HeaderReference::new("even", rid));
107        self.even_header = Some(h);
108        self
109    }
110
111    pub fn footer(mut self, h: Footer, rid: &str) -> Self {
112        self.footer_reference = Some(FooterReference::new("default", rid));
113        self.footer = Some(h);
114        self
115    }
116
117    pub fn first_footer(mut self, h: Footer, rid: &str) -> Self {
118        self.first_footer_reference = Some(FooterReference::new("first", rid));
119        self.first_footer = Some(h);
120        self.title_pg = true;
121        self
122    }
123
124    pub fn first_footer_without_title_pg(mut self, h: Footer, rid: &str) -> Self {
125        self.first_footer_reference = Some(FooterReference::new("first", rid));
126        self.first_footer = Some(h);
127        self
128    }
129
130    pub fn even_footer(mut self, h: Footer, rid: &str) -> Self {
131        self.even_footer_reference = Some(FooterReference::new("even", rid));
132        self.even_footer = Some(h);
133        self
134    }
135
136    pub fn get_headers(&self) -> Vec<&Header> {
137        let mut headers = vec![];
138        if let Some(ref header) = self.header {
139            headers.push(header);
140        }
141        if let Some(ref header) = self.first_header {
142            headers.push(header);
143        }
144        if let Some(ref header) = self.even_header {
145            headers.push(header);
146        }
147        headers
148    }
149
150    pub fn get_footers(&self) -> Vec<&Footer> {
151        let mut footers = vec![];
152        if let Some(ref footer) = self.footer {
153            footers.push(footer);
154        }
155        if let Some(ref footer) = self.first_footer {
156            footers.push(footer);
157        }
158        if let Some(ref footer) = self.even_footer {
159            footers.push(footer);
160        }
161        footers
162    }
163
164    pub fn page_num_type(mut self, h: PageNumType) -> Self {
165        self.page_num_type = Some(h);
166        self
167    }
168}
169
170impl Default for SectionProperty {
171    fn default() -> Self {
172        Self {
173            page_size: PageSize::new(),
174            page_margin: PageMargin::new(),
175            columns: 1,
176            space: 425,
177            title_pg: false,
178            text_direction: "lrTb".to_string(),
179            doc_grid: None,
180            // headers
181            header_reference: None,
182            header: None,
183            first_header_reference: None,
184            first_header: None,
185            even_header_reference: None,
186            even_header: None,
187            // footers
188            footer_reference: None,
189            footer: None,
190            first_footer_reference: None,
191            first_footer: None,
192            even_footer_reference: None,
193            even_footer: None,
194            section_type: None,
195            page_num_type: None,
196        }
197    }
198}
199
200impl BuildXML for SectionProperty {
201    fn build_to<W: Write>(
202        &self,
203        stream: xml::writer::EventWriter<W>,
204    ) -> xml::writer::Result<xml::writer::EventWriter<W>> {
205        XMLBuilder::from(stream)
206            .open_section_property()?
207            .add_child(&self.page_size)?
208            .add_child(&self.page_margin)?
209            .columns(&format!("{}", &self.space), &format!("{}", &self.columns))?
210            .add_optional_child(&self.doc_grid)?
211            .add_optional_child(&self.header_reference)?
212            .add_optional_child(&self.first_header_reference)?
213            .add_optional_child(&self.even_header_reference)?
214            .add_optional_child(&self.footer_reference)?
215            .add_optional_child(&self.first_footer_reference)?
216            .add_optional_child(&self.even_footer_reference)?
217            .add_optional_child(&self.page_num_type)?
218            .apply_if(self.text_direction != "lrTb", |b| {
219                b.text_direction(&self.text_direction)
220            })?
221            .apply_opt(self.section_type, |t, b| b.type_tag(&t.to_string()))?
222            .apply_if(self.title_pg, |b| b.title_pg())?
223            .close()?
224            .into_inner()
225    }
226}
227
228#[cfg(test)]
229mod tests {
230
231    use super::*;
232    #[cfg(test)]
233    use pretty_assertions::assert_eq;
234    use std::str;
235
236    #[test]
237    fn text_section_text_direction() {
238        let mut c = SectionProperty::new();
239        c = c.text_direction("tbRl".to_string());
240        let b = c.build();
241        assert_eq!(
242            str::from_utf8(&b).unwrap(),
243            r#"<w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="1" /><w:textDirection w:val="tbRl" /></w:sectPr>"#
244        )
245    }
246
247    #[test]
248    fn test_section_property_default() {
249        let c = SectionProperty::new();
250        let b = c.build();
251        assert_eq!(
252            str::from_utf8(&b).unwrap(),
253            r#"<w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="1" /></w:sectPr>"#
254        );
255    }
256
257    #[test]
258    fn test_section_property_with_footer() {
259        let c = SectionProperty::new().footer(Footer::new(), "rId6");
260        let b = c.build();
261        assert_eq!(
262            str::from_utf8(&b).unwrap(),
263            r#"<w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="1" /><w:footerReference w:type="default" r:id="rId6" /></w:sectPr>"#
264        );
265    }
266
267    #[test]
268    fn test_section_property_with_title_pf() {
269        let c = SectionProperty::new().title_pg();
270        let b = c.build();
271        assert_eq!(
272            str::from_utf8(&b).unwrap(),
273            r#"<w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:cols w:space="425" w:num="1" /><w:titlePg /></w:sectPr>"#
274        );
275    }
276}