From 61cc95f6ba3e7b805d7350a6415f4cb6554e59dc Mon Sep 17 00:00:00 2001 From: bokuweb Date: Fri, 6 Dec 2019 19:18:48 +0900 Subject: [PATCH] feat: Add numberings --- docx-core/src/documents/content_types.rs | 33 +- docx-core/src/documents/document_rels.rs | 33 +- .../src/documents/elements/indent_level.rs | 36 ++ docx-core/src/documents/elements/level.rs | 93 ++++ docx-core/src/documents/elements/level_jc.rs | 36 ++ .../src/documents/elements/level_text.rs | 36 ++ docx-core/src/documents/elements/mod.rs | 18 + .../src/documents/elements/number_format.rs | 39 ++ docx-core/src/documents/elements/numbering.rs | 64 +++ .../src/documents/elements/numbering_id.rs | 36 ++ .../documents/elements/numbering_property.rs | 45 ++ docx-core/src/documents/elements/paragraph.rs | 24 +- .../documents/elements/paragraph_property.rs | 32 +- docx-core/src/documents/elements/start.rs | 36 ++ docx-core/src/documents/elements/style.rs | 14 +- docx-core/src/documents/mod.rs | 13 +- docx-core/src/documents/numberings.rs | 131 +++++ docx-core/src/documents/styles.rs | 14 +- docx-core/src/documents/xml_docx.rs | 1 + docx-core/src/xml_builder/elements.rs | 15 + docx-core/src/xml_builder/mod.rs | 1 + docx-core/src/xml_builder/numbering.rs | 27 + docx-core/src/zipper/mod.rs | 2 + docx-core/tests/lib.rs | 11 + docx-core/tests/output/word/styles.xml | 23 +- fixtures/numbering/[Content_Types].xml | 11 +- .../numbering/word/_rels/document.xml.rels | 6 +- fixtures/numbering/word/numbering.xml | 466 +++++++++++++++++- fixtures/word_default/[Content_Types].xml | 2 + fixtures/word_default/_rels/.rels | 2 + fixtures/word_default/docProps/app.xml | 2 + fixtures/word_default/docProps/core.xml | 2 + .../word_default/word/_rels/document.xml.rels | 2 + fixtures/word_default/word/document.xml | 60 +++ fixtures/word_default/word/fontTable.xml | 2 + fixtures/word_default/word/numbering.xml | 120 +++++ fixtures/word_default/word/settings.xml | 69 +++ fixtures/word_default/word/styles.xml | 444 +++++++++++++++++ fixtures/word_default/word/theme/theme1.xml | 2 + fixtures/word_default/word/webSettings.xml | 2 + fixtures/word_default/word_default.docx | Bin 0 -> 13149 bytes 41 files changed, 1916 insertions(+), 89 deletions(-) create mode 100644 docx-core/src/documents/elements/indent_level.rs create mode 100644 docx-core/src/documents/elements/level.rs create mode 100644 docx-core/src/documents/elements/level_jc.rs create mode 100644 docx-core/src/documents/elements/level_text.rs create mode 100644 docx-core/src/documents/elements/number_format.rs create mode 100644 docx-core/src/documents/elements/numbering.rs create mode 100644 docx-core/src/documents/elements/numbering_id.rs create mode 100644 docx-core/src/documents/elements/numbering_property.rs create mode 100644 docx-core/src/documents/elements/start.rs create mode 100644 docx-core/src/documents/numberings.rs create mode 100644 docx-core/src/xml_builder/numbering.rs create mode 100644 fixtures/word_default/[Content_Types].xml create mode 100644 fixtures/word_default/_rels/.rels create mode 100644 fixtures/word_default/docProps/app.xml create mode 100644 fixtures/word_default/docProps/core.xml create mode 100644 fixtures/word_default/word/_rels/document.xml.rels create mode 100644 fixtures/word_default/word/document.xml create mode 100644 fixtures/word_default/word/fontTable.xml create mode 100644 fixtures/word_default/word/numbering.xml create mode 100644 fixtures/word_default/word/settings.xml create mode 100644 fixtures/word_default/word/styles.xml create mode 100644 fixtures/word_default/word/theme/theme1.xml create mode 100644 fixtures/word_default/word/webSettings.xml create mode 100644 fixtures/word_default/word_default.docx diff --git a/docx-core/src/documents/content_types.rs b/docx-core/src/documents/content_types.rs index b0361c8..f2643cf 100644 --- a/docx-core/src/documents/content_types.rs +++ b/docx-core/src/documents/content_types.rs @@ -51,36 +51,11 @@ impl BuildXML for ContentTypes { "/word/comments.xml", "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml", ) + .add_override( + "/word/numbering.xml", + "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml", + ) .close() .build() } } - -#[cfg(test)] -mod tests { - - use super::*; - #[cfg(test)] - use pretty_assertions::assert_eq; - use std::str; - - #[test] - fn test_build() { - let c = ContentTypes::new(); - let b = c.build(); - assert_eq!( - str::from_utf8(&b).unwrap(), - r#" - - - - - - - - - -"# - ); - } -} diff --git a/docx-core/src/documents/document_rels.rs b/docx-core/src/documents/document_rels.rs index ccbfe97..ba4f5f6 100644 --- a/docx-core/src/documents/document_rels.rs +++ b/docx-core/src/documents/document_rels.rs @@ -22,16 +22,21 @@ impl BuildXML for DocumentRels { ) .relationship( "rId2", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering", + "numbering.xml", + ) + .relationship( + "rId3", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments", "comments.xml", ) .relationship( - "rId3", + "rId4", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable", "fontTable.xml", ) .relationship( - "rId4", + "rId5", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings", "settings.xml", ) @@ -39,27 +44,3 @@ impl BuildXML for DocumentRels { .build() } } - -#[cfg(test)] -mod tests { - - use super::*; - #[cfg(test)] - use pretty_assertions::assert_eq; - use std::str; - - #[test] - fn test_build() { - let c = DocumentRels::new(); - let b = c.build(); - assert_eq!( - str::from_utf8(&b).unwrap(), - r#" - - - - -"# - ); - } -} diff --git a/docx-core/src/documents/elements/indent_level.rs b/docx-core/src/documents/elements/indent_level.rs new file mode 100644 index 0000000..f65075e --- /dev/null +++ b/docx-core/src/documents/elements/indent_level.rs @@ -0,0 +1,36 @@ +use crate::documents::BuildXML; +use crate::xml_builder::*; + +#[derive(Debug, Clone)] +pub struct IndentLevel { + val: usize, +} + +impl IndentLevel { + pub fn new(val: usize) -> IndentLevel { + IndentLevel { val } + } +} + +impl BuildXML for IndentLevel { + fn build(&self) -> Vec { + let b = XMLBuilder::new(); + b.indent_level(self.val).build() + } +} + +#[cfg(test)] +mod tests { + + use super::*; + #[cfg(test)] + use pretty_assertions::assert_eq; + use std::str; + + #[test] + fn test_indent_level() { + let c = IndentLevel::new(20); + let b = c.build(); + assert_eq!(str::from_utf8(&b).unwrap(), r#""#); + } +} diff --git a/docx-core/src/documents/elements/level.rs b/docx-core/src/documents/elements/level.rs new file mode 100644 index 0000000..aa43456 --- /dev/null +++ b/docx-core/src/documents/elements/level.rs @@ -0,0 +1,93 @@ +use crate::documents::{BuildXML, LevelJc, LevelText, NumberFormat, ParagraphProperty, Start}; +use crate::types::*; +use crate::xml_builder::*; + +#[derive(Debug, Clone)] +pub struct Level<'a> { + level: usize, + start: Start, + format: NumberFormat<'a>, + text: LevelText<'a>, + jc: LevelJc<'a>, + paragraph_property: ParagraphProperty<'a>, +} + +impl<'a> Level<'a> { + pub fn new( + level: usize, + start: Start, + format: NumberFormat<'a>, + text: LevelText<'a>, + jc: LevelJc<'a>, + ) -> Level<'a> { + Self { + level, + start, + format, + text, + jc, + paragraph_property: ParagraphProperty::new(), + } + } + + pub fn indent(mut self, left: usize, special_indent: Option) -> Self { + self.paragraph_property = self.paragraph_property.indent(left, special_indent); + self + } +} + +impl<'a> BuildXML for Level<'a> { + fn build(&self) -> Vec { + XMLBuilder::new() + .open_level(&format!("{}", self.level)) + .add_child(&self.start) + .add_child(&self.format) + .add_child(&self.text) + .add_child(&self.jc) + .add_child(&self.paragraph_property) + .close() + .build() + } +} + +#[cfg(test)] +mod tests { + + use super::*; + #[cfg(test)] + use pretty_assertions::assert_eq; + use std::str; + + #[test] + fn test_level() { + let b = Level::new( + 1, + Start::new(1), + NumberFormat::new("decimal"), + LevelText::new("%4."), + LevelJc::new("left"), + ) + .build(); + assert_eq!( + str::from_utf8(&b).unwrap(), + r#""# + ); + } + + #[test] + fn test_level_indent() { + let b = Level::new( + 1, + Start::new(1), + NumberFormat::new("decimal"), + LevelText::new("%4."), + LevelJc::new("left"), + ) + .indent(320, Some(SpecialIndentType::Hanging(200))) + .build(); + assert_eq!( + str::from_utf8(&b).unwrap(), + r#""# + ); + } +} diff --git a/docx-core/src/documents/elements/level_jc.rs b/docx-core/src/documents/elements/level_jc.rs new file mode 100644 index 0000000..3de564f --- /dev/null +++ b/docx-core/src/documents/elements/level_jc.rs @@ -0,0 +1,36 @@ +use crate::documents::BuildXML; +use crate::xml_builder::*; + +#[derive(Debug, Clone)] +pub struct LevelJc<'a> { + val: &'a str, +} + +impl<'a> LevelJc<'a> { + pub fn new(val: &'a str) -> Self { + Self { val } + } +} + +impl<'a> BuildXML for LevelJc<'a> { + fn build(&self) -> Vec { + let b = XMLBuilder::new(); + b.level_justification(self.val).build() + } +} + +#[cfg(test)] +mod tests { + + use super::*; + #[cfg(test)] + use pretty_assertions::assert_eq; + use std::str; + + #[test] + fn test_level_jc() { + let c = LevelJc::new("left"); + let b = c.build(); + assert_eq!(str::from_utf8(&b).unwrap(), r#""#); + } +} diff --git a/docx-core/src/documents/elements/level_text.rs b/docx-core/src/documents/elements/level_text.rs new file mode 100644 index 0000000..425e6d0 --- /dev/null +++ b/docx-core/src/documents/elements/level_text.rs @@ -0,0 +1,36 @@ +use crate::documents::BuildXML; +use crate::xml_builder::*; + +#[derive(Debug, Clone)] +pub struct LevelText<'a> { + val: &'a str, +} + +impl<'a> LevelText<'a> { + pub fn new(val: &'a str) -> Self { + Self { val } + } +} + +impl<'a> BuildXML for LevelText<'a> { + fn build(&self) -> Vec { + let b = XMLBuilder::new(); + b.level_text(self.val).build() + } +} + +#[cfg(test)] +mod tests { + + use super::*; + #[cfg(test)] + use pretty_assertions::assert_eq; + use std::str; + + #[test] + fn test_level_text() { + let c = LevelText::new("%4."); + let b = c.build(); + assert_eq!(str::from_utf8(&b).unwrap(), r#""#); + } +} diff --git a/docx-core/src/documents/elements/mod.rs b/docx-core/src/documents/elements/mod.rs index a9e1848..d1b534e 100644 --- a/docx-core/src/documents/elements/mod.rs +++ b/docx-core/src/documents/elements/mod.rs @@ -16,12 +16,20 @@ mod font; mod grid_span; mod highlight; mod indent; +mod indent_level; mod insert; mod italic; mod italic_cs; mod justification; +mod level; +mod level_jc; +mod level_text; mod name; mod next; +mod number_format; +mod numbering; +mod numbering_id; +mod numbering_property; mod paragraph; mod paragraph_property; mod paragraph_style; @@ -29,6 +37,7 @@ mod q_format; mod run; mod run_property; mod run_property_default; +mod start; mod style; mod sz; mod sz_cs; @@ -69,12 +78,20 @@ pub use font::*; pub use grid_span::*; pub use highlight::*; pub use indent::*; +pub use indent_level::*; pub use insert::*; pub use italic::*; pub use italic_cs::*; pub use justification::*; +pub use level::*; +pub use level_jc::*; +pub use level_text::*; pub use name::*; pub use next::*; +pub use number_format::*; +pub use numbering::*; +pub use numbering_id::*; +pub use numbering_property::*; pub use paragraph::*; pub use paragraph_property::*; pub use paragraph_style::*; @@ -82,6 +99,7 @@ pub use q_format::*; pub use run::*; pub use run_property::*; pub use run_property_default::*; +pub use start::*; pub use style::*; pub use sz::*; pub use sz_cs::*; diff --git a/docx-core/src/documents/elements/number_format.rs b/docx-core/src/documents/elements/number_format.rs new file mode 100644 index 0000000..e1ebfbc --- /dev/null +++ b/docx-core/src/documents/elements/number_format.rs @@ -0,0 +1,39 @@ +use crate::documents::BuildXML; +use crate::xml_builder::*; + +#[derive(Debug, Clone)] +pub struct NumberFormat<'a> { + val: &'a str, +} + +impl<'a> NumberFormat<'a> { + pub fn new(val: &'a str) -> Self { + Self { val } + } +} + +impl<'a> BuildXML for NumberFormat<'a> { + fn build(&self) -> Vec { + let b = XMLBuilder::new(); + b.number_format(self.val).build() + } +} + +#[cfg(test)] +mod tests { + + use super::*; + #[cfg(test)] + use pretty_assertions::assert_eq; + use std::str; + + #[test] + fn test_start() { + let c = NumberFormat::new("decimal"); + let b = c.build(); + assert_eq!( + str::from_utf8(&b).unwrap(), + r#""# + ); + } +} diff --git a/docx-core/src/documents/elements/numbering.rs b/docx-core/src/documents/elements/numbering.rs new file mode 100644 index 0000000..29a5c11 --- /dev/null +++ b/docx-core/src/documents/elements/numbering.rs @@ -0,0 +1,64 @@ +use crate::documents::{BuildXML, Level}; +use crate::xml_builder::*; + +#[derive(Debug, Clone)] +pub struct Numbering<'a> { + id: &'a str, + levels: Vec>, +} + +impl<'a> Numbering<'a> { + pub fn new(id: &'a str) -> Self { + Self { id, levels: vec![] } + } + + pub fn add_level(mut self, level: Level<'a>) -> Self { + self.levels.push(level); + self + } +} + +impl<'a> BuildXML for Numbering<'a> { + fn build(&self) -> Vec { + let mut b = XMLBuilder::new(); + b = b.open_abstract_num(self.id); + for l in &self.levels { + b = b.add_child(l); + } + b.close() + .open_num(self.id) + .abstract_num_id(self.id) + .close() + .build() + } +} + +#[cfg(test)] +mod tests { + + use super::*; + #[cfg(test)] + use crate::documents::{Level, LevelJc, LevelText, NumberFormat, Start}; + use pretty_assertions::assert_eq; + use std::str; + + #[test] + fn test_numbering() { + let mut c = Numbering::new("0"); + c = c.add_level(Level::new( + 1, + Start::new(1), + NumberFormat::new("decimal"), + LevelText::new("%4."), + LevelJc::new("left"), + )); + let b = c.build(); + assert_eq!( + str::from_utf8(&b).unwrap(), + r#" + + +"# + ); + } +} diff --git a/docx-core/src/documents/elements/numbering_id.rs b/docx-core/src/documents/elements/numbering_id.rs new file mode 100644 index 0000000..933e289 --- /dev/null +++ b/docx-core/src/documents/elements/numbering_id.rs @@ -0,0 +1,36 @@ +use crate::documents::BuildXML; +use crate::xml_builder::*; + +#[derive(Debug, Clone)] +pub struct NumberingId<'a> { + id: &'a str, +} + +impl<'a> NumberingId<'a> { + pub fn new(id: &'a str) -> NumberingId<'a> { + NumberingId { id } + } +} + +impl<'a> BuildXML for NumberingId<'a> { + fn build(&self) -> Vec { + let b = XMLBuilder::new(); + b.num_id(self.id).build() + } +} + +#[cfg(test)] +mod tests { + + use super::*; + #[cfg(test)] + use pretty_assertions::assert_eq; + use std::str; + + #[test] + fn test_num_id() { + let c = NumberingId::new("abc"); + let b = c.build(); + assert_eq!(str::from_utf8(&b).unwrap(), r#""#); + } +} diff --git a/docx-core/src/documents/elements/numbering_property.rs b/docx-core/src/documents/elements/numbering_property.rs new file mode 100644 index 0000000..4856832 --- /dev/null +++ b/docx-core/src/documents/elements/numbering_property.rs @@ -0,0 +1,45 @@ +use super::{IndentLevel, NumberingId}; +use crate::documents::BuildXML; +use crate::xml_builder::*; + +#[derive(Debug, Clone)] +pub struct NumberingProperty<'a> { + id: NumberingId<'a>, + level: IndentLevel, +} + +impl<'a> NumberingProperty<'a> { + pub fn new(id: NumberingId<'a>, level: IndentLevel) -> NumberingProperty { + Self { id, level } + } +} + +impl<'a> BuildXML for NumberingProperty<'a> { + fn build(&self) -> Vec { + let b = XMLBuilder::new(); + b.open_numbering_property() + .add_child(&self.id) + .add_child(&self.level) + .close() + .build() + } +} + +#[cfg(test)] +mod tests { + + use super::*; + #[cfg(test)] + use pretty_assertions::assert_eq; + use std::str; + + #[test] + fn test_num_property() { + let c = NumberingProperty::new(NumberingId::new("abc"), IndentLevel::new(3)); + let b = c.build(); + assert_eq!( + str::from_utf8(&b).unwrap(), + r#""# + ); + } +} diff --git a/docx-core/src/documents/elements/paragraph.rs b/docx-core/src/documents/elements/paragraph.rs index 41849c0..62122ae 100644 --- a/docx-core/src/documents/elements/paragraph.rs +++ b/docx-core/src/documents/elements/paragraph.rs @@ -6,7 +6,7 @@ use crate::xml_builder::*; #[derive(Debug, Clone)] pub struct Paragraph<'a> { pub(crate) children: Vec>, - property: ParagraphProperty, + property: ParagraphProperty<'a>, attrs: Vec<(String, String)>, } @@ -118,6 +118,11 @@ impl<'a> Paragraph<'a> { self.property = self.property.indent(left, special_indent); self } + + pub fn numbering(mut self, id: NumberingId<'a>, level: IndentLevel) -> Self { + self.property = self.property.numbering(id, level); + self + } } impl<'a> BuildXML for Paragraph<'a> { @@ -186,10 +191,25 @@ mod tests { .build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#"Hello + r#"Hello + + + "# ); } + + #[test] + fn test_numbering() { + let b = Paragraph::new() + .add_run(Run::new().add_text("Hello")) + .numbering(NumberingId::new("abc"), IndentLevel::new(1)) + .build(); + assert_eq!( + str::from_utf8(&b).unwrap(), + r#"Hello"# + ); + } } diff --git a/docx-core/src/documents/elements/paragraph_property.rs b/docx-core/src/documents/elements/paragraph_property.rs index b00b94a..e42dec3 100644 --- a/docx-core/src/documents/elements/paragraph_property.rs +++ b/docx-core/src/documents/elements/paragraph_property.rs @@ -1,22 +1,26 @@ -use super::{Indent, Justification, ParagraphStyle, RunProperty}; +use super::{ + Indent, IndentLevel, Justification, NumberingId, NumberingProperty, ParagraphStyle, RunProperty, +}; use crate::documents::BuildXML; use crate::types::{AlignmentType, SpecialIndentType}; use crate::xml_builder::*; #[derive(Debug, Clone)] -pub struct ParagraphProperty { +pub struct ParagraphProperty<'a> { run_property: RunProperty, style: ParagraphStyle, + numbering_property: Option>, alignment: Option, indent: Option, } -impl Default for ParagraphProperty { +impl<'a> Default for ParagraphProperty<'a> { fn default() -> Self { let s: Option<&str> = None; ParagraphProperty { run_property: RunProperty::new(), style: ParagraphStyle::new(s), + numbering_property: None, alignment: None, indent: None, } @@ -28,37 +32,39 @@ impl Default for ParagraphProperty { // This element specifies a set of paragraph properties which shall be applied to the contents of the parent // paragraph after all style/numbering/table properties have been applied to the text. These properties are defined // as direct formatting, since they are directly applied to the paragraph and supersede any formatting from styles. -impl ParagraphProperty { - pub fn new() -> ParagraphProperty { +impl<'a> ParagraphProperty<'a> { + pub fn new() -> ParagraphProperty<'a> { Default::default() } - pub fn align(mut self, alignment_type: AlignmentType) -> ParagraphProperty { + pub fn align(mut self, alignment_type: AlignmentType) -> Self { self.alignment = Some(Justification::new(alignment_type.to_string())); self } - pub fn style(mut self, style_id: &str) -> ParagraphProperty { + pub fn style(mut self, style_id: &str) -> Self { self.style = ParagraphStyle::new(Some(style_id)); self } - pub fn indent( - mut self, - left: usize, - special_indent: Option, - ) -> ParagraphProperty { + pub fn indent(mut self, left: usize, special_indent: Option) -> Self { self.indent = Some(Indent::new(left, special_indent)); self } + + pub fn numbering(mut self, id: NumberingId<'a>, level: IndentLevel) -> Self { + self.numbering_property = Some(NumberingProperty::new(id, level)); + self + } } -impl BuildXML for ParagraphProperty { +impl<'a> BuildXML for ParagraphProperty<'a> { fn build(&self) -> Vec { XMLBuilder::new() .open_paragraph_property() .add_child(&self.style) .add_child(&self.run_property) + .add_optional_child(&self.numbering_property) .add_optional_child(&self.alignment) .add_optional_child(&self.indent) .close() diff --git a/docx-core/src/documents/elements/start.rs b/docx-core/src/documents/elements/start.rs new file mode 100644 index 0000000..8f69b1a --- /dev/null +++ b/docx-core/src/documents/elements/start.rs @@ -0,0 +1,36 @@ +use crate::documents::BuildXML; +use crate::xml_builder::*; + +#[derive(Debug, Clone)] +pub struct Start { + val: usize, +} + +impl Start { + pub fn new(val: usize) -> Start { + Start { val } + } +} + +impl BuildXML for Start { + fn build(&self) -> Vec { + let b = XMLBuilder::new(); + b.start(self.val).build() + } +} + +#[cfg(test)] +mod tests { + + use super::*; + #[cfg(test)] + use pretty_assertions::assert_eq; + use std::str; + + #[test] + fn test_start() { + let c = Start::new(1); + let b = c.build(); + assert_eq!(str::from_utf8(&b).unwrap(), r#""#); + } +} diff --git a/docx-core/src/documents/elements/style.rs b/docx-core/src/documents/elements/style.rs index 9bd8917..7fef5b8 100644 --- a/docx-core/src/documents/elements/style.rs +++ b/docx-core/src/documents/elements/style.rs @@ -5,16 +5,16 @@ use crate::StyleType; use super::{BasedOn, Name, Next, ParagraphProperty, QFormat, RunProperty}; #[derive(Debug)] -pub struct Style { +pub struct Style<'a> { style_id: String, name: Name, style_type: StyleType, run_property: RunProperty, - paragraph_property: ParagraphProperty, + paragraph_property: ParagraphProperty<'a>, } -impl Default for Style { - fn default() -> Style { +impl<'a> Default for Style<'a> { + fn default() -> Self { let name = Name::new(""); let rpr = RunProperty::new(); let ppr = ParagraphProperty::new(); @@ -28,12 +28,12 @@ impl Default for Style { } } -impl Style { +impl<'a> Style<'a> { pub fn new( style_id: impl Into, name: impl Into, style_type: StyleType, - ) -> Style { + ) -> Self { let name = Name::new(name.into()); let default = Default::default(); Style { @@ -65,7 +65,7 @@ impl Style { } } -impl BuildXML for Style { +impl<'a> BuildXML for Style<'a> { fn build(&self) -> Vec { let b = XMLBuilder::new(); // Set "Normal" as default if you need change these values please fix it diff --git a/docx-core/src/documents/mod.rs b/docx-core/src/documents/mod.rs index d5a0453..c1b61b9 100644 --- a/docx-core/src/documents/mod.rs +++ b/docx-core/src/documents/mod.rs @@ -7,6 +7,7 @@ mod document_rels; mod elements; mod font_table; mod history_id; +mod numberings; mod rels; mod settings; mod styles; @@ -22,6 +23,7 @@ pub use document::*; pub use document_rels::*; pub use elements::*; pub use font_table::*; +pub use numberings::*; pub use rels::*; pub use settings::*; pub use styles::*; @@ -33,9 +35,10 @@ pub struct Docx<'a> { rels: Rels, document_rels: DocumentRels, doc_props: DocProps<'a>, - styles: Styles, + styles: Styles<'a>, document: Document<'a>, comments: Comments<'a>, + numberings: Numberings<'a>, settings: Settings, font_table: FontTable, } @@ -51,6 +54,7 @@ impl<'a> Default for Docx<'a> { let settings = Settings::new(); let font_table = FontTable::new(); let comments = Comments::new(); + let numberings = Numberings::new(); Docx { content_type, rels, @@ -61,6 +65,7 @@ impl<'a> Default for Docx<'a> { document_rels, settings, font_table, + numberings, } } } @@ -80,6 +85,11 @@ impl<'a> Docx<'a> { self } + pub fn add_numbering(mut self, num: Numbering<'a>) -> Docx<'a> { + self.numberings = self.numberings.add_numbering(num); + self + } + pub fn build(&mut self) -> XMLDocx { self.update_comments(); XMLDocx { @@ -92,6 +102,7 @@ impl<'a> Docx<'a> { document_rels: self.document_rels.build(), settings: self.settings.build(), font_table: self.font_table.build(), + numberings: self.numberings.build(), } } diff --git a/docx-core/src/documents/numberings.rs b/docx-core/src/documents/numberings.rs new file mode 100644 index 0000000..2f7e5d0 --- /dev/null +++ b/docx-core/src/documents/numberings.rs @@ -0,0 +1,131 @@ +use super::*; +use crate::documents::BuildXML; +use crate::types::*; +use crate::xml_builder::*; + +#[derive(Debug)] +pub struct Numberings<'a> { + numberings: Vec>, +} + +impl<'a> Numberings<'a> { + pub fn new() -> Self { + Default::default() + } + + pub fn add_numbering(mut self, n: Numbering<'a>) -> Self { + self.numberings.push(n); + self + } +} + +impl<'a> Default for Numberings<'a> { + fn default() -> Self { + Self { numberings: vec![] } + } +} + +impl<'a> BuildXML for Numberings<'a> { + fn build(&self) -> Vec { + let mut b = XMLBuilder::new().declaration(Some(true)).open_numbering(); + b = b.add_child(&create_default_numbering()); + for n in &self.numberings { + b = b.add_child(n); + } + b.close().build() + } +} + +fn create_default_numbering() -> Numbering<'static> { + Numbering::new("0") + .add_level( + Level::new( + 0, + Start::new(1), + NumberFormat::new("decimal"), + LevelText::new("%1."), + LevelJc::new("left"), + ) + .indent(420, Some(SpecialIndentType::Hanging(420))), + ) + .add_level( + Level::new( + 1, + Start::new(1), + NumberFormat::new("decimal"), + LevelText::new("(%2)"), + LevelJc::new("left"), + ) + .indent(840, Some(SpecialIndentType::Hanging(420))), + ) + .add_level( + Level::new( + 2, + Start::new(1), + NumberFormat::new("decimalEnclosedCircle"), + LevelText::new("%3"), + LevelJc::new("left"), + ) + .indent(1260, Some(SpecialIndentType::Hanging(420))), + ) + .add_level( + Level::new( + 3, + Start::new(1), + NumberFormat::new("decimal"), + LevelText::new("%4."), + LevelJc::new("left"), + ) + .indent(1680, Some(SpecialIndentType::Hanging(420))), + ) + .add_level( + Level::new( + 4, + Start::new(1), + NumberFormat::new("decimal"), + LevelText::new("(%5)"), + LevelJc::new("left"), + ) + .indent(2100, Some(SpecialIndentType::Hanging(420))), + ) + .add_level( + Level::new( + 5, + Start::new(1), + NumberFormat::new("decimalEnclosedCircle"), + LevelText::new("%6"), + LevelJc::new("left"), + ) + .indent(2520, Some(SpecialIndentType::Hanging(420))), + ) + .add_level( + Level::new( + 6, + Start::new(1), + NumberFormat::new("decimal"), + LevelText::new("%7."), + LevelJc::new("left"), + ) + .indent(2940, Some(SpecialIndentType::Hanging(420))), + ) + .add_level( + Level::new( + 7, + Start::new(1), + NumberFormat::new("decimal"), + LevelText::new("(%8)"), + LevelJc::new("left"), + ) + .indent(3360, Some(SpecialIndentType::Hanging(420))), + ) + .add_level( + Level::new( + 8, + Start::new(1), + NumberFormat::new("decimalEnclosedCircle"), + LevelText::new("%9"), + LevelJc::new("left"), + ) + .indent(3780, Some(SpecialIndentType::Hanging(420))), + ) +} diff --git a/docx-core/src/documents/styles.rs b/docx-core/src/documents/styles.rs index 66edbdc..79607b3 100644 --- a/docx-core/src/documents/styles.rs +++ b/docx-core/src/documents/styles.rs @@ -4,23 +4,23 @@ use crate::types::*; use crate::xml_builder::*; #[derive(Debug)] -pub struct Styles { +pub struct Styles<'a> { doc_defaults: DocDefaults, - styles: Vec