1use super::base::{ContentType, Part, PartType};
6use crate::exc::PptxError;
7use crate::generator::charts::{generate_chart_part_xml, Chart};
8
9#[derive(Debug, Clone)]
11pub struct ChartPart {
12 path: String,
13 chart_number: usize,
14 chart: Option<Chart>,
15 xml_content: Option<String>,
16}
17
18impl ChartPart {
19 pub fn new(chart_number: usize) -> Self {
21 ChartPart {
22 path: format!("ppt/charts/chart{}.xml", chart_number),
23 chart_number,
24 chart: None,
25 xml_content: None,
26 }
27 }
28
29 pub fn from_chart(chart_number: usize, chart: Chart) -> Self {
31 ChartPart {
32 path: format!("ppt/charts/chart{}.xml", chart_number),
33 chart_number,
34 chart: Some(chart),
35 xml_content: None,
36 }
37 }
38
39 pub fn chart_number(&self) -> usize {
41 self.chart_number
42 }
43
44 pub fn chart(&self) -> Option<&Chart> {
46 self.chart.as_ref()
47 }
48
49 pub fn set_chart(&mut self, chart: Chart) {
51 self.chart = Some(chart);
52 self.xml_content = None;
53 }
54
55 pub fn rel_target(&self) -> String {
57 format!("../charts/chart{}.xml", self.chart_number)
58 }
59}
60
61impl Part for ChartPart {
62 fn path(&self) -> &str {
63 &self.path
64 }
65
66 fn part_type(&self) -> PartType {
67 PartType::Chart
68 }
69
70 fn content_type(&self) -> ContentType {
71 ContentType::Chart
72 }
73
74 fn to_xml(&self) -> Result<String, PptxError> {
75 if let Some(ref xml) = self.xml_content {
76 return Ok(xml.clone());
77 }
78
79 if let Some(ref chart) = self.chart {
80 return Ok(generate_chart_part_xml(chart));
81 }
82
83 Err(PptxError::InvalidOperation(
85 "No chart data available".to_string(),
86 ))
87 }
88
89 fn from_xml(xml: &str) -> Result<Self, PptxError> {
90 Ok(ChartPart {
92 path: "ppt/charts/chart1.xml".to_string(),
93 chart_number: 1,
94 chart: None,
95 xml_content: Some(xml.to_string()),
96 })
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103 use crate::generator::charts::{ChartBuilder, ChartSeries, ChartType};
104
105 #[test]
106 fn test_chart_part_new() {
107 let part = ChartPart::new(1);
108 assert_eq!(part.chart_number(), 1);
109 assert_eq!(part.path(), "ppt/charts/chart1.xml");
110 }
111
112 #[test]
113 fn test_chart_part_from_chart() {
114 let chart = ChartBuilder::new("Test", ChartType::Bar)
115 .categories(vec!["A", "B"])
116 .add_series(ChartSeries::new("Data", vec![1.0, 2.0]))
117 .build();
118
119 let part = ChartPart::from_chart(2, chart);
120 assert_eq!(part.chart_number(), 2);
121 assert!(part.chart().is_some());
122 }
123
124 #[test]
125 fn test_chart_part_to_xml() {
126 let chart = ChartBuilder::new("Sales", ChartType::Bar)
127 .categories(vec!["Q1", "Q2"])
128 .add_series(ChartSeries::new("2024", vec![100.0, 150.0]))
129 .build();
130
131 let part = ChartPart::from_chart(1, chart);
132 let xml = part.to_xml().unwrap();
133
134 assert!(xml.contains("c:chart"));
135 }
136
137 #[test]
138 fn test_chart_rel_target() {
139 let part = ChartPart::new(3);
140 assert_eq!(part.rel_target(), "../charts/chart3.xml");
141 }
142}