#[cfg(test)]
mod tests;
use crate::{
Borders, Fills, Fonts, Format, HorizontalAlignment, NumFormats,
Result, VerticalAlignment, XmlWritable, XmlWriter,
};
use indexmap::{indexmap, IndexSet};
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Hash, Eq, PartialEq, Debug)]
struct FormatData {
num_format: Option<usize>,
font: Option<usize>,
fill: Option<usize>,
border: Option<usize>,
horizontal_alignment: Option<HorizontalAlignment>,
vertical_alignment: Option<VerticalAlignment>,
}
impl XmlWritable for FormatData {
fn write_xml<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
let mut attrs = indexmap! {
"fontId" =>
format!("{}", self.font.unwrap_or_default()),
"numFmtId" =>
format!("{}", self.num_format.unwrap_or_default()),
"fillId" =>
format!("{}", self.fill.unwrap_or_default()),
"borderId" =>
format!("{}", self.border.unwrap_or_default()),
"xfId" => "0".to_string(),
};
if self.font.is_some() {
attrs.insert("applyFont", "1".to_string());
}
if self.fill.is_some() {
attrs.insert("applyFill", "1".to_string());
}
if self.border.is_some() {
attrs.insert("applyBorder", "1".to_string());
}
if self.horizontal_alignment.is_some()
|| self.vertical_alignment.is_some()
{
attrs.insert("applyAlignment", "1".to_string());
}
let tag = "xf";
match (self.horizontal_alignment, self.vertical_alignment) {
(None, None) => {
w.empty_tag_with_attrs(tag, attrs)?;
}
_ => {
w.start_tag_with_attrs(tag, attrs)?;
self.write_alignment(w)?;
w.end_tag(tag)?;
}
}
Ok(())
}
}
impl FormatData {
fn write_alignment<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
let mut attrs = indexmap! {};
if let Some(h) = self.horizontal_alignment {
attrs.insert("horizontal", h.xml_identifier());
}
if let Some(v) = self.vertical_alignment {
if let Some(s) = v.xml_identifier() {
attrs.insert("vertical", s);
}
}
w.empty_tag_with_attrs("alignment", attrs)
}
}
#[derive(Default, Debug)]
struct Inner {
formats: IndexSet<FormatData>,
num_formats: NumFormats,
fonts: Fonts,
fills: Fills,
borders: Borders,
}
#[derive(Clone, Debug)]
pub(crate) struct Formats {
inner: Rc<RefCell<Inner>>,
}
impl Default for Formats {
fn default() -> Self {
let mut inner = Inner::default();
inner.create_or_get_index_format(&Format::default());
Formats {
inner: Rc::new(RefCell::new(inner)),
}
}
}
impl Formats {
pub fn create_or_get_index(
&mut self,
format: Option<&Format>,
) -> Option<usize> {
self.inner.borrow_mut().create_or_get_index(format)
}
}
impl XmlWritable for Formats {
fn write_xml<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
self.inner.borrow().write_xml(w)
}
}
impl XmlWritable for Inner {
fn write_xml<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
let tag = "styleSheet";
let attrs = indexmap! {
"xmlns" =>
"http://schemas.openxmlformats.org/spreadsheetml/2006/main",
};
w.start_tag_with_attrs(tag, attrs)?;
self.write_num_fmts(w)?;
self.write_fonts(w)?;
self.write_fills(w)?;
self.write_borders(w)?;
self.write_cell_style_xfs(w)?;
self.write_cell_xfs(w)?;
self.write_cell_styles(w)?;
self.write_dxfs(w)?;
self.write_table_styles(w)?;
w.end_tag(tag)?;
Ok(())
}
}
impl Inner {
fn create_or_get_index(
&mut self,
format: Option<&Format>,
) -> Option<usize> {
format.map(|f| self.create_or_get_index_format(f))
}
fn create_or_get_index_format(&mut self, f: &Format) -> usize {
let f = self.build_format_data(f);
self.formats.insert_full(f).0
}
fn build_format_data(&mut self, f: &Format) -> FormatData {
let font = if f.font == Default::default() {
None
} else {
Some(&f.font)
};
let num_format = if f.num_format == Default::default() {
None
} else {
Some(&f.num_format)
};
let fill = if f.fill == Default::default() {
None
} else {
Some(&f.fill)
};
let borders = if f.borders == Default::default() {
None
} else {
Some(&f.borders)
};
FormatData {
font: self.fonts.create_or_get_index(font),
num_format: self.num_formats.create_or_get_index(num_format),
fill: self.fills.create_or_get_index(fill),
border: self.borders.create_or_get_index(borders),
horizontal_alignment: f.horizontal_alignment,
vertical_alignment: f.vertical_alignment,
}
}
fn write_num_fmts<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
self.num_formats.write_xml(w)
}
fn write_fonts<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
self.fonts.write_xml(w)
}
fn write_fills<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
self.fills.write_xml(w)
}
fn write_borders<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
self.borders.write_xml(w)
}
fn write_cell_style_xfs<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
let tag = "cellStyleXfs";
let attrs = indexmap! { "count" => "1" };
w.start_tag_with_attrs(tag, attrs)?;
{
let tag = "xf";
let attrs = indexmap! {
"numFmtId" => "0",
"fontId" => "0",
"fillId" => "0",
"borderId" => "0"
};
w.empty_tag_with_attrs(tag, attrs)?;
}
w.end_tag(tag)?;
Ok(())
}
fn write_cell_xfs<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
let tag = "cellXfs";
let attrs = indexmap! {
"count" => format!("{}", self.formats.len()),
};
w.start_tag_with_attrs(tag, attrs)?;
{
for format in self.formats.iter() {
format.write_xml(w)?;
}
}
w.end_tag(tag)?;
Ok(())
}
fn write_cell_styles<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
let tag = "cellStyles";
let attrs = indexmap! { "count" => "1" };
w.start_tag_with_attrs(tag, attrs)?;
{
let tag = "cellStyle";
let attrs = indexmap! {
"name" => "Normal",
"xfId" => "0",
"builtinId" => "0",
};
w.empty_tag_with_attrs(tag, attrs)?;
}
w.end_tag(tag)?;
Ok(())
}
fn write_dxfs<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
w.empty_tag_with_attrs("dxfs", indexmap! { "count" => "0" })
}
fn write_table_styles<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
w.empty_tag_with_attrs(
"tableStyles",
indexmap! {
"count" => "0",
"defaultTableStyle" => "TableStyleMedium9",
"defaultPivotStyle" => "PivotStyleLight16",
},
)
}
}