feat: Add styles

main
bokuweb 2019-11-07 13:57:58 +09:00
parent 16ecf4ec8c
commit f5f089c54e
15 changed files with 278 additions and 40 deletions

View File

@ -55,6 +55,8 @@ impl BuildXML for ContentTypes {
mod tests { mod tests {
use super::*; use super::*;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::str; use std::str;
#[test] #[test]

View File

@ -0,0 +1,34 @@
use crate::documents::BuildXML;
use crate::xml_builder::*;
pub struct Color {
val: String,
}
impl Color {
pub fn new(val: impl Into<String>) -> Color {
Color { val: val.into() }
}
}
impl BuildXML for Color {
fn build(&self) -> Vec<u8> {
XMLBuilder::new().color(&self.val).build()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::str;
#[test]
fn test_build() {
let c = Color::new("FFFFFF");
let b = c.build();
assert_eq!(str::from_utf8(&b).unwrap(), r#"<w:color w:val="FFFFFF" />"#);
}
}

View File

@ -19,9 +19,8 @@ impl DocDefaults {
impl BuildXML for DocDefaults { impl BuildXML for DocDefaults {
fn build(&self) -> Vec<u8> { fn build(&self) -> Vec<u8> {
let b = XMLBuilder::new(); let b = XMLBuilder::new();
let run_property_default = self.run_property_default.build();
b.open_doc_defaults() b.open_doc_defaults()
.add_child_buffer(&run_property_default) .add_child(&self.run_property_default)
.close() .close()
.build() .build()
} }

View File

@ -1,4 +1,5 @@
mod based_on; mod based_on;
mod color;
mod doc_defaults; mod doc_defaults;
mod name; mod name;
mod next; mod next;
@ -10,6 +11,7 @@ mod style;
mod sz; mod sz;
pub use based_on::*; pub use based_on::*;
pub use color::*;
pub use doc_defaults::*; pub use doc_defaults::*;
pub use name::*; pub use name::*;
pub use next::*; pub use next::*;

View File

@ -25,6 +25,8 @@ impl BuildXML for ParagraphProperty {
mod tests { mod tests {
use super::*; use super::*;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::str; use std::str;
#[test] #[test]

View File

@ -1,32 +1,45 @@
use super::Sz; use super::{Color, Sz};
use crate::documents::BuildXML; use crate::documents::BuildXML;
use crate::xml_builder::*; use crate::xml_builder::*;
pub struct RunProperty { pub struct RunProperty {
sz: Option<Sz>, sz: Option<Sz>,
color: Option<Color>,
} }
impl RunProperty { impl RunProperty {
pub fn new() -> RunProperty { pub fn new() -> RunProperty {
RunProperty { sz: None } Default::default()
} }
pub fn add_sz(mut self, sz: Sz) -> RunProperty { pub fn add_sz(mut self, sz: usize) -> RunProperty {
self.sz = Some(sz); self.sz = Some(Sz::new(sz));
self self
} }
pub fn add_color(mut self, color: &str) -> RunProperty {
self.color = Some(Color::new(color));
self
}
}
impl Default for RunProperty {
fn default() -> Self {
Self {
sz: None,
color: None,
}
}
} }
impl BuildXML for RunProperty { impl BuildXML for RunProperty {
fn build(&self) -> Vec<u8> { fn build(&self) -> Vec<u8> {
let b = XMLBuilder::new(); let b = XMLBuilder::new();
let b = b.open_run_property(); b.open_run_property()
let b = if let Some(sz) = &self.sz { .add_optional_child(&self.sz)
b.add_child_buffer(&sz.build()) .add_optional_child(&self.color)
} else { .close()
b .build()
};
b.close().build()
} }
} }
@ -40,11 +53,11 @@ mod tests {
#[test] #[test]
fn test_build() { fn test_build() {
let c = RunProperty::new().add_sz(Sz::new(10)); let c = RunProperty::new().add_sz(10).add_color("FFFFFF");
let b = c.build(); let b = c.build();
assert_eq!( assert_eq!(
str::from_utf8(&b).unwrap(), str::from_utf8(&b).unwrap(),
r#"<w:rPr><w:sz w:val="10" /></w:rPr>"# r#"<w:rPr><w:sz w:val="10" /><w:color w:val="FFFFFF" /></w:rPr>"#
); );
} }
} }

View File

@ -16,9 +16,8 @@ impl RunPropertyDefault {
impl BuildXML for RunPropertyDefault { impl BuildXML for RunPropertyDefault {
fn build(&self) -> Vec<u8> { fn build(&self) -> Vec<u8> {
let b = XMLBuilder::new(); let b = XMLBuilder::new();
let run_property = self.run_property.build();
b.open_run_property_default() b.open_run_property_default()
.add_child_buffer(&run_property) .add_child(&self.run_property)
.close() .close()
.build() .build()
} }
@ -28,6 +27,8 @@ impl BuildXML for RunPropertyDefault {
mod tests { mod tests {
use super::*; use super::*;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::str; use std::str;
#[test] #[test]

View File

@ -11,18 +11,14 @@ pub struct Style {
paragraph_property: ParagraphProperty, paragraph_property: ParagraphProperty,
} }
impl Style { impl Default for Style {
pub fn new( fn default() -> Style {
style_id: impl Into<String>, let name = Name::new("");
name: impl Into<String>,
style_type: StyleType,
) -> Style {
let name = Name::new(name.into());
let rpr = RunProperty::new(); let rpr = RunProperty::new();
let ppr = ParagraphProperty::new(); let ppr = ParagraphProperty::new();
Style { Style {
style_id: style_id.into(), style_id: "".to_owned(),
style_type, style_type: StyleType::Paragraph,
name, name,
run_property: rpr, run_property: rpr,
paragraph_property: ppr, paragraph_property: ppr,
@ -30,22 +26,34 @@ impl Style {
} }
} }
impl Style {
pub fn new(
style_id: impl Into<String>,
name: impl Into<String>,
style_type: StyleType,
) -> Style {
let name = Name::new(name.into());
let default = Default::default();
Style {
style_id: style_id.into(),
style_type,
name,
..default
}
}
}
impl BuildXML for Style { impl BuildXML for Style {
fn build(&self) -> Vec<u8> { fn build(&self) -> Vec<u8> {
let b = XMLBuilder::new(); let b = XMLBuilder::new();
let name = self.name.build(); // Set "Normal" as default if you need change these values please fix it
let rpr = self.run_property.build();
let ppr = self.paragraph_property.build();
let based_on = BasedOn::new("Normal").build();
let next = Next::new("Normal").build();
let q_format = QFormat::new().build();
b.open_style(self.style_type, &self.style_id) b.open_style(self.style_type, &self.style_id)
.add_child_buffer(&name) .add_child(&self.name)
.add_child_buffer(&rpr) .add_child(&self.run_property)
.add_child_buffer(&ppr) .add_child(&self.paragraph_property)
.add_child_buffer(&based_on) .add_child(&BasedOn::new("Normal"))
.add_child_buffer(&next) .add_child(&Next::new("Normal"))
.add_child_buffer(&q_format) .add_child(&QFormat::new())
.close() .close()
.build() .build()
} }

View File

@ -3,14 +3,17 @@ mod content_types;
mod doc_props; mod doc_props;
mod elements; mod elements;
mod rels; mod rels;
mod styles;
mod xml_document; mod xml_document;
pub(crate) use build_xml::*; pub(crate) use build_xml::*;
use crate::xml_builder::*;
use content_types::*; use content_types::*;
use doc_props::*; use doc_props::*;
use elements::*; use elements::*;
use rels::*; use rels::*;
use styles::*;
pub(crate) struct Document { pub(crate) struct Document {
content_type: ContentTypes, content_type: ContentTypes,

View File

@ -39,6 +39,8 @@ mod tests {
use super::*; use super::*;
use std::str; use std::str;
#[cfg(test)]
use pretty_assertions::assert_eq;
#[test] #[test]
fn test_build() { fn test_build() {

View File

@ -0,0 +1,59 @@
use crate::documents::BuildXML;
use crate::xml_builder::*;
use super::{DocDefaults, Style, StyleType};
pub struct Styles {
doc_defaults: DocDefaults,
styles: Vec<Style>,
}
impl Styles {
pub fn new() -> Styles {
Default::default()
}
pub fn add_style(mut self, style: Style) -> Self {
self.styles.push(style);
self
}
}
impl Default for Styles {
fn default() -> Self {
Self {
doc_defaults: DocDefaults::new(),
styles: vec![],
}
}
}
impl BuildXML for Styles {
fn build(&self) -> Vec<u8> {
let b = XMLBuilder::new();
b.open_styles()
.add_child(&self.doc_defaults)
.add_children(&self.styles)
.close()
.build()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::str;
#[test]
fn test_build() {
let c = Styles::new().add_style(Style::new("Title", "TitleName", StyleType::Paragraph));
let b = c.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:styles xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 w15"><w:docDefaults><w:rPrDefault><w:rPr /></w:rPrDefault></w:docDefaults><w:style w:type="paragraph" w:styleId="Title"><w:name w:val="TitleName" /><w:rPr /><w:pPr /><w:basedOn w:val="Normal" /><w:next w:val="Normal" /><w:qFormat /></w:style></w:styles>"#
);
}
}

View File

@ -0,0 +1,28 @@
use super::XMLBuilder;
use super::XmlEvent;
impl XMLBuilder {
// i.e. <w:color ... >
pub(crate) fn color(mut self, val: &str) -> Self {
self.writer
.write(XmlEvent::start_element("w:color").attr("w:val", val))
.expect("should write to buf");
self.close()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::str;
#[test]
fn test_color() {
let b = XMLBuilder::new();
let r = b.color("2E74B5").build();
assert_eq!(str::from_utf8(&r).unwrap(), r#"<w:color w:val="2E74B5" />"#);
}
}

View File

@ -2,6 +2,7 @@
mod macros; mod macros;
mod based_on; mod based_on;
mod color;
mod doc_defaults; mod doc_defaults;
mod name; mod name;
mod next; mod next;
@ -13,6 +14,7 @@ mod style;
mod sz; mod sz;
pub use based_on::*; pub use based_on::*;
pub use color::*;
pub use doc_defaults::*; pub use doc_defaults::*;
pub use name::*; pub use name::*;
pub use next::*; pub use next::*;

View File

@ -6,7 +6,9 @@ mod declaration;
mod elements; mod elements;
mod properties; mod properties;
mod relationship; mod relationship;
mod styles;
use crate::BuildXML;
use std::str; use std::str;
use xml::common::XmlVersion; use xml::common::XmlVersion;
use xml::writer::{EmitterConfig, EventWriter, XmlEvent}; use xml::writer::{EmitterConfig, EventWriter, XmlEvent};
@ -50,12 +52,36 @@ impl XMLBuilder {
self.close() self.close()
} }
pub(crate) fn add_child_buffer(mut self, buf: &[u8]) -> Self { pub(crate) fn add_child<T>(mut self, child: &T) -> Self
let text = str::from_utf8(buf).unwrap(); where
T: BuildXML,
{
let buf = child.build();
let text = str::from_utf8(&buf).unwrap();
self.writer.write(text).expect("should write to buf"); self.writer.write(text).expect("should write to buf");
self self
} }
pub(crate) fn add_optional_child<T>(mut self, child: &Option<T>) -> Self
where
T: BuildXML,
{
if let Some(c) = child {
self = self.add_child(c)
}
self
}
pub(crate) fn add_children<T>(mut self, children: &[T]) -> Self
where
T: BuildXML,
{
for c in children {
self = self.add_child(c);
}
self
}
// Close tag // Close tag
pub(crate) fn close(mut self) -> Self { pub(crate) fn close(mut self) -> Self {
self.writer self.writer

View File

@ -0,0 +1,57 @@
use std::fmt;
use super::XMLBuilder;
use super::XmlEvent;
impl XMLBuilder {
// Build w:style element
// i.e. <w:styles ... >
pub(crate) fn open_styles(mut self) -> Self {
self.writer
.write(
XmlEvent::start_element("w:styles")
.attr(
"xmlns:mc",
"http://schemas.openxmlformats.org/markup-compatibility/2006",
)
.attr(
"xmlns:r",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships",
)
.attr(
"xmlns:w",
"http://schemas.openxmlformats.org/wordprocessingml/2006/main",
)
.attr(
"xmlns:w14",
"http://schemas.microsoft.com/office/word/2010/wordml",
)
.attr(
"xmlns:w15",
"http://schemas.microsoft.com/office/word/2012/wordml",
)
.attr("mc:Ignorable", "w14 w15"),
)
.expect("should write to buf");
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::str;
#[test]
fn test_declaration() {
let b = XMLBuilder::new();
let r = b.open_styles().close().build();
assert_eq!(
str::from_utf8(&r).unwrap(),
r#"<w:styles xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 w15" />"#
);
}
}