use anyhow::bail;
use quick_xml::events::{BytesStart, Event};
use std::io::Read;
use crate::excel::XmlReader;
use crate::raw::drawing::{
effect::{effect_container::XlsxEffectDag, effect_list::XlsxEffectList},
fill::{
blip_fill::XlsxBlipFill, gradient_fill::XlsxGradientFill, group_fill::XlsxGroupFill,
no_fill::XlsxNoFill, pattern_fill::XlsxPatternFill, solid_fill::XlsxSolidFill,
},
line::outline::XlsxOutline,
scene::scene_3d_type::XlsxScene3DType,
};
use super::{
custom_geometry::XlsxCustomGeometry, preset_geometry::XlsxPresetGeometry,
shape_3d_type::XlsxShape3DType, transform_2d::XlsxTransform2D,
};
#[derive(Debug, Clone, PartialEq)]
pub struct XlsxShapeProperties {
pub blip_fill: Option<XlsxBlipFill>,
pub custom_geometry: Option<XlsxCustomGeometry>,
pub effect_dag: Option<XlsxEffectDag>,
pub effect_list: Option<XlsxEffectList>,
pub gradient_fill: Option<XlsxGradientFill>,
pub group_fill: Option<XlsxGroupFill>,
pub outline: Option<XlsxOutline>,
pub no_fill: Option<XlsxNoFill>,
pub pattern_fill: Option<XlsxPatternFill>,
pub preset_gemoetry: Option<XlsxPresetGeometry>,
pub scene3d: Option<XlsxScene3DType>,
pub solid_fill: Option<XlsxSolidFill>,
pub shape3d: Option<XlsxShape3DType>,
pub transform2d: Option<XlsxTransform2D>,
pub black_white_mode: Option<String>,
}
impl XlsxShapeProperties {
pub(crate) fn load(reader: &mut XmlReader<impl Read>, e: &BytesStart) -> anyhow::Result<Self> {
let mut properties = Self {
blip_fill: None,
custom_geometry: None,
effect_dag: None,
effect_list: None,
gradient_fill: None,
group_fill: None,
outline: None,
no_fill: None,
pattern_fill: None,
preset_gemoetry: None,
scene3d: None,
solid_fill: None,
shape3d: None,
transform2d: None,
black_white_mode: None,
};
let attributes = e.attributes();
for a in attributes {
match a {
Ok(a) => {
let string_value = String::from_utf8(a.value.to_vec())?;
match a.key.local_name().as_ref() {
b"bwMode" => {
properties.black_white_mode = Some(string_value);
break;
}
_ => {}
}
}
Err(error) => {
bail!(error.to_string())
}
}
}
let mut buf = Vec::new();
loop {
buf.clear();
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"extLst" => {
let _ = reader.read_to_end_into(e.to_end().to_owned().name(), &mut Vec::new());
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"blipFill" => {
properties.blip_fill = Some(XlsxBlipFill::load(reader, e)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"custGeom" => {
properties.custom_geometry = Some(XlsxCustomGeometry::load(reader)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"effectDag" => {
properties.effect_dag = Some(XlsxEffectDag::load_effect_dag(reader, e)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"effectLst" => {
properties.effect_list = Some(XlsxEffectList::load(reader)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"gradFill" => {
properties.gradient_fill = Some(XlsxGradientFill::load(reader, e)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"grpFill" => {
properties.group_fill = Some(true);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"ln" => {
properties.outline = Some(XlsxOutline::load(reader, e)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"noFill" => {
properties.no_fill = Some(true);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"pattFill" => {
properties.pattern_fill = Some(XlsxPatternFill::load(reader, e)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"prstGeom" => {
properties.preset_gemoetry = Some(XlsxPresetGeometry::load(reader, e)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"scene3d" => {
properties.scene3d = Some(XlsxScene3DType::load(reader)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"solidFill" => {
properties.solid_fill = XlsxSolidFill::load(reader, b"solidFill")?;
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"sp3d" => {
properties.shape3d = Some(XlsxShape3DType::load(reader, e)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"xfrm" => {
properties.transform2d = Some(XlsxTransform2D::load(reader, e)?);
}
Ok(Event::End(ref e)) if e.local_name().as_ref() == b"spPr" => break,
Ok(Event::Eof) => bail!("unexpected end of file."),
Err(e) => bail!(e.to_string()),
_ => (),
}
}
Ok(properties)
}
}