Skip to main content

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