use super::util::XmlNodeExt;
use crate::{
error::{
LimitViolationError, MaxOccurs, MissingAttributeError, MissingChildNodeError, NotGroupMemberError,
ParseEnumError,
},
shared::drawingml::{
audiovideo::EmbeddedWAVAudioFile,
colors::Color,
core::{AnimationElementChoice, AnimationGraphicalObjectBuildProperties},
simpletypes::{
Angle, DrawingElementId, FixedPercentage, Percentage, PositiveFixedPercentage, PositivePercentage, ShapeId,
},
},
xml::{parse_xml_bool, XmlNode},
xsdtypes::{XsdChoice, XsdType},
};
use std::{error::Error, str::FromStr};
pub type Result<T> = ::std::result::Result<T, Box<dyn Error>>;
pub type Index = u32;
pub type TLTimeNodeId = u32;
pub type TLSubShapeId = ShapeId;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLChartSubelementType {
#[strum(serialize = "gridLegend")]
GridLegend,
#[strum(serialize = "series")]
Series,
#[strum(serialize = "category")]
Category,
#[strum(serialize = "ptInSeries")]
PointInSeries,
#[strum(serialize = "ptInCategory")]
PointInCategory,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLParaBuildType {
#[strum(serialize = "allAtOnce")]
AllAtOnce,
#[strum(serialize = "p")]
Paragraph,
#[strum(serialize = "cust")]
Custom,
#[strum(serialize = "whole")]
Whole,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLDiagramBuildType {
#[strum(serialize = "whole")]
Whole,
#[strum(serialize = "depthByNode")]
DepthByNode,
#[strum(serialize = "depthByBranch")]
DepthByBranch,
#[strum(serialize = "breadthByNode")]
BreadthByNode,
#[strum(serialize = "breadthByLvl")]
BreadthByLevel,
#[strum(serialize = "cw")]
Clockwise,
#[strum(serialize = "cwIn")]
ClockwiseIn,
#[strum(serialize = "cwOut")]
ClockwiseOut,
#[strum(serialize = "ccw")]
CounterClockwise,
#[strum(serialize = "ccwIn")]
CounterClockwiseIn,
#[strum(serialize = "ccwOut")]
CounterClockwiseOut,
#[strum(serialize = "inByRing")]
InByRing,
#[strum(serialize = "outByRing")]
OutByRing,
#[strum(serialize = "up")]
Up,
#[strum(serialize = "down")]
Down,
#[strum(serialize = "allAtOnce")]
AllAtOnce,
#[strum(serialize = "cust")]
Custom,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLOleChartBuildType {
#[strum(serialize = "allAtOnce")]
AllAtOnce,
#[strum(serialize = "series")]
Series,
#[strum(serialize = "category")]
Category,
#[strum(serialize = "seriesEl")]
SeriesElement,
#[strum(serialize = "categoryEl")]
CategoryElement,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLTriggerRuntimeNode {
#[strum(serialize = "first")]
First,
#[strum(serialize = "last")]
Last,
#[strum(serialize = "all")]
All,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLTriggerEvent {
#[strum(serialize = "onBegin")]
OnBegin,
#[strum(serialize = "onEnd")]
OnEnd,
#[strum(serialize = "begin")]
Begin,
#[strum(serialize = "end")]
End,
#[strum(serialize = "onClick")]
OnClick,
#[strum(serialize = "onDblClick")]
OnDoubleClick,
#[strum(serialize = "onMouseOver")]
OnMouseOver,
#[strum(serialize = "onMouseOut")]
OnMouseOut,
#[strum(serialize = "onNext")]
OnNext,
#[strum(serialize = "onPrev")]
OnPrev,
#[strum(serialize = "onStopAudio")]
OnStopAudio,
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, EnumString)]
pub enum IterateType {
#[strum(serialize = "el")]
Element,
#[strum(serialize = "wd")]
Word,
#[strum(serialize = "lt")]
Letter,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLTimeNodePresetClassType {
#[strum(serialize = "entr")]
Entrance,
#[strum(serialize = "exit")]
Exit,
#[strum(serialize = "emph")]
Emphasis,
#[strum(serialize = "path")]
Path,
#[strum(serialize = "verb")]
Verb,
#[strum(serialize = "mediacall")]
Mediacall,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLTimeNodeRestartType {
#[strum(serialize = "always")]
Always,
#[strum(serialize = "whenNotActive")]
WhenNotActive,
#[strum(serialize = "never")]
Never,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLTimeNodeFillType {
#[strum(serialize = "remove")]
Remove,
#[strum(serialize = "freeze")]
Freeze,
#[strum(serialize = "hold")]
Hold,
#[strum(serialize = "transition")]
Transition,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLTimeNodeSyncType {
#[strum(serialize = "canSlip")]
CanSlip,
#[strum(serialize = "locked")]
Locked,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLTimeNodeMasterRelation {
#[strum(serialize = "sameClick")]
SameClick,
#[strum(serialize = "lastClick")]
LastClick,
#[strum(serialize = "nextClick")]
NextClick,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLTimeNodeType {
#[strum(serialize = "clickEffect")]
ClickEffect,
#[strum(serialize = "withEffect")]
WithEffect,
#[strum(serialize = "afterEffect")]
AfterEffect,
#[strum(serialize = "mainSequence")]
MainSequence,
#[strum(serialize = "interactiveSeq")]
InteractiveSequence,
#[strum(serialize = "clickPar")]
ClickParagraph,
#[strum(serialize = "withGroup")]
WithGroup,
#[strum(serialize = "afterGroup")]
AfterGroup,
#[strum(serialize = "tmRoot")]
TimingRoot,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLNextActionType {
#[strum(serialize = "none")]
None,
#[strum(serialize = "seek")]
Seek,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLPreviousActionType {
#[strum(serialize = "none")]
None,
#[strum(serialize = "skipTimed")]
SkipTimed,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLAnimateBehaviorCalcMode {
#[strum(serialize = "discrete")]
Discrete,
#[strum(serialize = "fmla")]
Formula,
#[strum(serialize = "lin")]
Linear,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLAnimateBehaviorValueType {
#[strum(serialize = "clr")]
Color,
#[strum(serialize = "num")]
Number,
#[strum(serialize = "str")]
String,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLBehaviorAdditiveType {
#[strum(serialize = "base")]
Base,
#[strum(serialize = "sum")]
Sum,
#[strum(serialize = "repl")]
Replace,
#[strum(serialize = "mult")]
Multiply,
#[strum(serialize = "none")]
None,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLBehaviorAccumulateType {
#[strum(serialize = "none")]
None,
#[strum(serialize = "always")]
Always,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLBehaviorTransformType {
#[strum(serialize = "pt")]
Point,
#[strum(serialize = "img")]
Image,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLBehaviorOverrideType {
#[strum(serialize = "normal")]
Normal,
#[strum(serialize = "childStyle")]
ChildStyle,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLAnimateColorSpace {
#[strum(serialize = "rgb")]
Rgb,
#[strum(serialize = "hsl")]
Hsl,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLAnimateColorDirection {
#[strum(serialize = "cw")]
Clockwise,
#[strum(serialize = "ccw")]
CounterClockwise,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLAnimateEffectTransition {
#[strum(serialize = "in")]
In,
#[strum(serialize = "out")]
Out,
#[strum(serialize = "none")]
None,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLAnimateMotionBehaviorOrigin {
#[strum(serialize = "parent")]
Parent,
#[strum(serialize = "layout")]
Layout,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLAnimateMotionPathEditMode {
#[strum(serialize = "relative")]
Relative,
#[strum(serialize = "fixed")]
Fixed,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, EnumString)]
pub enum TLCommandType {
#[strum(serialize = "evt")]
Event,
#[strum(serialize = "call")]
Call,
#[strum(serialize = "verb")]
Verb,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct IndexRange {
pub start: Index,
pub end: Index,
}
impl IndexRange {
pub fn new(start: Index, end: Index) -> Self {
Self { start, end }
}
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut start = None;
let mut end = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"st" => start = Some(value.parse()?),
"end" => end = Some(value.parse()?),
_ => (),
}
}
let start = start.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "st"))?;
let end = end.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "end"))?;
Ok(Self { start, end })
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TimeNodeGroup {
Parallel(Box<TLCommonTimeNodeData>),
Sequence(Box<TLTimeNodeSequence>),
Exclusive(Box<TLCommonTimeNodeData>),
Animate(Box<TLAnimateBehavior>),
AnimateColor(Box<TLAnimateColorBehavior>),
AnimateEffect(Box<TLAnimateEffectBehavior>),
AnimateMotion(Box<TLAnimateMotionBehavior>),
AnimateRotation(Box<TLAnimateRotationBehavior>),
AnimateScale(Box<TLAnimateScaleBehavior>),
Command(Box<TLCommandBehavior>),
Set(Box<TLSetBehavior>),
Audio(Box<TLMediaNodeAudio>),
Video(Box<TLMediaNodeVideo>),
}
impl XsdType for TimeNodeGroup {
fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
match xml_node.local_name() {
"par" => Ok(TimeNodeGroup::Parallel(Box::new(
TLCommonTimeNodeData::from_xml_element(xml_node)?,
))),
"seq" => Ok(TimeNodeGroup::Sequence(Box::new(TLTimeNodeSequence::from_xml_element(
xml_node,
)?))),
"excl" => Ok(TimeNodeGroup::Exclusive(Box::new(
TLCommonTimeNodeData::from_xml_element(xml_node)?,
))),
"anim" => Ok(TimeNodeGroup::Animate(Box::new(TLAnimateBehavior::from_xml_element(
xml_node,
)?))),
"animClr" => Ok(TimeNodeGroup::AnimateColor(Box::new(
TLAnimateColorBehavior::from_xml_element(xml_node)?,
))),
"animEffect" => Ok(TimeNodeGroup::AnimateEffect(Box::new(
TLAnimateEffectBehavior::from_xml_element(xml_node)?,
))),
"animMotion" => Ok(TimeNodeGroup::AnimateMotion(Box::new(
TLAnimateMotionBehavior::from_xml_element(xml_node)?,
))),
"animRot" => Ok(TimeNodeGroup::AnimateRotation(Box::new(
TLAnimateRotationBehavior::from_xml_element(xml_node)?,
))),
"animScale" => Ok(TimeNodeGroup::AnimateScale(Box::new(
TLAnimateScaleBehavior::from_xml_element(xml_node)?,
))),
"cmd" => Ok(TimeNodeGroup::Command(Box::new(TLCommandBehavior::from_xml_element(
xml_node,
)?))),
"set" => Ok(TimeNodeGroup::Set(Box::new(TLSetBehavior::from_xml_element(xml_node)?))),
"audio" => Ok(TimeNodeGroup::Audio(Box::new(TLMediaNodeAudio::from_xml_element(
xml_node,
)?))),
"video" => Ok(TimeNodeGroup::Video(Box::new(TLMediaNodeVideo::from_xml_element(
xml_node,
)?))),
_ => Err(Box::new(NotGroupMemberError::new(
xml_node.name.clone(),
"TimeNodeGroup",
))),
}
}
}
impl XsdChoice for TimeNodeGroup {
fn is_choice_member<T>(name: T) -> bool
where
T: AsRef<str>,
{
match name.as_ref() {
"par" | "seq" | "excl" | "anim" | "animClr" | "animEffect" | "animMotion" | "animRot" | "animScale"
| "cmd" | "set" | "audio" | "video" => true,
_ => false,
}
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct TLTimeNodeList(pub Vec<TimeNodeGroup>);
impl TLTimeNodeList {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let vec = xml_node
.child_nodes
.iter()
.filter_map(TimeNodeGroup::try_from_xml_element)
.collect::<Result<Vec<_>>>()?;
Ok(Self(vec))
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLCommonBehaviorData {
pub additive: Option<TLBehaviorAdditiveType>,
pub accumulate: Option<TLBehaviorAccumulateType>,
pub transform_type: Option<TLBehaviorTransformType>,
pub from: Option<String>,
pub to: Option<String>,
pub by: Option<String>,
pub runtime_context: Option<String>,
pub override_type: Option<TLBehaviorOverrideType>,
pub common_time_node_data: Box<TLCommonTimeNodeData>,
pub target_element: TLTimeTargetElement,
pub attr_name_list: Option<Vec<String>>,
}
impl TLCommonBehaviorData {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut additive = None;
let mut accumulate = None;
let mut transform_type = None;
let mut from = None;
let mut to = None;
let mut by = None;
let mut runtime_context = None;
let mut override_type = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"additive" => additive = Some(value.parse()?),
"accumulate" => accumulate = Some(value.parse()?),
"xfrmType" => transform_type = Some(value.parse()?),
"from" => from = Some(value.clone()),
"to" => to = Some(value.clone()),
"by" => by = Some(value.clone()),
"rctx" => runtime_context = Some(value.clone()),
"override" => override_type = Some(value.parse()?),
_ => (),
}
}
let mut common_time_node_data = None;
let mut target_element = None;
let mut attr_name_list = None;
for child_node in &xml_node.child_nodes {
match child_node.local_name() {
"cTn" => common_time_node_data = Some(Box::new(TLCommonTimeNodeData::from_xml_element(child_node)?)),
"tgtEl" => {
target_element = Some(
child_node
.child_nodes
.first()
.ok_or_else(|| {
MissingChildNodeError::new(child_node.name.clone(), "sldTgt|sndTgt|spTgt|inkTgt").into()
})
.and_then(TLTimeTargetElement::from_xml_element)?,
);
}
"attrNameLst" => {
let vec = child_node
.child_nodes
.iter()
.filter(|attr_name_node| attr_name_node.local_name() == "attrName")
.map(|attr_name_node| attr_name_node.text.as_ref().cloned().unwrap_or_default())
.collect::<Vec<_>>();
if vec.is_empty() {
return Err(Box::new(LimitViolationError::new(
child_node.name.clone(),
"attrName",
1,
MaxOccurs::Unbounded,
0,
)));
}
attr_name_list = Some(vec);
}
_ => (),
}
}
let common_time_node_data =
common_time_node_data.ok_or_else(|| MissingChildNodeError::new(xml_node.name.clone(), "cTn"))?;
let target_element =
target_element.ok_or_else(|| MissingChildNodeError::new(xml_node.name.clone(), "tgtEl"))?;
Ok(Self {
additive,
accumulate,
transform_type,
from,
to,
by,
runtime_context,
override_type,
common_time_node_data,
target_element,
attr_name_list,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLCommonMediaNodeData {
pub volume: Option<PositiveFixedPercentage>,
pub mute: Option<bool>,
pub number_of_slides: Option<u32>,
pub show_when_stopped: Option<bool>,
pub common_time_node_data: Box<TLCommonTimeNodeData>,
pub target_element: TLTimeTargetElement,
}
impl TLCommonMediaNodeData {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut volume = None;
let mut mute = None;
let mut number_of_slides = None;
let mut show_when_stopped = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"vol" => volume = Some(value.parse()?),
"mute" => mute = Some(parse_xml_bool(value)?),
"numSld" => number_of_slides = Some(value.parse()?),
"showWhenStopped" => show_when_stopped = Some(parse_xml_bool(value)?),
_ => (),
}
}
let mut common_time_node_data = None;
let mut target_element = None;
for child_node in &xml_node.child_nodes {
match child_node.local_name() {
"cTn" => common_time_node_data = Some(Box::new(TLCommonTimeNodeData::from_xml_element(child_node)?)),
"tgtEl" => {
target_element = Some(
child_node
.child_nodes
.first()
.ok_or_else(|| {
MissingChildNodeError::new(child_node.name.clone(), "TLTimeTargetElement").into()
})
.and_then(TLTimeTargetElement::from_xml_element)?,
)
}
_ => (),
}
}
let common_time_node_data =
common_time_node_data.ok_or_else(|| MissingChildNodeError::new(xml_node.name.clone(), "cTn"))?;
let target_element =
target_element.ok_or_else(|| MissingChildNodeError::new(xml_node.name.clone(), "tgtEl"))?;
Ok(Self {
volume,
mute,
number_of_slides,
show_when_stopped,
common_time_node_data,
target_element,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLBuildParagraph {
pub build_common: TLBuildCommonAttributes,
pub build_type: Option<TLParaBuildType>,
pub build_level: Option<u32>,
pub animate_bg: Option<bool>,
pub auto_update_anim_bg: Option<bool>,
pub reverse: Option<bool>,
pub auto_advance_time: Option<TLTime>,
pub template_list: Option<TLTemplateList>,
}
impl TLBuildParagraph {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut shape_id = None;
let mut group_id = None;
let mut ui_expand = None;
let mut build_type = None;
let mut build_level = None;
let mut animate_bg = None;
let mut auto_update_anim_bg = None;
let mut reverse = None;
let mut auto_advance_time = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"spid" => shape_id = Some(value.parse()?),
"grpId" => group_id = Some(value.parse()?),
"uiExpand" => ui_expand = Some(parse_xml_bool(value)?),
"build" => build_type = Some(value.parse()?),
"bldLvl" => build_level = Some(value.parse()?),
"animBg" => animate_bg = Some(parse_xml_bool(value)?),
"autoUpdateAnimBg" => auto_update_anim_bg = Some(parse_xml_bool(value)?),
"rev" => reverse = Some(parse_xml_bool(value)?),
"advAuto" => auto_advance_time = Some(value.parse()?),
_ => (),
}
}
let shape_id = shape_id.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "spid"))?;
let group_id = group_id.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "grpId"))?;
let template_list = xml_node
.child_nodes
.iter()
.find(|child_node| child_node.local_name() == "tmplLst")
.map(TLTemplateList::from_xml_element)
.transpose()?;
Ok(Self {
build_common: TLBuildCommonAttributes {
shape_id,
group_id,
ui_expand,
},
build_type,
build_level,
animate_bg,
auto_update_anim_bg,
reverse,
auto_advance_time,
template_list,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLPoint {
pub x: Percentage,
pub y: Percentage,
}
impl TLPoint {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut x = None;
let mut y = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"x" => x = Some(value.parse()?),
"y" => y = Some(value.parse()?),
_ => (),
}
}
let x = x.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "x"))?;
let y = y.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "y"))?;
Ok(Self { x, y })
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TLTime {
TimePoint(u32),
Indefinite,
}
impl FromStr for TLTime {
type Err = ParseEnumError;
fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
match s {
"indefinite" => Ok(TLTime::Indefinite),
_ => Ok(TLTime::TimePoint(s.parse().map_err(|_| Self::Err::new("TLTime"))?)),
}
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct TLTemplate {
pub level: Option<u32>,
pub time_node_list: TLTimeNodeList,
}
impl TLTemplate {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let level = xml_node.attributes.get("lvl").map(|value| value.parse()).transpose()?;
let time_node_list = xml_node
.child_nodes
.iter()
.find(|child_node| child_node.local_name() == "tnLst")
.ok_or_else(|| MissingChildNodeError::new(xml_node.name.clone(), "tnLst").into())
.and_then(TLTimeNodeList::from_xml_element)?;
Ok(Self { level, time_node_list })
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct TLTemplateList(pub Vec<TLTemplate>);
impl TLTemplateList {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let vec = xml_node
.child_nodes
.iter()
.filter(|child_node| child_node.local_name() == "tmpl")
.map(TLTemplate::from_xml_element)
.collect::<Result<Vec<_>>>()?;
match vec.len() {
0..=9 => Ok(Self(vec)),
len => Err(Box::new(LimitViolationError::new(
xml_node.name.clone(),
"tmpl",
0,
MaxOccurs::Value(9),
len as u32,
))),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLBuildCommonAttributes {
pub shape_id: DrawingElementId,
pub group_id: u32,
pub ui_expand: Option<bool>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLBuildDiagram {
pub build_common: TLBuildCommonAttributes,
pub build_type: Option<TLDiagramBuildType>,
}
impl TLBuildDiagram {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut shape_id = None;
let mut group_id = None;
let mut ui_expand = None;
let mut build_type = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"spid" => shape_id = Some(value.parse()?),
"grpId" => group_id = Some(value.parse()?),
"uiExpand" => ui_expand = Some(parse_xml_bool(value)?),
"bld" => build_type = Some(value.parse()?),
_ => (),
}
}
let shape_id = shape_id.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "spid"))?;
let group_id = group_id.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "grpId"))?;
Ok(Self {
build_common: TLBuildCommonAttributes {
shape_id,
group_id,
ui_expand,
},
build_type,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLOleBuildChart {
pub build_common: TLBuildCommonAttributes,
pub build_type: Option<TLOleChartBuildType>,
pub animate_bg: Option<bool>,
}
impl TLOleBuildChart {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut shape_id = None;
let mut group_id = None;
let mut ui_expand = None;
let mut build_type = None;
let mut animate_bg = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"spid" => shape_id = Some(value.parse()?),
"grpId" => group_id = Some(value.parse()?),
"uiExpand" => ui_expand = Some(parse_xml_bool(value)?),
"bld" => build_type = Some(value.parse()?),
"animBg" => animate_bg = Some(parse_xml_bool(value)?),
_ => (),
}
}
let shape_id = shape_id.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "spid"))?;
let group_id = group_id.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "grpId"))?;
Ok(Self {
build_common: TLBuildCommonAttributes {
shape_id,
group_id,
ui_expand,
},
build_type,
animate_bg,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLGraphicalObjectBuild {
pub build_common: TLBuildCommonAttributes,
pub build_choice: TLGraphicalObjectBuildChoice,
}
impl TLGraphicalObjectBuild {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut shape_id = None;
let mut group_id = None;
let mut ui_expand = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"spid" => shape_id = Some(value.parse()?),
"grpId" => group_id = Some(value.parse()?),
"uiExpand" => ui_expand = Some(parse_xml_bool(value)?),
_ => (),
}
}
let build_choice = xml_node
.child_nodes
.iter()
.find_map(TLGraphicalObjectBuildChoice::try_from_xml_element)
.transpose()?
.ok_or_else(|| MissingChildNodeError::new(xml_node.name.clone(), "TLGraphicalObjectBuildChoice"))?;
let shape_id = shape_id.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "spid"))?;
let group_id = group_id.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "grpId"))?;
Ok(Self {
build_common: TLBuildCommonAttributes {
shape_id,
group_id,
ui_expand,
},
build_choice,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TLGraphicalObjectBuildChoice {
BuildAsOne,
BuildSubElements(AnimationGraphicalObjectBuildProperties),
}
impl XsdType for TLGraphicalObjectBuildChoice {
fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
match xml_node.local_name() {
"bldAsOne" => Ok(TLGraphicalObjectBuildChoice::BuildAsOne),
"bldSub" => Ok(TLGraphicalObjectBuildChoice::BuildSubElements(
AnimationGraphicalObjectBuildProperties::from_xml_element(xml_node)?,
)),
_ => Err(Box::new(NotGroupMemberError::new(
xml_node.name.clone(),
"TLGraphicalObjectBuildChoice",
))),
}
}
}
impl XsdChoice for TLGraphicalObjectBuildChoice {
fn is_choice_member<T>(name: T) -> bool
where
T: AsRef<str>,
{
match name.as_ref() {
"bldAsOne" | "bldSub" => true,
_ => false,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLTimeNodeSequence {
pub concurrent: Option<bool>,
pub prev_action_type: Option<TLPreviousActionType>,
pub next_action_type: Option<TLNextActionType>,
pub common_time_node_data: Box<TLCommonTimeNodeData>,
pub prev_condition_list: Option<TLTimeConditionList>,
pub next_condition_list: Option<TLTimeConditionList>,
}
impl TLTimeNodeSequence {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut concurrent = None;
let mut prev_action_type = None;
let mut next_action_type = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"concurrent" => concurrent = Some(parse_xml_bool(value)?),
"prevAc" => prev_action_type = Some(value.parse()?),
"nextAc" => next_action_type = Some(value.parse()?),
_ => (),
}
}
let mut common_time_node_data = None;
let mut prev_condition_list = None;
let mut next_condition_list = None;
for child_node in &xml_node.child_nodes {
match child_node.local_name() {
"cTn" => common_time_node_data = Some(Box::new(TLCommonTimeNodeData::from_xml_element(child_node)?)),
"prevCondLst" => prev_condition_list = Some(TLTimeConditionList::from_xml_element(child_node)?),
"nextCondLst" => next_condition_list = Some(TLTimeConditionList::from_xml_element(child_node)?),
_ => (),
}
}
let common_time_node_data =
common_time_node_data.ok_or_else(|| MissingChildNodeError::new(xml_node.name.clone(), "cTn"))?;
Ok(Self {
concurrent,
prev_action_type,
next_action_type,
common_time_node_data,
prev_condition_list,
next_condition_list,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLAnimateBehavior {
pub by: Option<String>,
pub from: Option<String>,
pub to: Option<String>,
pub calc_mode: Option<TLAnimateBehaviorCalcMode>,
pub value_type: Option<TLAnimateBehaviorValueType>,
pub common_behavior_data: Box<TLCommonBehaviorData>,
pub time_animate_value_list: Option<TLTimeAnimateValueList>,
}
impl TLAnimateBehavior {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut by = None;
let mut from = None;
let mut to = None;
let mut calc_mode = None;
let mut value_type = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"by" => by = Some(value.clone()),
"from" => from = Some(value.clone()),
"to" => to = Some(value.clone()),
"calcmode" => calc_mode = Some(value.parse()?),
"valueType" => value_type = Some(value.parse()?),
_ => (),
}
}
let mut common_behavior_data = None;
let mut time_animate_value_list = None;
for child_node in &xml_node.child_nodes {
match child_node.local_name() {
"cBhvr" => common_behavior_data = Some(Box::new(TLCommonBehaviorData::from_xml_element(child_node)?)),
"tavLst" => time_animate_value_list = Some(TLTimeAnimateValueList::from_xml_element(child_node)?),
_ => (),
}
}
let common_behavior_data =
common_behavior_data.ok_or_else(|| MissingChildNodeError::new(xml_node.name.clone(), "cBhvr"))?;
Ok(Self {
by,
from,
to,
calc_mode,
value_type,
common_behavior_data,
time_animate_value_list,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLAnimateColorBehavior {
pub color_space: Option<TLAnimateColorSpace>,
pub direction: Option<TLAnimateColorDirection>,
pub common_behavior_data: Box<TLCommonBehaviorData>,
pub by: Option<TLByAnimateColorTransform>,
pub from: Option<Color>,
pub to: Option<Color>,
}
impl TLAnimateColorBehavior {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut color_space = None;
let mut direction = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"clrSpc" => color_space = Some(value.parse()?),
"dir" => direction = Some(value.parse()?),
_ => (),
}
}
let mut common_behavior_data = None;
let mut by = None;
let mut from = None;
let mut to = None;
for child_node in &xml_node.child_nodes {
match child_node.local_name() {
"cBhvr" => common_behavior_data = Some(Box::new(TLCommonBehaviorData::from_xml_element(child_node)?)),
"by" => {
by = Some(
child_node
.child_nodes
.iter()
.find_map(TLByAnimateColorTransform::try_from_xml_element)
.transpose()?
.ok_or_else(|| {
MissingChildNodeError::new(child_node.name.clone(), "TLByAnimateColorTransform")
})?,
)
}
"from" => {
from = Some(
child_node
.child_nodes
.iter()
.find_map(Color::try_from_xml_element)
.transpose()?
.ok_or_else(|| MissingChildNodeError::new(child_node.name.clone(), "EG_Color"))?,
)
}
"to" => {
to = Some(
child_node
.child_nodes
.iter()
.find_map(Color::try_from_xml_element)
.transpose()?
.ok_or_else(|| MissingChildNodeError::new(child_node.name.clone(), "EG_Color"))?,
)
}
_ => (),
}
}
let common_behavior_data =
common_behavior_data.ok_or_else(|| MissingChildNodeError::new(xml_node.name.clone(), "cBhvr"))?;
Ok(Self {
color_space,
direction,
common_behavior_data,
by,
from,
to,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLAnimateEffectBehavior {
pub transition: Option<TLAnimateEffectTransition>,
pub filter: Option<String>,
pub property_list: Option<String>,
pub common_behavior_data: Box<TLCommonBehaviorData>,
pub progress: Option<TLAnimVariant>,
}
impl TLAnimateEffectBehavior {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut transition = None;
let mut filter = None;
let mut property_list = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"transition" => transition = Some(value.parse()?),
"filter" => filter = Some(value.clone()),
"prLst" => property_list = Some(value.clone()),
_ => (),
}
}
let mut common_behavior_data = None;
let mut progress = None;
for child_node in &xml_node.child_nodes {
match child_node.local_name() {
"cBhvr" => common_behavior_data = Some(Box::new(TLCommonBehaviorData::from_xml_element(child_node)?)),
"progress" => {
progress = Some(
child_node
.child_nodes
.iter()
.find_map(TLAnimVariant::try_from_xml_element)
.transpose()?
.ok_or_else(|| MissingChildNodeError::new(child_node.name.clone(), "CT_TLAnimVariant"))?,
)
}
_ => (),
}
}
let common_behavior_data =
common_behavior_data.ok_or_else(|| MissingChildNodeError::new(xml_node.name.clone(), "cBhvr"))?;
Ok(Self {
transition,
filter,
property_list,
common_behavior_data,
progress,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLAnimateMotionBehavior {
pub origin: Option<TLAnimateMotionBehaviorOrigin>,
pub path: Option<String>,
pub path_edit_mode: Option<TLAnimateMotionPathEditMode>,
pub rotate_angle: Option<Angle>,
pub points_types: Option<String>,
pub common_behavior_data: Box<TLCommonBehaviorData>,
pub by: Option<TLPoint>,
pub from: Option<TLPoint>,
pub to: Option<TLPoint>,
pub rotation_center: Option<TLPoint>,
}
impl TLAnimateMotionBehavior {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut origin = None;
let mut path = None;
let mut path_edit_mode = None;
let mut rotate_angle = None;
let mut points_types = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"origin" => origin = Some(value.parse()?),
"path" => path = Some(value.clone()),
"pathEditMode" => path_edit_mode = Some(value.parse()?),
"rAng" => rotate_angle = Some(value.parse()?),
"ptsTypes" => points_types = Some(value.clone()),
_ => (),
}
}
let mut common_behavior_data = None;
let mut by = None;
let mut from = None;
let mut to = None;
let mut rotation_center = None;
for child_node in &xml_node.child_nodes {
match child_node.local_name() {
"cBhvr" => common_behavior_data = Some(Box::new(TLCommonBehaviorData::from_xml_element(child_node)?)),
"by" => by = Some(TLPoint::from_xml_element(child_node)?),
"from" => from = Some(TLPoint::from_xml_element(child_node)?),
"to" => to = Some(TLPoint::from_xml_element(child_node)?),
"rCtr" => rotation_center = Some(TLPoint::from_xml_element(child_node)?),
_ => (),
}
}
let common_behavior_data =
common_behavior_data.ok_or_else(|| MissingChildNodeError::new(xml_node.name.clone(), "cBhvr"))?;
Ok(Self {
origin,
path,
path_edit_mode,
rotate_angle,
points_types,
common_behavior_data,
by,
from,
to,
rotation_center,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLAnimateRotationBehavior {
pub by: Option<Angle>,
pub from: Option<Angle>,
pub to: Option<Angle>,
pub common_behavior_data: Box<TLCommonBehaviorData>,
}
impl TLAnimateRotationBehavior {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut by = None;
let mut from = None;
let mut to = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"by" => by = Some(value.parse()?),
"from" => from = Some(value.parse()?),
"to" => to = Some(value.parse()?),
_ => (),
}
}
let common_behavior_data = xml_node
.child_nodes
.iter()
.find(|child_node| child_node.local_name() == "cBhvr")
.ok_or_else(|| Box::<dyn Error>::from(MissingChildNodeError::new(xml_node.name.clone(), "cBhvr")))
.and_then(TLCommonBehaviorData::from_xml_element)?
.into();
Ok(Self {
by,
from,
to,
common_behavior_data,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLAnimateScaleBehavior {
pub zoom_contents: Option<bool>,
pub common_behavior_data: Box<TLCommonBehaviorData>,
pub by: Option<TLPoint>,
pub from: Option<TLPoint>,
pub to: Option<TLPoint>,
}
impl TLAnimateScaleBehavior {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let zoom_contents = xml_node
.attributes
.get("zoomContents")
.map(parse_xml_bool)
.transpose()?;
let mut common_behavior_data = None;
let mut by = None;
let mut from = None;
let mut to = None;
for child_node in &xml_node.child_nodes {
match child_node.local_name() {
"cBhvr" => common_behavior_data = Some(Box::new(TLCommonBehaviorData::from_xml_element(child_node)?)),
"by" => by = Some(TLPoint::from_xml_element(child_node)?),
"from" => from = Some(TLPoint::from_xml_element(child_node)?),
"to" => to = Some(TLPoint::from_xml_element(child_node)?),
_ => (),
}
}
let common_behavior_data =
common_behavior_data.ok_or_else(|| MissingChildNodeError::new(xml_node.name.clone(), "cBhvr"))?;
Ok(Self {
zoom_contents,
common_behavior_data,
by,
from,
to,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLCommandBehavior {
pub command_type: Option<TLCommandType>,
pub command: Option<String>,
pub common_behavior_data: Box<TLCommonBehaviorData>,
}
impl TLCommandBehavior {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut command_type = None;
let mut command = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"type" => command_type = Some(value.parse()?),
"cmd" => command = Some(value.clone()),
_ => (),
}
}
let common_behavior_data = xml_node
.child_nodes
.iter()
.find(|child_node| child_node.local_name() == "cBhvr")
.ok_or_else(|| Box::<dyn Error>::from(MissingChildNodeError::new(xml_node.name.clone(), "cBhvr")))
.and_then(TLCommonBehaviorData::from_xml_element)?
.into();
Ok(Self {
command_type,
command,
common_behavior_data,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLSetBehavior {
pub common_behavior_data: Box<TLCommonBehaviorData>,
pub to: Option<TLAnimVariant>,
}
impl TLSetBehavior {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut common_behavior_data = None;
let mut to = None;
for child_node in &xml_node.child_nodes {
match child_node.local_name() {
"cBhvr" => common_behavior_data = Some(Box::new(TLCommonBehaviorData::from_xml_element(child_node)?)),
"to" => {
to = Some(
child_node
.child_nodes
.iter()
.find_map(TLAnimVariant::try_from_xml_element)
.transpose()?
.ok_or_else(|| MissingChildNodeError::new(child_node.name.clone(), "CT_TLAnimVariant"))?,
)
}
_ => (),
}
}
let common_behavior_data =
common_behavior_data.ok_or_else(|| MissingChildNodeError::new(xml_node.name.clone(), "cBhvr"))?;
Ok(Self {
common_behavior_data,
to,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLMediaNodeAudio {
pub is_narration: Option<bool>,
pub common_media_node_data: Box<TLCommonMediaNodeData>,
}
impl TLMediaNodeAudio {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let is_narration = xml_node.attributes.get("isNarration").map(parse_xml_bool).transpose()?;
let common_media_node_data = xml_node
.child_nodes
.iter()
.find(|child_node| child_node.local_name() == "cMediaNode")
.ok_or_else(|| Box::<dyn Error>::from(MissingChildNodeError::new(xml_node.name.clone(), "cMediaNode")))
.and_then(TLCommonMediaNodeData::from_xml_element)?
.into();
Ok(Self {
is_narration,
common_media_node_data,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLMediaNodeVideo {
pub fullscreen: Option<bool>,
pub common_media_node_data: Box<TLCommonMediaNodeData>,
}
impl TLMediaNodeVideo {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let fullscreen = xml_node.attributes.get("fullScrn").map(parse_xml_bool).transpose()?;
let common_media_node_data = xml_node
.child_nodes
.iter()
.find(|child_node| child_node.local_name() == "cMediaNode")
.ok_or_else(|| Box::<dyn Error>::from(MissingChildNodeError::new(xml_node.name.clone(), "cMediaNode")))
.and_then(TLCommonMediaNodeData::from_xml_element)?
.into();
Ok(Self {
fullscreen,
common_media_node_data,
})
}
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct TLTimeAnimateValue {
pub time: Option<TLTimeAnimateValueTime>,
pub formula: Option<String>,
pub value: Option<TLAnimVariant>,
}
impl TLTimeAnimateValue {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
xml_node
.attributes
.iter()
.try_fold(Default::default(), |mut instance: Self, (attr, value)| {
match attr.as_ref() {
"tm" => instance.time = Some(value.parse()?),
"fmla" => instance.formula = Some(value.clone()),
_ => (),
}
Ok(instance)
})
.and_then(|instance| {
let value = xml_node
.child_nodes
.iter()
.find(|child_node| child_node.local_name() == "val")
.map(|child_node| {
child_node
.child_nodes
.iter()
.find(|val_node| TLAnimVariant::is_choice_member(val_node.local_name()))
.ok_or_else(|| MissingChildNodeError::new(child_node.name.clone(), "TLAnimVariant").into())
.and_then(TLAnimVariant::from_xml_element)
})
.transpose()?;
Ok(Self { value, ..instance })
})
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct TLTimeAnimateValueList(pub Vec<TLTimeAnimateValue>);
impl TLTimeAnimateValueList {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let vec = xml_node
.child_nodes
.iter()
.filter(|child_node| child_node.local_name() == "tav")
.map(TLTimeAnimateValue::from_xml_element)
.collect::<Result<Vec<_>>>()?;
Ok(Self(vec))
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TLTimeAnimateValueTime {
Percentage(PositiveFixedPercentage),
Indefinite,
}
impl FromStr for TLTimeAnimateValueTime {
type Err = ParseEnumError;
fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
match s {
"indefinite" => Ok(TLTimeAnimateValueTime::Indefinite),
_ => Ok(TLTimeAnimateValueTime::Percentage(
s.parse().map_err(|_| Self::Err::new("TLTimeAnimateValueTime"))?,
)),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TLAnimVariant {
Bool(bool),
Int(i32),
Float(f32),
String(String),
Color(Color),
}
impl XsdType for TLAnimVariant {
fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
match xml_node.local_name() {
"boolVal" => Ok(TLAnimVariant::Bool(parse_xml_bool(xml_node.get_val_attribute()?)?)),
"intVal" => Ok(TLAnimVariant::Int(xml_node.get_val_attribute()?.parse()?)),
"fltVal" => Ok(TLAnimVariant::Float(xml_node.get_val_attribute()?.parse()?)),
"strVal" => Ok(TLAnimVariant::String(xml_node.get_val_attribute()?.clone())),
"clrVal" => {
let color = xml_node
.child_nodes
.iter()
.find_map(Color::try_from_xml_element)
.transpose()?
.ok_or_else(|| MissingChildNodeError::new(xml_node.name.clone(), "EG_Color"))?;
Ok(TLAnimVariant::Color(color))
}
_ => Err(NotGroupMemberError::new(xml_node.name.clone(), "EG_TLAnimVariant").into()),
}
}
}
impl XsdChoice for TLAnimVariant {
fn is_choice_member<T>(name: T) -> bool
where
T: AsRef<str>,
{
match name.as_ref() {
"boolVal" | "intVal" | "fltVal" | "strVal" | "clrVal" => true,
_ => false,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TLTimeConditionTriggerGroup {
TargetElement(TLTimeTargetElement),
TimeNode(TLTimeNodeId),
RuntimeNode(TLTriggerRuntimeNode),
}
impl XsdType for TLTimeConditionTriggerGroup {
fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
match xml_node.local_name() {
"tgtEl" => {
let target_element = xml_node
.child_nodes
.iter()
.find_map(TLTimeTargetElement::try_from_xml_element)
.transpose()?
.ok_or_else(|| MissingChildNodeError::new(xml_node.name.clone(), "sldTgt|sndTgt|spTgt|inkTgt"))?;
Ok(TLTimeConditionTriggerGroup::TargetElement(target_element))
}
"tn" => {
let val = xml_node.get_val_attribute()?.parse()?;
Ok(TLTimeConditionTriggerGroup::TimeNode(val))
}
"rtn" => {
let val = xml_node.get_val_attribute()?.parse()?;
Ok(TLTimeConditionTriggerGroup::RuntimeNode(val))
}
_ => Err(Box::new(NotGroupMemberError::new(
xml_node.name.clone(),
"EG_TLTimeConditionTriggerGroup",
))),
}
}
}
impl XsdChoice for TLTimeConditionTriggerGroup {
fn is_choice_member<T>(name: T) -> bool
where
T: AsRef<str>,
{
match name.as_ref() {
"tgtEl" | "tn" | "rtn" => true,
_ => false,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TLTimeTargetElement {
SlideTarget,
SoundTarget(EmbeddedWAVAudioFile),
ShapeTarget(TLShapeTargetElement),
InkTarget(TLSubShapeId),
}
impl XsdType for TLTimeTargetElement {
fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
match xml_node.local_name() {
"sldTgt" => Ok(TLTimeTargetElement::SlideTarget),
"sndTgt" => Ok(TLTimeTargetElement::SoundTarget(
EmbeddedWAVAudioFile::from_xml_element(xml_node)?,
)),
"spTgt" => Ok(TLTimeTargetElement::ShapeTarget(
TLShapeTargetElement::from_xml_element(xml_node)?,
)),
"inkTgt" => {
let spid = xml_node
.attributes
.get("spid")
.ok_or_else(|| Box::<dyn Error>::from(MissingAttributeError::new(xml_node.name.clone(), "spid")))
.and_then(|value| value.parse().map_err(Into::into))?;
Ok(TLTimeTargetElement::InkTarget(spid))
}
_ => Err(Box::new(NotGroupMemberError::new(
xml_node.name.clone(),
"CT_TLTimeTargetElement",
))),
}
}
}
impl XsdChoice for TLTimeTargetElement {
fn is_choice_member<T>(name: T) -> bool
where
T: AsRef<str>,
{
match name.as_ref() {
"sldTgt" | "sndTgt" | "spTgt" | "inkTgt" => true,
_ => false,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLShapeTargetElement {
pub shape_id: DrawingElementId,
pub target: Option<TLShapeTargetElementGroup>,
}
impl TLShapeTargetElement {
pub fn new(shape_id: DrawingElementId, target: Option<TLShapeTargetElementGroup>) -> Self {
Self { shape_id, target }
}
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let shape_id = xml_node
.attributes
.get("spid")
.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "spid"))?
.parse()?;
let target = xml_node
.child_nodes
.iter()
.find_map(TLShapeTargetElementGroup::try_from_xml_element)
.transpose()?;
Ok(Self { shape_id, target })
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TLShapeTargetElementGroup {
Background,
SubShape(TLSubShapeId),
OleChartElement(TLOleChartTargetElement),
TextElement(Option<TLTextTargetElement>),
GraphicElement(AnimationElementChoice),
}
impl XsdType for TLShapeTargetElementGroup {
fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
match xml_node.local_name() {
"bg" => Ok(TLShapeTargetElementGroup::Background),
"subSp" => {
let spid = xml_node
.attributes
.get("spid")
.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "spid"))?
.parse()?;
Ok(TLShapeTargetElementGroup::SubShape(spid))
}
"oleChartEl" => Ok(TLShapeTargetElementGroup::OleChartElement(
TLOleChartTargetElement::from_xml_element(xml_node)?,
)),
"txEl" => {
let text_element = xml_node
.child_nodes
.iter()
.find_map(TLTextTargetElement::try_from_xml_element)
.transpose()?;
Ok(TLShapeTargetElementGroup::TextElement(text_element))
}
"graphicEl" => {
let animation_element = xml_node
.child_nodes
.iter()
.find_map(AnimationElementChoice::try_from_xml_element)
.transpose()?
.ok_or_else(|| MissingChildNodeError::new(xml_node.name.clone(), "CT_AnimationElementChoice"))?;
Ok(TLShapeTargetElementGroup::GraphicElement(animation_element))
}
_ => Err(Box::new(NotGroupMemberError::new(
xml_node.name.clone(),
"TLShapeTargetElementGroup",
))),
}
}
}
impl XsdChoice for TLShapeTargetElementGroup {
fn is_choice_member<T>(name: T) -> bool
where
T: AsRef<str>,
{
match name.as_ref() {
"bg" | "subSp" | "oleChartEl" | "txEl" | "graphicEl" => true,
_ => false,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLOleChartTargetElement {
pub element_type: TLChartSubelementType,
pub level: Option<u32>,
}
impl TLOleChartTargetElement {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut element_type = None;
let mut level = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"type" => element_type = Some(value.parse()?),
"lvl" => level = Some(value.parse()?),
_ => (),
}
}
let element_type = element_type.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "type"))?;
Ok(Self { element_type, level })
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TLTextTargetElement {
CharRange(IndexRange),
ParagraphRange(IndexRange),
}
impl XsdType for TLTextTargetElement {
fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
match xml_node.local_name() {
"charRg" => Ok(TLTextTargetElement::CharRange(IndexRange::from_xml_element(xml_node)?)),
"pRg" => Ok(TLTextTargetElement::ParagraphRange(IndexRange::from_xml_element(
xml_node,
)?)),
_ => Err(Box::new(NotGroupMemberError::new(
xml_node.name.clone(),
"TLTextTargetElement",
))),
}
}
}
impl XsdChoice for TLTextTargetElement {
fn is_choice_member<T>(name: T) -> bool
where
T: AsRef<str>,
{
match name.as_ref() {
"charRg" | "pRg" => true,
_ => false,
}
}
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct TLTimeCondition {
pub trigger_event: Option<TLTriggerEvent>,
pub delay: Option<TLTime>,
pub trigger: Option<TLTimeConditionTriggerGroup>,
}
impl TLTimeCondition {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
xml_node
.attributes
.iter()
.try_fold(Default::default(), |mut instance: Self, (attr, value)| {
match attr.as_str() {
"evt" => instance.trigger_event = Some(value.parse()?),
"delay" => instance.delay = Some(value.parse()?),
_ => (),
}
Ok(instance)
})
.and_then(|instance| {
let trigger = xml_node
.child_nodes
.iter()
.find_map(TLTimeConditionTriggerGroup::try_from_xml_element)
.transpose()?;
Ok(Self { trigger, ..instance })
})
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct TLTimeConditionList(pub Vec<TLTimeCondition>);
impl TLTimeConditionList {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let list = xml_node
.child_nodes
.iter()
.filter(|child_node| child_node.local_name() == "cond")
.map(TLTimeCondition::from_xml_element)
.collect::<Result<Vec<_>>>()?;
if list.is_empty() {
Err(Box::new(LimitViolationError::new(
xml_node.name.clone(),
"cond",
1,
MaxOccurs::Unbounded,
0,
)))
} else {
Ok(Self(list))
}
}
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct TLCommonTimeNodeData {
pub id: Option<TLTimeNodeId>,
pub preset_id: Option<i32>,
pub preset_class: Option<TLTimeNodePresetClassType>,
pub preset_subtype: Option<i32>,
pub duration: Option<TLTime>,
pub repeat_count: Option<TLTime>,
pub repeat_duration: Option<TLTime>,
pub speed: Option<Percentage>,
pub acceleration: Option<PositiveFixedPercentage>,
pub deceleration: Option<PositiveFixedPercentage>,
pub auto_reverse: Option<bool>,
pub restart_type: Option<TLTimeNodeRestartType>,
pub fill_type: Option<TLTimeNodeFillType>,
pub sync_behavior: Option<TLTimeNodeSyncType>,
pub time_filter: Option<String>,
pub event_filter: Option<String>,
pub display: Option<bool>,
pub master_relationship: Option<TLTimeNodeMasterRelation>,
pub build_level: Option<i32>,
pub group_id: Option<u32>,
pub after_effect: Option<bool>,
pub node_type: Option<TLTimeNodeType>,
pub node_placeholder: Option<bool>,
pub start_condition_list: Option<TLTimeConditionList>,
pub end_condition_list: Option<TLTimeConditionList>,
pub end_sync: Option<TLTimeCondition>,
pub iterate: Option<TLIterateData>,
pub child_time_node_list: Option<TLTimeNodeList>,
pub sub_time_node_list: Option<TLTimeNodeList>,
}
impl TLCommonTimeNodeData {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
xml_node
.attributes
.iter()
.try_fold(Default::default(), |mut instance: Self, (attr, value)| {
match attr.as_ref() {
"id" => instance.id = Some(value.parse()?),
"presetID" => instance.preset_id = Some(value.parse()?),
"presetClass" => instance.preset_class = Some(value.parse()?),
"presetSubtype" => instance.preset_subtype = Some(value.parse()?),
"dur" => instance.duration = Some(value.parse()?),
"repeatCount" => instance.repeat_count = Some(value.parse()?),
"repeatDur" => instance.repeat_duration = Some(value.parse()?),
"spd" => instance.speed = Some(value.parse()?),
"accel" => instance.acceleration = Some(value.parse()?),
"decel" => instance.deceleration = Some(value.parse()?),
"autoRev" => instance.auto_reverse = Some(parse_xml_bool(value)?),
"restart" => instance.restart_type = Some(value.parse()?),
"fill" => instance.fill_type = Some(value.parse()?),
"syncBehavior" => instance.sync_behavior = Some(value.parse()?),
"tmFilter" => instance.time_filter = Some(value.clone()),
"evtFilter" => instance.event_filter = Some(value.clone()),
"display" => instance.display = Some(parse_xml_bool(value)?),
"masterRel" => instance.master_relationship = Some(value.parse()?),
"bldLvl" => instance.build_level = Some(value.parse()?),
"grpId" => instance.group_id = Some(value.parse()?),
"afterEffect" => instance.after_effect = Some(parse_xml_bool(value)?),
"nodeType" => instance.node_type = Some(value.parse()?),
"nodePh" => instance.node_placeholder = Some(parse_xml_bool(value)?),
_ => (),
}
Ok(instance)
})
.and_then(|instance| {
xml_node
.child_nodes
.iter()
.try_fold(instance, |mut instance, child_node| {
match child_node.local_name() {
"stCondLst" => {
instance.start_condition_list = Some(TLTimeConditionList::from_xml_element(child_node)?)
}
"endCondLst" => {
instance.end_condition_list = Some(TLTimeConditionList::from_xml_element(child_node)?)
}
"endSync" => instance.end_sync = Some(TLTimeCondition::from_xml_element(child_node)?),
"iterate" => instance.iterate = Some(TLIterateData::from_xml_element(child_node)?),
"childTnLst" => {
instance.child_time_node_list = Some(TLTimeNodeList::from_xml_element(child_node)?)
}
"subTnLst" => {
instance.sub_time_node_list = Some(TLTimeNodeList::from_xml_element(child_node)?)
}
_ => (),
}
Ok(instance)
})
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TLIterateDataChoice {
Absolute(TLTime),
Percent(PositivePercentage),
}
impl XsdType for TLIterateDataChoice {
fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
match xml_node.local_name() {
"tmAbs" => Ok(TLIterateDataChoice::Absolute(xml_node.get_val_attribute()?.parse()?)),
"tmPct" => Ok(TLIterateDataChoice::Percent(xml_node.get_val_attribute()?.parse()?)),
_ => Err(Box::new(NotGroupMemberError::new(
xml_node.name.clone(),
"TLIterateDataChoice",
))),
}
}
}
impl XsdChoice for TLIterateDataChoice {
fn is_choice_member<T>(name: T) -> bool
where
T: AsRef<str>,
{
match name.as_ref() {
"tmAbs" | "tmPct" => true,
_ => false,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLIterateData {
pub iterate_type: Option<IterateType>,
pub backwards: Option<bool>,
pub interval: TLIterateDataChoice,
}
impl TLIterateData {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut iterate_type = None;
let mut backwards = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"type" => iterate_type = Some(value.parse()?),
"backwards" => backwards = Some(parse_xml_bool(value)?),
_ => (),
}
}
let interval = xml_node
.child_nodes
.first()
.ok_or_else(|| MissingChildNodeError::new(xml_node.name.clone(), "TLIterateDataChoice").into())
.and_then(TLIterateDataChoice::from_xml_element)?;
Ok(Self {
iterate_type,
backwards,
interval,
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TLByAnimateColorTransform {
Rgb(TLByRgbColorTransform),
Hsl(TLByHslColorTransform),
}
impl XsdType for TLByAnimateColorTransform {
fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
match xml_node.local_name() {
"rgb" => Ok(TLByAnimateColorTransform::Rgb(TLByRgbColorTransform::from_xml_element(
xml_node,
)?)),
"hsl" => Ok(TLByAnimateColorTransform::Hsl(TLByHslColorTransform::from_xml_element(
xml_node,
)?)),
_ => Err(Box::new(NotGroupMemberError::new(
xml_node.name.clone(),
"TLByAnimateColorTransform",
))),
}
}
}
impl XsdChoice for TLByAnimateColorTransform {
fn is_choice_member<T>(name: T) -> bool
where
T: AsRef<str>,
{
match name.as_ref() {
"rgb" | "hsl" => true,
_ => false,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLByRgbColorTransform {
pub r: FixedPercentage,
pub g: FixedPercentage,
pub b: FixedPercentage,
}
impl TLByRgbColorTransform {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut r = None;
let mut g = None;
let mut b = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"r" => r = Some(value.parse()?),
"g" => g = Some(value.parse()?),
"b" => b = Some(value.parse()?),
_ => (),
}
}
let r = r.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "r"))?;
let g = g.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "g"))?;
let b = b.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "b"))?;
Ok(Self { r, g, b })
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct TLByHslColorTransform {
pub h: Angle,
pub s: FixedPercentage,
pub l: FixedPercentage,
}
impl TLByHslColorTransform {
pub fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
let mut h = None;
let mut s = None;
let mut l = None;
for (attr, value) in &xml_node.attributes {
match attr.as_str() {
"h" => h = Some(value.parse()?),
"s" => s = Some(value.parse()?),
"l" => l = Some(value.parse()?),
_ => (),
}
}
let h = h.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "h"))?;
let s = s.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "s"))?;
let l = l.ok_or_else(|| MissingAttributeError::new(xml_node.name.clone(), "l"))?;
Ok(Self { h, s, l })
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Build {
Paragraph(Box<TLBuildParagraph>),
Diagram(Box<TLBuildDiagram>),
OleChart(Box<TLOleBuildChart>),
Graphic(Box<TLGraphicalObjectBuild>),
}
impl XsdType for Build {
fn from_xml_element(xml_node: &XmlNode) -> Result<Self> {
match xml_node.local_name() {
"bldP" => Ok(Build::Paragraph(Box::new(TLBuildParagraph::from_xml_element(
xml_node,
)?))),
"bldDgm" => Ok(Build::Diagram(Box::new(TLBuildDiagram::from_xml_element(xml_node)?))),
"bldOleChart" => Ok(Build::OleChart(Box::new(TLOleBuildChart::from_xml_element(xml_node)?))),
"bldGraphic" => Ok(Build::Graphic(Box::new(TLGraphicalObjectBuild::from_xml_element(
xml_node,
)?))),
_ => Err(Box::new(NotGroupMemberError::new(
xml_node.name.clone(),
"CT_BuildList",
))),
}
}
}
impl XsdChoice for Build {
fn is_choice_member<T>(name: T) -> bool
where
T: AsRef<str>,
{
match name.as_ref() {
"bldP" | "bldDgm" | "bldOleChart" | "bldGraphic" => true,
_ => false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
impl IndexRange {
pub fn test_xml(node_name: &'static str) -> String {
format!(r#"<{node_name} st="0" end="5"></{node_name}>"#, node_name = node_name)
}
pub fn test_instance() -> Self {
Self { start: 0, end: 5 }
}
}
#[test]
pub fn test_index_range_from_xml() {
let xml = IndexRange::test_xml("index");
assert_eq!(
IndexRange::from_xml_element(&XmlNode::from_str(&xml).unwrap()).unwrap(),
IndexRange::test_instance(),
);
}
impl TLCommonBehaviorData {
pub fn test_xml(node_name: &'static str) -> String {
format!(
r#"<{node_name} additive="sum" accumulate="none" xfrmType="pt" from="Example" to="Example"
by="Example" rctx="Example" override="childStyle">
{}
<tgtEl>
<sldTgt />
</tgtEl>
<attrNameLst>
<attrName>style.fontSize</p:attrName>
</attrNameLst>
</{node_name}>"#,
TLCommonTimeNodeData::test_xml_non_recursive("cTn"),
node_name = node_name,
)
}
pub fn test_instance() -> Self {
Self {
additive: Some(TLBehaviorAdditiveType::Sum),
accumulate: Some(TLBehaviorAccumulateType::None),
transform_type: Some(TLBehaviorTransformType::Point),
from: Some(String::from("Example")),
to: Some(String::from("Example")),
by: Some(String::from("Example")),
runtime_context: Some(String::from("Example")),
override_type: Some(TLBehaviorOverrideType::ChildStyle),
common_time_node_data: Box::new(TLCommonTimeNodeData::test_instance_non_recursive()),
target_element: TLTimeTargetElement::SlideTarget,
attr_name_list: Some(vec![String::from("style.fontSize")]),
}
}
}
#[test]
pub fn test_tl_common_behavior_data_from_xml() {
let xml = TLCommonBehaviorData::test_xml("tlCommonBehaviorData");
assert_eq!(
TLCommonBehaviorData::from_xml_element(&XmlNode::from_str(&xml).unwrap()).unwrap(),
TLCommonBehaviorData::test_instance()
);
}
impl TLCommonMediaNodeData {
pub fn test_xml(node_name: &'static str) -> String {
format!(
r#"<{node_name} vol="50000" mute="false" numSld="1" showWhenStopped="true">
{}
<tgtEl>
<sldTgt />
</tgtEl>
</{node_name}>"#,
TLCommonTimeNodeData::test_xml_non_recursive("cTn"),
node_name = node_name,
)
}
pub fn test_instance() -> Self {
Self {
volume: Some(50_000.0),
mute: Some(false),
number_of_slides: Some(1),
show_when_stopped: Some(true),
common_time_node_data: Box::new(TLCommonTimeNodeData::test_instance_non_recursive()),
target_element: TLTimeTargetElement::SlideTarget,
}
}
}
#[test]
pub fn test_tl_common_media_node_data_from_xml() {
let xml = TLCommonMediaNodeData::test_xml("tlCommonMediaNodeData");
assert_eq!(
TLCommonMediaNodeData::from_xml_element(&XmlNode::from_str(&xml).unwrap()).unwrap(),
TLCommonMediaNodeData::test_instance(),
);
}
impl TLPoint {
pub fn test_xml(node_name: &'static str) -> String {
format!(
r#"<{node_name} x="100000" y="100000"></{node_name}>"#,
node_name = node_name
)
}
pub fn test_instance() -> Self {
Self {
x: 100_000.0,
y: 100_000.0,
}
}
}
#[test]
pub fn test_tl_point_from_xml() {
let xml = TLPoint::test_xml("tlPoint");
assert_eq!(
TLPoint::from_xml_element(&XmlNode::from_str(&xml).unwrap()).unwrap(),
TLPoint::test_instance(),
);
}
impl TLTimeCondition {
pub fn test_xml(node_name: &'static str) -> String {
format!(
r#"<{node_name} evt="onClick" delay="1000">
<tgtEl>
<sldTgt/>
</tgtEl>
</{node_name}>"#,
node_name = node_name,
)
}
pub fn test_instance() -> Self {
Self {
trigger_event: Some(TLTriggerEvent::OnClick),
delay: Some(TLTime::TimePoint(1000)),
trigger: Some(TLTimeConditionTriggerGroup::TargetElement(
TLTimeTargetElement::SlideTarget,
)),
}
}
}
#[test]
pub fn test_tl_time_condition_from_xml() {
let xml = TLTimeCondition::test_xml("tlTimeCondition");
assert_eq!(
TLTimeCondition::from_xml_element(&XmlNode::from_str(&xml).unwrap()).unwrap(),
TLTimeCondition::test_instance(),
);
}
impl TLTimeConditionList {
pub fn test_xml(node_name: &'static str) -> String {
format!(
r#"<{node_name}>{}</{node_name}>"#,
TLTimeCondition::test_xml("cond"),
node_name = node_name,
)
}
pub fn test_instance() -> Self {
Self(vec![TLTimeCondition::test_instance()])
}
}
#[test]
pub fn test_tl_time_condition_list_from_xml() {
let xml = TLTimeConditionList::test_xml("tlTimeConditionList");
assert_eq!(
TLTimeConditionList::from_xml_element(&XmlNode::from_str(&xml).unwrap()).unwrap(),
TLTimeConditionList::test_instance(),
);
}
impl TLTimeNodeList {
pub fn test_xml(node_name: &'static str) -> String {
format!(
r#"<{node_name}>
{}
{}
</{node_name}>"#,
TLCommonTimeNodeData::test_xml_non_recursive("par"),
TLTimeNodeSequence::test_xml("seq"),
node_name = node_name,
)
}
pub fn test_instance() -> Self {
Self(vec![
TimeNodeGroup::Parallel(Box::new(TLCommonTimeNodeData::test_instance_non_recursive())),
TimeNodeGroup::Sequence(Box::new(TLTimeNodeSequence::test_instance())),
])
}
}
#[test]
pub fn test_tl_time_node_list_from_xml() {
let xml = TLTimeNodeList::test_xml("tlTimeNodeList");
assert_eq!(
TLTimeNodeList::from_xml_element(&XmlNode::from_str(&xml).unwrap()).unwrap(),
TLTimeNodeList::test_instance(),
);
}
impl TLCommonTimeNodeData {
const TEST_ATTRIBUTES: &'static str = r#"id="1" presetID="1" presetClass="entr" presetSubtype="0" dur="1000"
repeatCount="1000" repeatDur="1000" spd="100000" accel="0" decel="0" autoRev="false" restart="never"
fill="hold" syncBehavior="locked" tmFilter="Example filter" evtFilter="Example filter" display="true"
masterRel="sameClick" bldLvl="1" grpId="1" afterEffect="true" nodeType="mainSequence" nodePh="false""#;
pub fn test_xml(node_name: &'static str) -> String {
format!(
r#"<{node_name} {}>
{}
{}
{}
{}
{}
{}
</{node_name}>"#,
Self::TEST_ATTRIBUTES,
TLTimeConditionList::test_xml("stCondLst"),
TLTimeConditionList::test_xml("endCondLst"),
TLTimeCondition::test_xml("endSync"),
TLIterateData::test_xml("iterate"),
TLTimeNodeList::test_xml("childTnLst"),
TLTimeNodeList::test_xml("subTnLst"),
node_name = node_name,
)
}
pub fn test_xml_non_recursive(node_name: &'static str) -> String {
format!(
r#"<{node_name} {}></{node_name}>"#,
Self::TEST_ATTRIBUTES,
node_name = node_name,
)
}
pub fn test_instance() -> Self {
Self {
start_condition_list: Some(TLTimeConditionList::test_instance()),
end_condition_list: Some(TLTimeConditionList::test_instance()),
end_sync: Some(TLTimeCondition::test_instance()),
iterate: Some(TLIterateData::test_instance()),
child_time_node_list: Some(TLTimeNodeList::test_instance()),
sub_time_node_list: Some(TLTimeNodeList::test_instance()),
..Self::test_instance_non_recursive()
}
}
pub fn test_instance_non_recursive() -> Self {
Self {
id: Some(1),
preset_id: Some(1),
preset_class: Some(TLTimeNodePresetClassType::Entrance),
preset_subtype: Some(0),
duration: Some(TLTime::TimePoint(1000)),
repeat_count: Some(TLTime::TimePoint(1000)),
repeat_duration: Some(TLTime::TimePoint(1000)),
speed: Some(100_000.0),
acceleration: Some(0.0),
deceleration: Some(0.0),
auto_reverse: Some(false),
restart_type: Some(TLTimeNodeRestartType::Never),
fill_type: Some(TLTimeNodeFillType::Hold),
sync_behavior: Some(TLTimeNodeSyncType::Locked),
time_filter: Some(String::from("Example filter")),
event_filter: Some(String::from("Example filter")),
display: Some(true),
master_relationship: Some(TLTimeNodeMasterRelation::SameClick),
build_level: Some(1),
group_id: Some(1),
after_effect: Some(true),
node_type: Some(TLTimeNodeType::MainSequence),
node_placeholder: Some(false),
..Default::default()
}
}
}
#[test]
pub fn test_tl_common_time_node_data_from_xml() {
let xml = TLCommonTimeNodeData::test_xml("tlCommonTimeNodeData");
assert_eq!(
TLCommonTimeNodeData::from_xml_element(&XmlNode::from_str(&xml).unwrap()).unwrap(),
TLCommonTimeNodeData::test_instance(),
);
}
impl TLTimeNodeSequence {
pub fn test_xml(node_name: &'static str) -> String {
format!(
r#"<{node_name} concurrent="false" prevAc="none" nextAc="none">
{}
{}
{}
</{node_name}>"#,
TLCommonTimeNodeData::test_xml_non_recursive("cTn"),
TLTimeConditionList::test_xml("prevCondLst"),
TLTimeConditionList::test_xml("nextCondLst"),
node_name = node_name,
)
}
pub fn test_instance() -> Self {
Self {
concurrent: Some(false),
prev_action_type: Some(TLPreviousActionType::None),
next_action_type: Some(TLNextActionType::None),
common_time_node_data: Box::new(TLCommonTimeNodeData::test_instance_non_recursive()),
prev_condition_list: Some(TLTimeConditionList::test_instance()),
next_condition_list: Some(TLTimeConditionList::test_instance()),
}
}
}
#[test]
pub fn test_tl_time_node_sequence_from_xml() {
let xml = TLTimeNodeSequence::test_xml("tlTimeNodeSequence");
assert_eq!(
TLTimeNodeSequence::from_xml_element(&XmlNode::from_str(&xml).unwrap()).unwrap(),
TLTimeNodeSequence::test_instance(),
);
}
impl TLIterateData {
pub fn test_xml(node_name: &'static str) -> String {
format!(
r#"<{node_name} type="el" backwards="false">
<tmAbs val="10000" />
</{node_name}>"#,
node_name = node_name,
)
}
pub fn test_instance() -> Self {
Self {
iterate_type: Some(IterateType::Element),
backwards: Some(false),
interval: TLIterateDataChoice::Absolute(TLTime::TimePoint(10_000)),
}
}
}
#[test]
pub fn test_tl_iterate_data_from_xml() {
let xml = TLIterateData::test_xml("tlIterateData");
assert_eq!(
TLIterateData::from_xml_element(&XmlNode::from_str(&xml).unwrap()).unwrap(),
TLIterateData::test_instance(),
);
}
impl TLTemplate {
pub fn test_xml(node_name: &'static str) -> String {
format!(
r#"<{node_name} lvl="0">{}</{node_name}>"#,
TLTimeNodeList::test_xml("tnLst"),
node_name = node_name
)
}
pub fn test_instance() -> Self {
Self {
level: Some(0),
time_node_list: TLTimeNodeList::test_instance(),
}
}
}
#[test]
pub fn test_tl_template_from_xml() {
let xml = TLTemplate::test_xml("tlTemplate");
assert_eq!(
TLTemplate::from_xml_element(&XmlNode::from_str(&xml).unwrap()).unwrap(),
TLTemplate::test_instance(),
);
}
impl TLTemplateList {
pub fn test_xml(node_name: &'static str) -> String {
format!(
r#"<{node_name}>{}</{node_name}>"#,
TLTemplate::test_xml("tmpl"),
node_name = node_name
)
}
pub fn test_instance() -> Self {
Self(vec![TLTemplate::test_instance()])
}
}
#[test]
pub fn test_tl_template_list_from_xml() {
let xml = TLTemplateList::test_xml("tlTemplateList");
assert_eq!(
TLTemplateList::from_xml_element(&XmlNode::from_str(&xml).unwrap()).unwrap(),
TLTemplateList::test_instance(),
);
}
impl TLBuildCommonAttributes {
const TEST_ATTRIBUTES: &'static str = r#"spid="0" grpId="0" uiExpand="true""#;
pub fn test_instance() -> Self {
Self {
shape_id: 0,
group_id: 0,
ui_expand: Some(true),
}
}
}
impl TLBuildParagraph {
pub fn test_xml(node_name: &'static str) -> String {
format!(
r#"<{node_name} {} build="whole" bldLvl="0" animBg="true" autoUpdateAnimBg="true" rev="false" advAuto="1000">
{}
</{node_name}>"#,
TLBuildCommonAttributes::TEST_ATTRIBUTES,
TLTemplateList::test_xml("tmplLst"),
node_name = node_name,
)
}
pub fn test_instance() -> Self {
Self {
build_common: TLBuildCommonAttributes::test_instance(),
build_type: Some(TLParaBuildType::Whole),
build_level: Some(0),
animate_bg: Some(true),
auto_update_anim_bg: Some(true),
reverse: Some(false),
auto_advance_time: Some(TLTime::TimePoint(1000)),
template_list: Some(TLTemplateList::test_instance()),
}
}
}
#[test]
pub fn test_tl_build_paragraph_from_xml() {
let xml = TLBuildParagraph::test_xml("tlBuildParagraph");
assert_eq!(
TLBuildParagraph::from_xml_element(&XmlNode::from_str(&xml).unwrap()).unwrap(),
TLBuildParagraph::test_instance(),
);
}
impl TLBuildDiagram {
pub fn test_xml(node_name: &'static str) -> String {
format!(
r#"<{node_name} {} bld="whole"></{node_name}>"#,
TLBuildCommonAttributes::TEST_ATTRIBUTES,
node_name = node_name,
)
}
pub fn test_instance() -> Self {
Self {
build_common: TLBuildCommonAttributes::test_instance(),
build_type: Some(TLDiagramBuildType::Whole),
}
}
}
#[test]
pub fn test_tl_build_diagram_from_xml() {
let xml = TLBuildDiagram::test_xml("tlBuildDiagram");
assert_eq!(
TLBuildDiagram::from_xml_element(&XmlNode::from_str(&xml).unwrap()).unwrap(),
TLBuildDiagram::test_instance(),
);
}
impl TLOleBuildChart {
pub fn test_xml(node_name: &'static str) -> String {
format!(
r#"<{node_name} {} bld="allAtOnce" animBg="true"></{node_name}>"#,
TLBuildCommonAttributes::TEST_ATTRIBUTES,
node_name = node_name,
)
}
pub fn test_instance() -> Self {
Self {
build_common: TLBuildCommonAttributes::test_instance(),
build_type: Some(TLOleChartBuildType::AllAtOnce),
animate_bg: Some(true),
}
}
}
#[test]
pub fn test_tl_ole_build_chart_from_xml() {
let xml = TLOleBuildChart::test_xml("tlOleBuildChart");
assert_eq!(
TLOleBuildChart::from_xml_element(&XmlNode::from_str(&xml).unwrap()).unwrap(),
TLOleBuildChart::test_instance(),
);
}
impl TLGraphicalObjectBuild {
pub fn test_xml(node_name: &'static str) -> String {
format!(
r#"<{node_name} {}>
<bldAsOne />
</{node_name}>"#,
TLBuildCommonAttributes::TEST_ATTRIBUTES,
node_name = node_name,
)
}
pub fn test_instance() -> Self {
Self {
build_common: TLBuildCommonAttributes::test_instance(),
build_choice: TLGraphicalObjectBuildChoice::BuildAsOne,
}
}
}
#[test]
pub fn test_tl_graphical_object_build_from_xml() {
let xml = TLGraphicalObjectBuild::test_xml("tlGraphicalObjectBuild");
assert_eq!(
TLGraphicalObjectBuild::from_xml_element(&XmlNode::from_str(&xml).unwrap()).unwrap(),
TLGraphicalObjectBuild::test_instance(),
);
}
}