docx_rs/documents/elements/
run_property.rs

1use serde::Serialize;
2use std::io::Write;
3
4use super::*;
5use crate::documents::BuildXML;
6use crate::types::*;
7use crate::xml_builder::*;
8
9#[derive(Debug, Clone, Serialize, PartialEq, Default)]
10#[serde(rename_all = "camelCase")]
11pub struct RunProperty {
12    #[serde(skip_serializing_if = "Option::is_none")]
13    pub style: Option<RunStyle>,
14    #[serde(skip_serializing_if = "Option::is_none")]
15    pub sz: Option<Sz>,
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub sz_cs: Option<SzCs>,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub color: Option<Color>,
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub highlight: Option<Highlight>,
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub vert_align: Option<VertAlign>,
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub underline: Option<Underline>,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub bold: Option<Bold>,
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub bold_cs: Option<BoldCs>,
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub caps: Option<Caps>,
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub italic: Option<Italic>,
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub italic_cs: Option<ItalicCs>,
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub vanish: Option<Vanish>,
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub spec_vanish: Option<SpecVanish>,
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub character_spacing: Option<CharacterSpacing>,
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub stretch: Option<Stretch>,
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub fonts: Option<RunFonts>,
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub text_border: Option<TextBorder>,
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub del: Option<Delete>,
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub ins: Option<Insert>,
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub strike: Option<Strike>,
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub dstrike: Option<Dstrike>,
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub positional_tab: Option<PositionalTab>,
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub shading: Option<Shading>,
60}
61
62impl RunProperty {
63    pub fn new() -> RunProperty {
64        Default::default()
65    }
66
67    pub fn style(mut self, style_id: &str) -> Self {
68        self.style = Some(RunStyle::new(style_id));
69        self
70    }
71
72    pub fn size(mut self, size: usize) -> RunProperty {
73        self.sz = Some(Sz::new(size));
74        self.sz_cs = Some(SzCs::new(size));
75        self
76    }
77
78    pub fn spacing(mut self, spacing: i32) -> RunProperty {
79        self.character_spacing = Some(CharacterSpacing::new(spacing));
80        self
81    }
82
83    pub fn color(mut self, color: impl Into<String>) -> RunProperty {
84        self.color = Some(Color::new(color));
85        self
86    }
87
88    pub fn highlight(mut self, color: impl Into<String>) -> RunProperty {
89        self.highlight = Some(Highlight::new(color));
90        self
91    }
92
93    pub fn vert_align(mut self, a: VertAlignType) -> Self {
94        self.vert_align = Some(VertAlign::new(a));
95        self
96    }
97
98    pub fn bold(mut self) -> RunProperty {
99        self.bold = Some(Bold::new());
100        self.bold_cs = Some(BoldCs::new());
101        self
102    }
103
104    pub fn disable_bold(mut self) -> RunProperty {
105        self.bold = Some(Bold::new().disable());
106        self.bold_cs = Some(BoldCs::new().disable());
107        self
108    }
109
110    pub fn caps(mut self) -> RunProperty {
111        self.caps = Some(Caps::new());
112        self
113    }
114
115    pub fn italic(mut self) -> RunProperty {
116        self.italic = Some(Italic::new());
117        self.italic_cs = Some(ItalicCs::new());
118        self
119    }
120
121    pub fn strike(mut self) -> RunProperty {
122        self.strike = Some(Strike::new());
123        self.dstrike = None;
124        self
125    }
126
127    pub fn disable_strike(mut self) -> RunProperty {
128        self.strike = Some(Strike::new().disable());
129        self
130    }
131
132    pub fn dstrike(mut self) -> RunProperty {
133        self.dstrike = Some(Dstrike::new());
134        self.strike = None;
135        self
136    }
137
138    pub fn disable_dstrike(mut self) -> RunProperty {
139        self.dstrike = Some(Dstrike::new().disable());
140        self
141    }
142
143    pub fn disable_italic(mut self) -> RunProperty {
144        self.italic = Some(Italic::new().disable());
145        self.italic_cs = Some(ItalicCs::new().disable());
146        self
147    }
148
149    pub fn underline(mut self, line_type: impl Into<String>) -> RunProperty {
150        self.underline = Some(Underline::new(line_type));
151        self
152    }
153
154    pub fn vanish(mut self) -> RunProperty {
155        self.vanish = Some(Vanish::new());
156        self
157    }
158
159    pub fn spec_vanish(mut self) -> RunProperty {
160        self.spec_vanish = Some(SpecVanish::new());
161        self
162    }
163
164    pub fn fonts(mut self, font: RunFonts) -> RunProperty {
165        self.fonts = Some(font);
166        self
167    }
168
169    pub fn character_spacing(mut self, v: i32) -> RunProperty {
170        self.character_spacing = Some(CharacterSpacing::new(v));
171        self
172    }
173
174    pub fn stretch(mut self, v: i32) -> RunProperty {
175        self.stretch = Some(Stretch::new(v));
176        self
177    }
178
179    pub fn text_border(mut self, b: TextBorder) -> Self {
180        self.text_border = Some(b);
181        self
182    }
183
184    pub fn delete(mut self, d: Delete) -> Self {
185        self.del = Some(d);
186        self
187    }
188
189    pub fn insert(mut self, i: Insert) -> Self {
190        self.ins = Some(i);
191        self
192    }
193
194    pub fn ptab(mut self, ptab: PositionalTab) -> Self {
195        self.positional_tab = Some(ptab);
196        self
197    }
198
199    pub fn shading(mut self, s: Shading) -> Self {
200        self.shading = Some(s);
201        self
202    }
203}
204
205impl BuildXML for RunProperty {
206    fn build_to<W: Write>(
207        &self,
208        stream: xml::writer::EventWriter<W>,
209    ) -> xml::writer::Result<xml::writer::EventWriter<W>> {
210        XMLBuilder::from(stream)
211            .open_run_property()?
212            .add_optional_child(&self.sz)?
213            .add_optional_child(&self.sz_cs)?
214            .add_optional_child(&self.color)?
215            .add_optional_child(&self.bold)?
216            .add_optional_child(&self.bold_cs)?
217            .add_optional_child(&self.caps)?
218            .add_optional_child(&self.italic)?
219            .add_optional_child(&self.italic_cs)?
220            .add_optional_child(&self.strike)?
221            .add_optional_child(&self.dstrike)?
222            .add_optional_child(&self.highlight)?
223            .add_optional_child(&self.underline)?
224            .add_optional_child(&self.vanish)?
225            .add_optional_child(&self.spec_vanish)?
226            .add_optional_child(&self.fonts)?
227            .add_optional_child(&self.text_border)?
228            .add_optional_child(&self.ins)?
229            .add_optional_child(&self.del)?
230            .add_optional_child(&self.vert_align)?
231            .add_optional_child(&self.character_spacing)?
232            .add_optional_child(&self.stretch)?
233            .add_optional_child(&self.style)?
234            .add_optional_child(&self.positional_tab)?
235            .add_optional_child(&self.shading)?
236            .close()?
237            .into_inner()
238    }
239}
240
241#[cfg(test)]
242mod tests {
243
244    use super::*;
245    #[cfg(test)]
246    use pretty_assertions::assert_eq;
247    use std::str;
248
249    #[test]
250    fn test_size() {
251        let c = RunProperty::new().size(10).color("FFFFFF");
252        let b = c.build();
253        assert_eq!(
254            str::from_utf8(&b).unwrap(),
255            r#"<w:rPr><w:sz w:val="10" /><w:szCs w:val="10" /><w:color w:val="FFFFFF" /></w:rPr>"#
256        );
257    }
258
259    #[test]
260    fn test_highlight() {
261        let c = RunProperty::new().highlight("FFFFFF");
262        let b = c.build();
263        assert_eq!(
264            str::from_utf8(&b).unwrap(),
265            r#"<w:rPr><w:highlight w:val="FFFFFF" /></w:rPr>"#
266        );
267    }
268
269    #[test]
270    fn test_bold() {
271        let c = RunProperty::new().bold();
272        let b = c.build();
273        assert_eq!(
274            str::from_utf8(&b).unwrap(),
275            r#"<w:rPr><w:b /><w:bCs /></w:rPr>"#
276        );
277    }
278
279    #[test]
280    fn test_strike() {
281        let c = RunProperty::new().strike();
282        let b = c.build();
283        assert_eq!(
284            str::from_utf8(&b).unwrap(),
285            r#"<w:rPr><w:strike /></w:rPr>"#
286        );
287    }
288
289    #[test]
290    fn test_underline() {
291        let c = RunProperty::new().underline("single");
292        let b = c.build();
293        assert_eq!(
294            str::from_utf8(&b).unwrap(),
295            r#"<w:rPr><w:u w:val="single" /></w:rPr>"#
296        );
297    }
298
299    #[test]
300    fn test_vanish() {
301        let c = RunProperty::new().vanish();
302        let b = c.build();
303        assert_eq!(
304            str::from_utf8(&b).unwrap(),
305            r#"<w:rPr><w:vanish /></w:rPr>"#
306        );
307    }
308
309    #[test]
310    fn test_run_fonts() {
311        let c = RunProperty::new().fonts(RunFonts::new().east_asia("Hiragino"));
312        let b = c.build();
313        assert_eq!(
314            str::from_utf8(&b).unwrap(),
315            r#"<w:rPr><w:rFonts w:eastAsia="Hiragino" /></w:rPr>"#
316        );
317    }
318
319    #[test]
320    fn test_character_spacing() {
321        let c = RunProperty::new().spacing(20);
322        let b = c.build();
323        assert_eq!(
324            str::from_utf8(&b).unwrap(),
325            r#"<w:rPr><w:spacing w:val="20" /></w:rPr>"#
326        );
327    }
328
329    #[test]
330    fn test_stretch() {
331        let c = RunProperty::new().stretch(80);
332        let b = c.build();
333        assert_eq!(
334            str::from_utf8(&b).unwrap(),
335            r#"<w:rPr><w:w w:val="80" /></w:rPr>"#
336        );
337    }
338
339    #[test]
340    fn test_ptab() {
341        let c = RunProperty::new().ptab(PositionalTab::new(
342            PositionalTabAlignmentType::Left,
343            PositionalTabRelativeTo::Margin,
344            TabLeaderType::None,
345        ));
346        let b = c.build();
347        assert_eq!(
348            str::from_utf8(&b).unwrap(),
349            r#"<w:rPr><w:ptab w:alignment="left" w:relativeTo="margin" w:leader="none" /></w:rPr>"#
350        );
351    }
352
353    #[test]
354    fn test_character_shading() {
355        let c = RunProperty::new().shading(
356            Shading::new()
357                .shd_type(ShdType::Clear)
358                .fill("FFFFFF")
359                .color("auto"),
360        );
361        let b = c.build();
362        assert_eq!(
363            str::from_utf8(&b).unwrap(),
364            r#"<w:rPr><w:shd w:val="clear" w:color="auto" w:fill="FFFFFF" /></w:rPr>"#
365        );
366    }
367
368    #[test]
369    fn test_dstrike() {
370        let c = RunProperty::new().dstrike();
371        let b = c.build();
372        assert_eq!(
373            str::from_utf8(&b).unwrap(),
374            r#"<w:rPr><w:dstrike /></w:rPr>"#
375        );
376    }
377}