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: xml::writer::EventWriter<W>,
86    ) -> xml::writer::Result<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    delegate_to_field! {
120        property =>
121        page_size(size: PageSize) -> Self,
122        page_margin(margin: PageMargin) -> Self,
123        page_orient(o: PageOrientationType) -> Self,
124        doc_grid(doc_grid: DocGrid) -> Self,
125        text_direction(direction: String) -> Self,
126        title_pg() -> Self,
127        // header(h: Header, rid: &str) -> Self,
128        // first_header(h: Header, rid: &str) -> Self,
129        // first_header_without_title_pg(h: Header, rid: &str) -> Self,
130        // even_header(h: Header, rid: &str) -> Self,
131        // footer(h: Footer, rid: &str) -> Self,
132        // first_footer(h: Footer, rid: &str) -> Self,
133        // first_footer_without_title_pg(h: Footer, rid: &str) -> Self,
134        // even_footer(h: Footer, rid: &str) -> Self,
135        page_num_type(h: PageNumType) -> Self,
136    }
137
138    pub fn add_paragraph(mut self, p: Paragraph) -> Self {
139        if p.has_numbering {
140            self.has_numbering = true
141        }
142        self.children.push(SectionChild::Paragraph(Box::new(p)));
143        self
144    }
145
146    pub fn add_table(mut self, t: Table) -> Self {
147        if t.has_numbering {
148            self.has_numbering = true
149        }
150        self.children.push(SectionChild::Table(Box::new(t)));
151        self
152    }
153
154    pub fn add_bookmark_start(mut self, id: usize, name: impl Into<String>) -> Self {
155        self.children
156            .push(SectionChild::BookmarkStart(BookmarkStart::new(id, name)));
157        self
158    }
159
160    pub fn add_bookmark_end(mut self, id: usize) -> Self {
161        self.children
162            .push(SectionChild::BookmarkEnd(BookmarkEnd::new(id)));
163        self
164    }
165
166    pub fn add_comment_start(mut self, comment: Comment) -> Self {
167        self.children.push(SectionChild::CommentStart(Box::new(
168            CommentRangeStart::new(comment),
169        )));
170        self
171    }
172
173    pub fn add_comment_end(mut self, id: usize) -> Self {
174        self.children
175            .push(SectionChild::CommentEnd(CommentRangeEnd::new(id)));
176        self
177    }
178
179    pub fn header(mut self, header: Header) -> Self {
180        self.temp_header = Some(header);
181        self
182    }
183
184    pub fn first_header(mut self, header: Header) -> Self {
185        self.temp_first_header = Some(header);
186        self
187    }
188
189    pub fn even_header(mut self, header: Header) -> Self {
190        self.temp_even_header = Some(header);
191        self
192    }
193
194    pub fn footer(mut self, footer: Footer) -> Self {
195        self.temp_footer = Some(footer);
196        self
197    }
198
199    pub fn first_footer(mut self, footer: Footer) -> Self {
200        self.temp_first_footer = Some(footer);
201        self
202    }
203
204    pub fn even_footer(mut self, footer: Footer) -> Self {
205        self.temp_even_footer = Some(footer);
206        self
207    }
208}
209
210impl Default for Section {
211    fn default() -> Self {
212        Self {
213            property: SectionProperty::new(),
214            children: vec![],
215            has_numbering: false,
216            temp_header: None,
217            temp_first_header: None,
218            temp_even_header: None,
219            temp_footer: None,
220            temp_first_footer: None,
221            temp_even_footer: None,
222        }
223    }
224}
225
226impl BuildXML for Section {
227    fn build_to<W: Write>(
228        &self,
229        stream: xml::writer::EventWriter<W>,
230    ) -> xml::writer::Result<xml::writer::EventWriter<W>> {
231        let id = crate::generate_para_id();
232        XMLBuilder::from(stream)
233            .add_children(&self.children)?
234            .open_paragraph(&id)?
235            .open_paragraph_property()?
236            .add_child(&self.property)?
237            .close()?
238            .close()?
239            .into_inner()
240    }
241}
242
243#[cfg(test)]
244mod tests {
245
246    use super::*;
247    #[cfg(test)]
248    use pretty_assertions::assert_eq;
249    use std::str;
250
251    #[test]
252    fn test_section_property_default() {
253        let c = Section::new();
254        let b = c.build();
255        assert_eq!(
256            str::from_utf8(&b).unwrap(),
257            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>"#
258        );
259    }
260
261    #[test]
262    fn test_section_with_paragraph() {
263        let c =
264            Section::new().add_paragraph(Paragraph::new().add_run(Run::new().add_text("Hello")));
265        let b = c.build();
266        assert_eq!(
267            str::from_utf8(&b).unwrap(),
268            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>"#
269        );
270    }
271}