Skip to main content

docx_rs/documents/elements/
section.rs

1use super::*;
2// use crate::create_header_rid;
3use crate::documents::BuildXML;
4use crate::types::*;
5use crate::xml_builder::*;
6use crate::Footer;
7use crate::{delegate_to_field, Header};
8use serde::ser::{SerializeStruct, Serializer};
9use serde::Serialize;
10use std::io::Write;
11
12#[derive(Debug, Clone, PartialEq)]
13pub enum SectionChild {
14    Paragraph(Box<Paragraph>),
15    Table(Box<Table>),
16    BookmarkStart(BookmarkStart),
17    BookmarkEnd(BookmarkEnd),
18    CommentStart(Box<CommentRangeStart>),
19    CommentEnd(CommentRangeEnd),
20    StructuredDataTag(Box<StructuredDataTag>),
21    TableOfContents(Box<TableOfContents>),
22}
23
24impl Serialize for SectionChild {
25    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
26    where
27        S: Serializer,
28    {
29        match *self {
30            SectionChild::Paragraph(ref p) => {
31                let mut t = serializer.serialize_struct("Paragraph", 2)?;
32                t.serialize_field("type", "paragraph")?;
33                t.serialize_field("data", p)?;
34                t.end()
35            }
36            SectionChild::Table(ref c) => {
37                let mut t = serializer.serialize_struct("Table", 2)?;
38                t.serialize_field("type", "table")?;
39                t.serialize_field("data", c)?;
40                t.end()
41            }
42            SectionChild::BookmarkStart(ref c) => {
43                let mut t = serializer.serialize_struct("BookmarkStart", 2)?;
44                t.serialize_field("type", "bookmarkStart")?;
45                t.serialize_field("data", c)?;
46                t.end()
47            }
48            SectionChild::BookmarkEnd(ref c) => {
49                let mut t = serializer.serialize_struct("BookmarkEnd", 2)?;
50                t.serialize_field("type", "bookmarkEnd")?;
51                t.serialize_field("data", c)?;
52                t.end()
53            }
54            SectionChild::CommentStart(ref r) => {
55                let mut t = serializer.serialize_struct("CommentRangeStart", 2)?;
56                t.serialize_field("type", "commentRangeStart")?;
57                t.serialize_field("data", r)?;
58                t.end()
59            }
60            SectionChild::CommentEnd(ref r) => {
61                let mut t = serializer.serialize_struct("CommentRangeEnd", 2)?;
62                t.serialize_field("type", "commentRangeEnd")?;
63                t.serialize_field("data", r)?;
64                t.end()
65            }
66            SectionChild::StructuredDataTag(ref r) => {
67                let mut t = serializer.serialize_struct("StructuredDataTag", 2)?;
68                t.serialize_field("type", "structuredDataTag")?;
69                t.serialize_field("data", r)?;
70                t.end()
71            }
72            SectionChild::TableOfContents(ref r) => {
73                let mut t = serializer.serialize_struct("TableOfContents", 2)?;
74                t.serialize_field("type", "tableOfContents")?;
75                t.serialize_field("data", r)?;
76                t.end()
77            }
78        }
79    }
80}
81
82impl BuildXML for SectionChild {
83    fn build_to<W: Write>(
84        &self,
85        stream: crate::xml::writer::EventWriter<W>,
86    ) -> crate::xml::writer::Result<crate::xml::writer::EventWriter<W>> {
87        match self {
88            SectionChild::Paragraph(v) => v.build_to(stream),
89            SectionChild::Table(v) => v.build_to(stream),
90            SectionChild::BookmarkStart(v) => v.build_to(stream),
91            SectionChild::BookmarkEnd(v) => v.build_to(stream),
92            SectionChild::CommentStart(v) => v.build_to(stream),
93            SectionChild::CommentEnd(v) => v.build_to(stream),
94            SectionChild::StructuredDataTag(v) => v.build_to(stream),
95            SectionChild::TableOfContents(v) => v.build_to(stream),
96        }
97    }
98}
99
100#[derive(Debug, Clone, PartialEq, Serialize)]
101#[serde(rename_all = "camelCase")]
102pub struct Section {
103    pub(crate) property: SectionProperty,
104    pub(crate) children: Vec<SectionChild>,
105    pub(crate) has_numbering: bool,
106    pub(crate) temp_header: Option<Header>,
107    pub(crate) temp_first_header: Option<Header>,
108    pub(crate) temp_even_header: Option<Header>,
109    pub(crate) temp_footer: Option<Footer>,
110    pub(crate) temp_first_footer: Option<Footer>,
111    pub(crate) temp_even_footer: Option<Footer>,
112}
113
114impl Section {
115    pub fn new() -> Section {
116        Default::default()
117    }
118
119    pub fn children(&self) -> &Vec<SectionChild> {
120        &self.children
121    }
122
123    delegate_to_field! {
124        property =>
125        page_size(size: PageSize) -> Self,
126        page_margin(margin: PageMargin) -> Self,
127        page_orient(o: PageOrientationType) -> Self,
128        doc_grid(doc_grid: DocGrid) -> Self,
129        text_direction(direction: String) -> Self,
130        title_pg() -> Self,
131        // header(h: Header, rid: &str) -> Self,
132        // first_header(h: Header, rid: &str) -> Self,
133        // first_header_without_title_pg(h: Header, rid: &str) -> Self,
134        // even_header(h: Header, rid: &str) -> Self,
135        // footer(h: Footer, rid: &str) -> Self,
136        // first_footer(h: Footer, rid: &str) -> Self,
137        // first_footer_without_title_pg(h: Footer, rid: &str) -> Self,
138        // even_footer(h: Footer, rid: &str) -> Self,
139        page_num_type(h: PageNumType) -> Self,
140    }
141
142    pub fn add_paragraph(mut self, p: Paragraph) -> Self {
143        if p.has_numbering {
144            self.has_numbering = true
145        }
146        self.children.push(SectionChild::Paragraph(Box::new(p)));
147        self
148    }
149
150    pub fn add_table(mut self, t: Table) -> Self {
151        if t.has_numbering {
152            self.has_numbering = true
153        }
154        self.children.push(SectionChild::Table(Box::new(t)));
155        self
156    }
157
158    pub fn add_bookmark_start(mut self, id: usize, name: impl Into<String>) -> Self {
159        self.children
160            .push(SectionChild::BookmarkStart(BookmarkStart::new(id, name)));
161        self
162    }
163
164    pub fn add_bookmark_end(mut self, id: usize) -> Self {
165        self.children
166            .push(SectionChild::BookmarkEnd(BookmarkEnd::new(id)));
167        self
168    }
169
170    pub fn add_comment_start(mut self, comment: Comment) -> Self {
171        self.children.push(SectionChild::CommentStart(Box::new(
172            CommentRangeStart::new(comment),
173        )));
174        self
175    }
176
177    pub fn add_comment_end(mut self, id: usize) -> Self {
178        self.children
179            .push(SectionChild::CommentEnd(CommentRangeEnd::new(id)));
180        self
181    }
182
183    pub fn header(mut self, header: Header) -> Self {
184        self.temp_header = Some(header);
185        self
186    }
187
188    pub fn first_header(mut self, header: Header) -> Self {
189        self.temp_first_header = Some(header);
190        self
191    }
192
193    pub fn even_header(mut self, header: Header) -> Self {
194        self.temp_even_header = Some(header);
195        self
196    }
197
198    pub fn footer(mut self, footer: Footer) -> Self {
199        self.temp_footer = Some(footer);
200        self
201    }
202
203    pub fn first_footer(mut self, footer: Footer) -> Self {
204        self.temp_first_footer = Some(footer);
205        self
206    }
207
208    pub fn even_footer(mut self, footer: Footer) -> Self {
209        self.temp_even_footer = Some(footer);
210        self
211    }
212}
213
214impl Default for Section {
215    fn default() -> Self {
216        Self {
217            property: SectionProperty::new(),
218            children: vec![],
219            has_numbering: false,
220            temp_header: None,
221            temp_first_header: None,
222            temp_even_header: None,
223            temp_footer: None,
224            temp_first_footer: None,
225            temp_even_footer: None,
226        }
227    }
228}
229
230impl BuildXML for Section {
231    fn build_to<W: Write>(
232        &self,
233        stream: crate::xml::writer::EventWriter<W>,
234    ) -> crate::xml::writer::Result<crate::xml::writer::EventWriter<W>> {
235        let id = crate::generate_para_id();
236        XMLBuilder::from(stream)
237            .add_children(&self.children)?
238            .open_paragraph(&id)?
239            .open_paragraph_property()?
240            .add_child(&self.property)?
241            .close()?
242            .close()?
243            .into_inner()
244    }
245}
246
247#[cfg(test)]
248mod tests {
249
250    use super::*;
251    #[cfg(test)]
252    use pretty_assertions::assert_eq;
253    use std::str;
254
255    #[test]
256    fn test_section_property_default() {
257        let c = Section::new();
258        let b = c.build();
259        assert_eq!(
260            str::from_utf8(&b).unwrap(),
261            r#"<w:p w14:paraId="12345678"><w:pPr><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></w:pPr></w:p>"#
262        );
263    }
264
265    #[test]
266    fn test_section_with_paragraph() {
267        let c =
268            Section::new().add_paragraph(Paragraph::new().add_run(Run::new().add_text("Hello")));
269        let b = c.build();
270        assert_eq!(
271            str::from_utf8(&b).unwrap(),
272            r#"<w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r></w:p><w:p w14:paraId="12345678"><w:pPr><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></w:pPr></w:p>"#
273        );
274    }
275}