2019-11-11 04:10:33 +02:00
|
|
|
use super::XMLBuilder;
|
|
|
|
use super::XmlEvent;
|
|
|
|
use crate::types::*;
|
|
|
|
|
2019-11-11 09:48:28 +02:00
|
|
|
const EXPECT_MESSAGE: &str = "should write buf";
|
|
|
|
|
2019-11-11 04:10:33 +02:00
|
|
|
impl XMLBuilder {
|
|
|
|
// i.e. <w:body... >
|
|
|
|
opened_el!(open_body, "w:body");
|
|
|
|
// i.e. <w:basedOn ... >
|
|
|
|
only_str_val_el!(based_on, "w:basedOn");
|
|
|
|
// i.e. <w:t ... >
|
|
|
|
pub(crate) fn text(mut self, text: &str, preserve_space: bool) -> Self {
|
|
|
|
let space = if preserve_space {
|
|
|
|
"preserve"
|
|
|
|
} else {
|
|
|
|
"default"
|
|
|
|
};
|
|
|
|
self.writer
|
|
|
|
.write(XmlEvent::start_element("w:t").attr("xml:space", space))
|
2019-11-11 09:48:28 +02:00
|
|
|
.expect(EXPECT_MESSAGE);
|
|
|
|
self.writer.write(text).expect(EXPECT_MESSAGE);
|
2019-11-11 04:10:33 +02:00
|
|
|
self.close()
|
|
|
|
}
|
2019-11-15 11:15:43 +02:00
|
|
|
// i.e. <w:delText ... >
|
|
|
|
pub(crate) fn delete_text(mut self, text: &str, preserve_space: bool) -> Self {
|
|
|
|
let space = if preserve_space {
|
|
|
|
"preserve"
|
|
|
|
} else {
|
|
|
|
"default"
|
|
|
|
};
|
|
|
|
self.writer
|
|
|
|
.write(XmlEvent::start_element("w:delText").attr("xml:space", space))
|
|
|
|
.expect(EXPECT_MESSAGE);
|
|
|
|
self.writer.write(text).expect(EXPECT_MESSAGE);
|
|
|
|
self.close()
|
|
|
|
}
|
2019-11-11 04:10:33 +02:00
|
|
|
// i.e. <w:r ... >
|
|
|
|
opened_el!(open_run, "w:r");
|
|
|
|
opened_el!(open_run_property, "w:rPr");
|
|
|
|
opened_el!(open_run_property_default, "w:rPrDefault");
|
|
|
|
// i.e. <w:qFormat ... >
|
|
|
|
closed_el!(q_format, "w:qFormat");
|
|
|
|
// i.e. <w:p ... >
|
2019-11-13 10:52:02 +02:00
|
|
|
// opened_el!(open_paragraph, "w:p");
|
|
|
|
opened_el_with_attrs!(open_paragraph, "w:p");
|
2019-11-11 04:10:33 +02:00
|
|
|
opened_el!(open_paragraph_property, "w:pPr");
|
|
|
|
opened_el!(open_doc_defaults, "w:docDefaults");
|
|
|
|
// i.e. <w:name ... >
|
|
|
|
only_str_val_el!(name, "w:name");
|
2019-11-11 06:05:07 +02:00
|
|
|
// i.e. <w:jc ... >
|
|
|
|
only_str_val_el!(justification, "w:jc");
|
|
|
|
// i.e. <w:pStyle ... >
|
2019-11-11 07:39:22 +02:00
|
|
|
only_str_val_el!(paragraph_style, "w:pStyle");
|
2019-11-11 04:10:33 +02:00
|
|
|
// i.e. <w:sz ... >
|
2019-11-11 08:36:26 +02:00
|
|
|
only_usize_val_el!(sz, "w:sz");
|
|
|
|
// i.e. <w:szCs ... >
|
|
|
|
only_usize_val_el!(sz_cs, "w:szCs");
|
2019-11-13 09:08:25 +02:00
|
|
|
|
|
|
|
closed_el!(b, "w:b");
|
|
|
|
closed_el!(b_cs, "w:bCs");
|
|
|
|
|
|
|
|
closed_el!(i, "w:i");
|
|
|
|
closed_el!(i_cs, "w:iCs");
|
2019-11-11 04:10:33 +02:00
|
|
|
// Build w:style element
|
|
|
|
// i.e. <w:style ... >
|
|
|
|
pub(crate) fn open_style(mut self, style_type: StyleType, id: &str) -> Self {
|
|
|
|
self.writer
|
|
|
|
.write(
|
|
|
|
XmlEvent::start_element("w:style")
|
|
|
|
.attr("w:type", &style_type.to_string())
|
|
|
|
.attr("w:styleId", id),
|
|
|
|
)
|
2019-11-11 09:48:28 +02:00
|
|
|
.expect(EXPECT_MESSAGE);
|
2019-11-11 04:10:33 +02:00
|
|
|
self
|
|
|
|
}
|
|
|
|
// i.e. <w:next ... >
|
2019-11-13 09:08:25 +02:00
|
|
|
only_str_val_el!(next, "w:next");
|
2019-11-11 04:10:33 +02:00
|
|
|
|
|
|
|
// i.e. <w:color ... >
|
2019-11-13 09:08:25 +02:00
|
|
|
only_str_val_el!(color, "w:color");
|
|
|
|
|
|
|
|
// i.e. <w:highlight ... >
|
|
|
|
only_str_val_el!(highlight, "w:highlight");
|
2019-11-11 09:48:28 +02:00
|
|
|
|
2019-12-04 09:28:11 +02:00
|
|
|
// i.e. <w:u ... >
|
|
|
|
only_str_val_el!(underline, "w:u");
|
|
|
|
|
2019-11-11 09:48:28 +02:00
|
|
|
// i.e. <w:ind ... >
|
|
|
|
pub(crate) fn indent(mut self, left: usize, special_indent: Option<SpecialIndentType>) -> Self {
|
|
|
|
let left = &format!("{}", left);
|
|
|
|
let base = XmlEvent::start_element("w:ind").attr("w:left", left);
|
|
|
|
match special_indent {
|
|
|
|
Some(SpecialIndentType::FirstLine(v)) => self
|
|
|
|
.writer
|
|
|
|
.write(base.attr("w:firstLine", &format!("{}", v)))
|
|
|
|
.expect(EXPECT_MESSAGE),
|
|
|
|
Some(SpecialIndentType::Hanging(v)) => self
|
|
|
|
.writer
|
|
|
|
.write(base.attr("w:hanging", &format!("{}", v)))
|
|
|
|
.expect(EXPECT_MESSAGE),
|
|
|
|
_ => self.writer.write(base).expect(EXPECT_MESSAGE),
|
|
|
|
};
|
2019-11-11 04:10:33 +02:00
|
|
|
self.close()
|
|
|
|
}
|
2019-11-12 06:33:45 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// Table elements
|
|
|
|
//
|
|
|
|
opened_el!(open_table, "w:tbl");
|
|
|
|
opened_el!(open_table_property, "w:tblPr");
|
|
|
|
opened_el!(open_table_grid, "w:tblGrid");
|
|
|
|
opened_el!(open_table_row, "w:tr");
|
|
|
|
opened_el!(open_table_row_property, "w:trPr");
|
|
|
|
opened_el!(open_table_cell, "w:tc");
|
|
|
|
opened_el!(open_table_cell_property, "w:tcPr");
|
2019-11-12 11:20:50 +02:00
|
|
|
opened_el!(open_table_cell_borders, "w:tcBorders");
|
2019-11-12 06:33:45 +02:00
|
|
|
opened_el!(open_table_borders, "w:tblBorders");
|
|
|
|
opened_el!(open_table_cell_margins, "w:tblCellMar");
|
|
|
|
|
|
|
|
closed_w_with_type_el!(table_width, "w:tblW");
|
|
|
|
closed_w_with_type_el!(table_indent, "w:tblInd");
|
|
|
|
closed_w_with_type_el!(grid_column, "w:gridCol");
|
|
|
|
closed_w_with_type_el!(table_cell_width, "w:tcW");
|
|
|
|
|
2019-11-13 08:00:53 +02:00
|
|
|
only_usize_val_el!(grid_span, "w:gridSpan");
|
|
|
|
only_str_val_el!(vertical_merge, "w:vMerge");
|
|
|
|
|
2019-11-12 10:32:50 +02:00
|
|
|
closed_w_with_type_el!(margin_top, "w:top");
|
|
|
|
closed_w_with_type_el!(margin_left, "w:left");
|
|
|
|
closed_w_with_type_el!(margin_bottom, "w:bottom");
|
|
|
|
closed_w_with_type_el!(margin_right, "w:right");
|
|
|
|
|
|
|
|
closed_border_el!(border_top, "w:top");
|
|
|
|
closed_border_el!(border_left, "w:left");
|
|
|
|
closed_border_el!(border_bottom, "w:bottom");
|
|
|
|
closed_border_el!(border_right, "w:right");
|
|
|
|
closed_border_el!(border_inside_h, "w:insideH");
|
|
|
|
closed_border_el!(border_inside_v, "w:insideV");
|
|
|
|
|
|
|
|
closed_el!(shd, "w:shd", "w:fill", "w:val");
|
2019-11-13 09:51:58 +02:00
|
|
|
|
|
|
|
closed_el!(tab, "w:tab");
|
|
|
|
closed_el!(br, "w:br", "w:type");
|
2019-11-14 08:54:39 +02:00
|
|
|
closed_el!(zoom, "w:zoom", "w:percent");
|
|
|
|
only_usize_val_el!(default_tab_stop, "w:defaultTabStop");
|
2019-11-14 12:21:45 +02:00
|
|
|
|
|
|
|
opened_el!(open_font, "w:font", "w:name");
|
|
|
|
only_str_val_el!(pitch, "w:pitch");
|
|
|
|
only_str_val_el!(family, "w:family");
|
|
|
|
only_str_val_el!(charset, "w:charset");
|
2019-11-14 18:50:30 +02:00
|
|
|
|
|
|
|
only_usize_val_el!(section_property, "w:sectPr");
|
|
|
|
only_str_val_el!(type_tag, "w:type");
|
|
|
|
closed_el!(page_size, "w:pgSz", "w:w", "w:h");
|
|
|
|
closed_el!(
|
|
|
|
page_margin,
|
|
|
|
"w:pgMar",
|
|
|
|
"w:left",
|
|
|
|
"w:right",
|
|
|
|
"w:header",
|
|
|
|
"w:top",
|
|
|
|
"w:footer",
|
|
|
|
"w:bottom",
|
|
|
|
"w:gutter"
|
|
|
|
);
|
2019-11-15 11:15:43 +02:00
|
|
|
|
2019-12-04 11:26:09 +02:00
|
|
|
opened_el!(open_insert, "w:ins", "w:id", "w:author", "w:date");
|
|
|
|
opened_el!(open_delete, "w:del", "w:id", "w:author", "w:date");
|
2019-12-04 09:55:03 +02:00
|
|
|
|
|
|
|
closed_el!(bookmark_start, "w:bookmarkStart", "w:id", "w:name");
|
|
|
|
closed_el!(bookmark_end, "w:bookmarkEnd", "w:id");
|
2019-12-04 10:25:31 +02:00
|
|
|
|
|
|
|
closed_el!(comment_range_start, "w:commentRangeStart", "w:id");
|
|
|
|
closed_el!(comment_range_end, "w:commentRangeEnd", "w:id");
|
2019-12-04 11:26:09 +02:00
|
|
|
opened_el!(open_comment, "w:comment", "w:id", "w:author", "w:date");
|
2019-11-11 04:10:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
#[cfg(test)]
|
|
|
|
use pretty_assertions::assert_eq;
|
|
|
|
use std::str;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_sz() {
|
|
|
|
let b = XMLBuilder::new();
|
|
|
|
let r = b.sz(20).build();
|
|
|
|
assert_eq!(str::from_utf8(&r).unwrap(), r#"<w:sz w:val="20" />"#);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_declaration() {
|
|
|
|
let b = XMLBuilder::new();
|
|
|
|
let r = b
|
|
|
|
.open_style(StyleType::Paragraph, "Heading")
|
|
|
|
.close()
|
|
|
|
.build();
|
|
|
|
assert_eq!(
|
|
|
|
str::from_utf8(&r).unwrap(),
|
|
|
|
r#"<w:style w:type="paragraph" w:styleId="Heading" />"#
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_next() {
|
|
|
|
let b = XMLBuilder::new();
|
|
|
|
let r = b.next("Normal").build();
|
|
|
|
assert_eq!(str::from_utf8(&r).unwrap(), r#"<w:next w:val="Normal" />"#);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_name() {
|
|
|
|
let b = XMLBuilder::new();
|
|
|
|
let r = b.name("Heading").build();
|
|
|
|
assert_eq!(str::from_utf8(&r).unwrap(), r#"<w:name w:val="Heading" />"#);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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" />"#);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_based_on() {
|
|
|
|
let b = XMLBuilder::new();
|
|
|
|
let r = b.based_on("Normal").build();
|
|
|
|
assert_eq!(
|
|
|
|
str::from_utf8(&r).unwrap(),
|
|
|
|
r#"<w:basedOn w:val="Normal" />"#
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|