docx_rust/formatting/
paragraph_property.rs

1use hard_xml::{XmlRead, XmlWrite};
2use std::borrow::Cow;
3
4use crate::{
5    __define_enum, __define_struct, __define_struct_vec, __setter, __xml_test_suites,
6    formatting::{Borders, Indent, Justification, NumberingProperty, Spacing, WidowControl},
7};
8
9/// Paragraph Property
10///
11/// ```rust
12/// use docx_rust::formatting::{ParagraphProperty, JustificationVal};
13///
14/// let prop = ParagraphProperty::default()
15///     .style_id("foo")
16///     .justification(JustificationVal::Start)
17///     .numbering((10isize, 20isize));
18/// ```
19#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
20#[cfg_attr(test, derive(PartialEq))]
21#[xml(tag = "w:pPr")]
22pub struct ParagraphProperty<'a> {
23    /// Specifies the style ID of the paragraph style.
24    #[xml(child = "w:pStyle")]
25    pub style_id: Option<ParagraphStyleId<'a>>,
26    ///  Keep Paragraph With Next Paragraph
27    #[xml(child = "w:keepNext")]
28    pub keep_next: Option<KeepNext>,
29    ///  Keep All Lines On One Page
30    #[xml(child = "w:keepLines")]
31    pub keep_lines: Option<KeepLines>,
32    ///  Start Paragraph on Next Page
33    #[xml(child = "w:pageBreakBefore")]
34    pub page_break_before: Option<PageBreakBefore>,
35    ///  Text Frame Properties
36    //#[xml(child = "w:framePr")]
37    //pub frame_pr: Option<FramePr>,
38    ///  Allow First/Last Line to Display on a Separate Page
39    /// Specifies whether enable widow control
40    #[xml(child = "w:widowControl")]
41    pub widow_control: Option<WidowControl>,
42    /// Specifies that the paragraph should be numbered.
43    #[xml(child = "w:numPr")]
44    pub numbering: Option<NumberingProperty<'a>>,
45    ///  Suppress Line Numbers for Paragraph
46    #[xml(child = "w:suppressLineNumbers")]
47    pub suppress_line_numbers: Option<SuppressLineNumbers>,
48    /// Specifies borders for the paragraph.
49    #[xml(child = "w:pBdr")]
50    pub border: Option<Borders<'a>>,
51    ///  Paragraph Shading
52    #[xml(child = "w:shd")]
53    pub shading: Option<super::Shading<'a>>,
54    ///  Set of Custom Tab Stops
55    #[xml(child = "w:tabs")]
56    pub tabs: Option<CustomTabStopSet>,
57    ///  Suppress Hyphenation for Paragraph
58    #[xml(child = "w:suppressAutoHyphens")]
59    pub suppress_auto_hyphens: Option<SuppressAutoHyphens>,
60    ///  Use East Asian Typography Rules for First and Last Character per Line
61    #[xml(child = "w:kinsoku")]
62    pub kinsoku: Option<Kinsoku>,
63    ///  Allow Line Breaking At Character Level
64    #[xml(child = "w:wordWrap")]
65    pub word_wrap: Option<WordWrap>,
66    ///  Allow Punctuation to Extent Past Text Extents
67    #[xml(child = "w:overflowPunct")]
68    pub overflow_punct: Option<OverflowPunct>,
69    ///  Compress Punctuation at Start of a Line
70    #[xml(child = "w:topLinePunct")]
71    pub top_line_punct: Option<TopLinePunct>,
72    ///  Automatically Adjust Spacing of Latin and East Asian Text
73    #[xml(child = "w:autoSpaceDE")]
74    pub auto_space_de: Option<AutoSpaceDE>,
75    ///  Automatically Adjust Spacing of East Asian Text and Numbers
76    #[xml(child = "w:autoSpaceDN")]
77    pub auto_space_dn: Option<AutoSpaceDN>,
78    ///  Right to Left Paragraph Layout
79    #[xml(child = "w:bidi")]
80    pub bidi: Option<Bidi>,
81    ///  Automatically Adjust Right Indent When Using Document Grid
82    #[xml(child = "w:adjustRightInd")]
83    pub adjust_right_ind: Option<AdjustRightInd>,
84    ///  Use Document Grid Settings for Inter-Line Paragraph Spacing
85    #[xml(child = "w:snapToGrid")]
86    pub snap_to_grid: Option<SnapToGrid>,
87    ///  Spacing Between Lines and Above/Below Paragraph
88    #[xml(child = "w:spacing")]
89    pub spacing: Option<Spacing>,
90    ///  Paragraph Indentation
91    #[xml(child = "w:ind")]
92    pub indent: Option<Indent>,
93    ///  Ignore Spacing Above and Below When Using Identical Styles
94    #[xml(child = "w:contextualSpacing")]
95    pub contextual_spacing: Option<ContextualSpacing>,
96    ///  Use Left/Right Indents as Inside/Outside Indents
97    #[xml(child = "w:mirrorIndents")]
98    pub mirror_indents: Option<MirrorIndents>,
99    ///  Prevent Text Frames From Overlapping
100    #[xml(child = "w:suppressOverlap")]
101    pub suppress_overlap: Option<SuppressOverlap>,
102    ///  Paragraph Alignment
103    #[xml(child = "w:jc")]
104    pub justification: Option<Justification>,
105    ///  Paragraph Text Flow Direction
106    #[xml(child = "w:textDirection")]
107    pub text_direction: Option<super::TextDirection>,
108    ///  Vertical Character Alignment on Line
109    #[xml(child = "w:textAlignment")]
110    pub text_alignment: Option<super::TextAlignment>,
111    ///  Allow Surrounding Paragraphs to Tight Wrap to Text Box Contents
112    #[xml(child = "w:textboxTightWrap")]
113    pub textbox_tight_wrap: Option<super::TextboxTightWrap>,
114    ///  Associated Outline Level
115    #[xml(child = "w:outlineLvl")]
116    pub outline_lvl: Option<OutlineLvl>,
117    ///  Associated HTML div ID
118    #[xml(child = "w:divId")]
119    pub div_id: Option<DivId>,
120    ///  Paragraph Conditional Formatting
121    #[xml(child = "w:cnfStyle")]
122    pub cnf_style: Option<CnfStyle<'a>>,
123    #[xml(child = "w:rPr")]
124    pub r_pr: Vec<super::CharacterProperty<'a>>,
125    #[xml(child = "w:sectPr")]
126    pub section_property: Option<SectionProperty<'a>>,
127    #[xml(child = "w:pPrChange")]
128    pub p_pr_change: Option<RevisionParagraphProperty<'a>>,
129}
130
131impl<'a> ParagraphProperty<'a> {
132    __setter!(style_id: Option<ParagraphStyleId<'a>>);
133    __setter!(justification: Option<Justification>);
134    __setter!(border: Option<Borders<'a>>);
135    __setter!(numbering: Option<NumberingProperty<'a>>);
136    __setter!(spacing: Option<Spacing>);
137    __setter!(indent: Option<Indent>);
138}
139
140#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
141#[cfg_attr(test, derive(PartialEq))]
142#[xml(tag = "w:pStyle")]
143pub struct ParagraphStyleId<'a> {
144    #[xml(attr = "w:val")]
145    pub value: Cow<'a, str>,
146}
147
148impl<'a, T: Into<Cow<'a, str>>> From<T> for ParagraphStyleId<'a> {
149    fn from(val: T) -> Self {
150        ParagraphStyleId { value: val.into() }
151    }
152}
153
154#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
155#[cfg_attr(test, derive(PartialEq))]
156#[xml(tag = "w:keepNext")]
157pub struct KeepNext {
158    #[xml(attr = "w:val")]
159    pub value: Option<bool>,
160}
161
162#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
163#[cfg_attr(test, derive(PartialEq))]
164#[xml(tag = "w:keepLines")]
165pub struct KeepLines {
166    #[xml(attr = "w:val")]
167    pub value: Option<bool>,
168}
169
170#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
171#[cfg_attr(test, derive(PartialEq))]
172#[xml(tag = "w:pageBreakBefore")]
173pub struct PageBreakBefore {
174    #[xml(attr = "w:val")]
175    pub value: Option<bool>,
176}
177
178#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
179#[cfg_attr(test, derive(PartialEq))]
180#[xml(tag = "w:suppressLineNumbers")]
181pub struct SuppressLineNumbers {
182    #[xml(attr = "w:val")]
183    pub value: Option<bool>,
184}
185
186#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
187#[cfg_attr(test, derive(PartialEq))]
188#[xml(tag = "w:suppressAutoHyphens")]
189pub struct SuppressAutoHyphens {
190    #[xml(attr = "w:val")]
191    pub value: Option<bool>,
192}
193
194#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
195#[cfg_attr(test, derive(PartialEq))]
196#[xml(tag = "w:kinsoku")]
197pub struct Kinsoku {
198    #[xml(attr = "w:val")]
199    pub value: Option<bool>,
200}
201
202#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
203#[cfg_attr(test, derive(PartialEq))]
204#[xml(tag = "w:wordWrap")]
205pub struct WordWrap {
206    #[xml(attr = "w:val")]
207    pub value: Option<bool>,
208}
209
210#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
211#[cfg_attr(test, derive(PartialEq))]
212#[xml(tag = "w:overflowPunct")]
213pub struct OverflowPunct {
214    #[xml(attr = "w:val")]
215    pub value: Option<bool>,
216}
217
218#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
219#[cfg_attr(test, derive(PartialEq))]
220#[xml(tag = "w:topLinePunct")]
221pub struct TopLinePunct {
222    #[xml(attr = "w:val")]
223    pub value: Option<bool>,
224}
225
226#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
227#[cfg_attr(test, derive(PartialEq))]
228#[xml(tag = "w:autoSpaceDE")]
229pub struct AutoSpaceDE {
230    #[xml(attr = "w:val")]
231    pub value: Option<bool>,
232}
233
234#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
235#[cfg_attr(test, derive(PartialEq))]
236#[xml(tag = "w:autoSpaceDN")]
237pub struct AutoSpaceDN {
238    #[xml(attr = "w:val")]
239    pub value: Option<bool>,
240}
241
242#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
243#[cfg_attr(test, derive(PartialEq))]
244#[xml(tag = "w:bidi")]
245pub struct Bidi {
246    #[xml(attr = "w:val")]
247    pub value: Option<bool>,
248}
249
250#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
251#[cfg_attr(test, derive(PartialEq))]
252#[xml(tag = "w:adjustRightInd")]
253pub struct AdjustRightInd {
254    #[xml(attr = "w:val")]
255    pub value: Option<bool>,
256}
257
258#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
259#[cfg_attr(test, derive(PartialEq))]
260#[xml(tag = "w:snapToGrid")]
261pub struct SnapToGrid {
262    #[xml(attr = "w:val")]
263    pub value: Option<bool>,
264}
265
266#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
267#[cfg_attr(test, derive(PartialEq))]
268#[xml(tag = "w:contextualSpacing")]
269pub struct ContextualSpacing {
270    #[xml(attr = "w:val")]
271    pub value: Option<bool>,
272}
273
274#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
275#[cfg_attr(test, derive(PartialEq))]
276#[xml(tag = "w:mirrorIndents")]
277pub struct MirrorIndents {
278    #[xml(attr = "w:val")]
279    pub value: Option<bool>,
280}
281
282#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
283#[cfg_attr(test, derive(PartialEq))]
284#[xml(tag = "w:suppressOverlap")]
285pub struct SuppressOverlap {
286    #[xml(attr = "w:val")]
287    pub value: Option<bool>,
288}
289
290#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
291#[cfg_attr(test, derive(PartialEq))]
292#[xml(tag = "w:outlineLvl")]
293pub struct OutlineLvl {
294    #[xml(attr = "w:val")]
295    pub value: isize,
296}
297
298#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
299#[cfg_attr(test, derive(PartialEq))]
300#[xml(tag = "w:divId")]
301pub struct DivId {
302    #[xml(attr = "w:val")]
303    pub value: isize,
304}
305
306#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
307#[cfg_attr(test, derive(PartialEq))]
308#[xml(tag = "w:cnfStyle")]
309pub struct CnfStyle<'a> {
310    #[xml(attr = "w:val")]
311    pub value: Cow<'a, str>,
312}
313
314#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
315#[cfg_attr(test, derive(PartialEq))]
316#[xml(tag = "w:pPrChange")]
317pub struct RevisionParagraphProperty<'a> {
318    #[xml(attr = "w:id")]
319    pub id: isize,
320    #[xml(attr = "w:author")]
321    pub author: Cow<'a, str>,
322    #[xml(attr = "w:date")]
323    pub date: Option<Cow<'a, str>>,
324
325    #[xml(child = "w:pPr")]
326    pub previous_property: Option<PreviousParagraphProperty<'a>>,
327}
328
329#[derive(Debug, Default, XmlRead, XmlWrite, Clone)]
330#[cfg_attr(test, derive(PartialEq))]
331#[xml(tag = "w:pPr")]
332pub struct PreviousParagraphProperty<'a> {
333    /// Specifies the style ID of the paragraph style.
334    #[xml(child = "w:pStyle")]
335    pub style_id: Option<ParagraphStyleId<'a>>,
336    ///  Keep Paragraph With Next Paragraph
337    #[xml(child = "w:keepNext")]
338    pub keep_next: Option<KeepNext>,
339    ///  Keep All Lines On One Page
340    #[xml(child = "w:keepLines")]
341    pub keep_lines: Option<KeepLines>,
342    ///  Start Paragraph on Next Page
343    #[xml(child = "w:pageBreakBefore")]
344    pub page_break_before: Option<PageBreakBefore>,
345    ///  Text Frame Properties
346    //#[xml(child = "w:framePr")]
347    //pub frame_pr: Option<FramePr>,
348    ///  Allow First/Last Line to Display on a Separate Page
349    /// Specifies whether enable widow control
350    #[xml(child = "w:widowControl")]
351    pub widow_control: Option<WidowControl>,
352    /// Specifies that the paragraph should be numbered.
353    #[xml(child = "w:numPr")]
354    pub numbering: Option<NumberingProperty<'a>>,
355    ///  Suppress Line Numbers for Paragraph
356    #[xml(child = "w:suppressLineNumbers")]
357    pub suppress_line_numbers: Option<SuppressLineNumbers>,
358    /// Specifies borders for the paragraph.
359    #[xml(child = "w:pBdr")]
360    pub border: Option<Borders<'a>>,
361    ///  Paragraph Shading
362    #[xml(child = "w:shd")]
363    pub shading: Option<super::Shading<'a>>,
364    ///  Set of Custom Tab Stops
365    #[xml(child = "w:tabs")]
366    pub tabs: Option<CustomTabStopSet>,
367    ///  Suppress Hyphenation for Paragraph
368    #[xml(child = "w:suppressAutoHyphens")]
369    pub suppress_auto_hyphens: Option<SuppressAutoHyphens>,
370    ///  Use East Asian Typography Rules for First and Last Character per Line
371    #[xml(child = "w:kinsoku")]
372    pub kinsoku: Option<Kinsoku>,
373    ///  Allow Line Breaking At Character Level
374    #[xml(child = "w:wordWrap")]
375    pub word_wrap: Option<WordWrap>,
376    ///  Allow Punctuation to Extent Past Text Extents
377    #[xml(child = "w:overflowPunct")]
378    pub overflow_punct: Option<OverflowPunct>,
379    ///  Compress Punctuation at Start of a Line
380    #[xml(child = "w:topLinePunct")]
381    pub top_line_punct: Option<TopLinePunct>,
382    ///  Automatically Adjust Spacing of Latin and East Asian Text
383    #[xml(child = "w:autoSpaceDE")]
384    pub auto_space_de: Option<AutoSpaceDE>,
385    ///  Automatically Adjust Spacing of East Asian Text and Numbers
386    #[xml(child = "w:autoSpaceDN")]
387    pub auto_space_dn: Option<AutoSpaceDN>,
388    ///  Right to Left Paragraph Layout
389    #[xml(child = "w:bidi")]
390    pub bidi: Option<Bidi>,
391    ///  Automatically Adjust Right Indent When Using Document Grid
392    #[xml(child = "w:adjustRightInd")]
393    pub adjust_right_ind: Option<AdjustRightInd>,
394    ///  Use Document Grid Settings for Inter-Line Paragraph Spacing
395    #[xml(child = "w:snapToGrid")]
396    pub snap_to_grid: Option<SnapToGrid>,
397    ///  Spacing Between Lines and Above/Below Paragraph
398    #[xml(child = "w:spacing")]
399    pub spacing: Option<Spacing>,
400    ///  Paragraph Indentation
401    #[xml(child = "w:ind")]
402    pub indent: Option<Indent>,
403    ///  Ignore Spacing Above and Below When Using Identical Styles
404    #[xml(child = "w:contextualSpacing")]
405    pub contextual_spacing: Option<ContextualSpacing>,
406    ///  Use Left/Right Indents as Inside/Outside Indents
407    #[xml(child = "w:mirrorIndents")]
408    pub mirror_indents: Option<MirrorIndents>,
409    ///  Prevent Text Frames From Overlapping
410    #[xml(child = "w:suppressOverlap")]
411    pub suppress_overlap: Option<SuppressOverlap>,
412    ///  Paragraph Alignment
413    #[xml(child = "w:jc")]
414    pub justification: Option<Justification>,
415    ///  Paragraph Text Flow Direction
416    #[xml(child = "w:textDirection")]
417    pub text_direction: Option<super::TextDirection>,
418    ///  Vertical Character Alignment on Line
419    #[xml(child = "w:textAlignment")]
420    pub text_alignment: Option<super::TextAlignment>,
421    ///  Allow Surrounding Paragraphs to Tight Wrap to Text Box Contents
422    #[xml(child = "w:textboxTightWrap")]
423    pub textbox_tight_wrap: Option<super::TextboxTightWrap>,
424    ///  Associated Outline Level
425    #[xml(child = "w:outlineLvl")]
426    pub outline_lvl: Option<OutlineLvl>,
427    ///  Associated HTML div ID
428    #[xml(child = "w:divId")]
429    pub div_id: Option<DivId>,
430    ///  Paragraph Conditional Formatting
431    #[xml(child = "w:cnfStyle")]
432    pub cnf_style: Option<CnfStyle<'a>>,
433}
434
435__define_enum! {
436    TabStopType  {
437        Clear = "clear", // No Tab Stop
438        Left = "left", // Left Tab
439        Center = "center", // Centered Tab
440        Right = "right", // Right Tab
441        Decimal = "decimal", // Decimal Tab
442        Bar = "bar", // Bar Tab
443        Num = "num", // List Tab
444    }
445}
446
447__define_enum! {
448    TabLeaderCharacter {
449        None = "none", // No tab stop leader
450        Dot = "dot", // Dotted leader line
451        Hyphen = "hyphen", // Dashed tab stop leader line
452        Underscore = "underscore", // Solid leader line
453        Heavy = "heavy", // Heavy solid leader line
454        MiddleDot = "middleDot", // Middle dot leader line
455    }
456}
457
458__define_struct! {
459    ("w:tab", CustomTabStop) {
460        "w:val", tab_stop_type, TabStopType
461        "w:leader", leader, TabLeaderCharacter
462        "w:pos", pos, isize
463    }
464}
465
466__define_struct_vec! {
467    ("w:tabs", CustomTabStopSet, CustomTabStopSetChoice) {} {
468        "w:tab", CustomTabStop
469    }
470}
471
472#[cfg(test)]
473use crate::formatting::JustificationVal;
474
475use super::SectionProperty;
476
477__xml_test_suites!(
478    ParagraphProperty,
479    ParagraphProperty::default(),
480    r#"<w:pPr/>"#,
481    ParagraphProperty::default().style_id("id"),
482    r#"<w:pPr><w:pStyle w:val="id"/></w:pPr>"#,
483    ParagraphProperty::default().justification(JustificationVal::Start),
484    r#"<w:pPr><w:jc w:val="start"/></w:pPr>"#,
485    ParagraphProperty::default().border(Borders::default()),
486    r#"<w:pPr><w:pBdr/></w:pPr>"#,
487    ParagraphProperty::default().numbering(NumberingProperty::default()),
488    r#"<w:pPr><w:numPr/></w:pPr>"#,
489);