docx_rs/documents/elements/
section.rs1use super::*;
2use 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 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}