1use super::base::{Part, PartType, ContentType};
6use crate::exc::PptxError;
7use crate::generator::charts::{Chart, generate_chart_part_xml};
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("No chart data available".to_string()))
85 }
86
87 fn from_xml(xml: &str) -> Result<Self, PptxError> {
88 Ok(ChartPart {
90 path: "ppt/charts/chart1.xml".to_string(),
91 chart_number: 1,
92 chart: None,
93 xml_content: Some(xml.to_string()),
94 })
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101 use crate::generator::charts::{ChartBuilder, ChartType, ChartSeries};
102
103 #[test]
104 fn test_chart_part_new() {
105 let part = ChartPart::new(1);
106 assert_eq!(part.chart_number(), 1);
107 assert_eq!(part.path(), "ppt/charts/chart1.xml");
108 }
109
110 #[test]
111 fn test_chart_part_from_chart() {
112 let chart = ChartBuilder::new("Test", ChartType::Bar)
113 .categories(vec!["A", "B"])
114 .add_series(ChartSeries::new("Data", vec![1.0, 2.0]))
115 .build();
116
117 let part = ChartPart::from_chart(2, chart);
118 assert_eq!(part.chart_number(), 2);
119 assert!(part.chart().is_some());
120 }
121
122 #[test]
123 fn test_chart_part_to_xml() {
124 let chart = ChartBuilder::new("Sales", ChartType::Bar)
125 .categories(vec!["Q1", "Q2"])
126 .add_series(ChartSeries::new("2024", vec![100.0, 150.0]))
127 .build();
128
129 let part = ChartPart::from_chart(1, chart);
130 let xml = part.to_xml().unwrap();
131
132 assert!(xml.contains("c:chart"));
133 }
134
135 #[test]
136 fn test_chart_rel_target() {
137 let part = ChartPart::new(3);
138 assert_eq!(part.rel_target(), "../charts/chart3.xml");
139 }
140}