1use super::base::{ContentType, Part, PartType};
6use crate::exc::PptxError;
7
8#[derive(Debug, Clone)]
10pub struct DefaultType {
11 pub extension: String,
12 pub content_type: String,
13}
14
15impl DefaultType {
16 pub fn new(extension: impl Into<String>, content_type: impl Into<String>) -> Self {
17 DefaultType {
18 extension: extension.into(),
19 content_type: content_type.into(),
20 }
21 }
22}
23
24#[derive(Debug, Clone)]
26pub struct OverrideType {
27 pub part_name: String,
28 pub content_type: String,
29}
30
31impl OverrideType {
32 pub fn new(part_name: impl Into<String>, content_type: impl Into<String>) -> Self {
33 OverrideType {
34 part_name: part_name.into(),
35 content_type: content_type.into(),
36 }
37 }
38}
39
40#[derive(Debug, Clone)]
42pub struct ContentTypesPart {
43 defaults: Vec<DefaultType>,
44 overrides: Vec<OverrideType>,
45}
46
47impl ContentTypesPart {
48 pub fn new() -> Self {
50 ContentTypesPart {
51 defaults: vec![
52 DefaultType::new(
53 "rels",
54 "application/vnd.openxmlformats-package.relationships+xml",
55 ),
56 DefaultType::new("xml", "application/xml"),
57 DefaultType::new("jpeg", "image/jpeg"),
58 DefaultType::new("jpg", "image/jpeg"),
59 DefaultType::new("png", "image/png"),
60 DefaultType::new("gif", "image/gif"),
61 DefaultType::new("bmp", "image/bmp"),
62 DefaultType::new("tiff", "image/tiff"),
63 DefaultType::new("svg", "image/svg+xml"),
64 DefaultType::new("mp4", "video/mp4"),
65 DefaultType::new("mp3", "audio/mpeg"),
66 DefaultType::new("wav", "audio/wav"),
67 ],
68 overrides: vec![],
69 }
70 }
71
72 pub fn add_default(&mut self, extension: impl Into<String>, content_type: impl Into<String>) {
74 self.defaults
75 .push(DefaultType::new(extension, content_type));
76 }
77
78 pub fn add_override(&mut self, part_name: impl Into<String>, content_type: impl Into<String>) {
80 self.overrides
81 .push(OverrideType::new(part_name, content_type));
82 }
83
84 pub fn add_presentation(&mut self) {
86 self.add_override(
87 "/ppt/presentation.xml",
88 "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml",
89 );
90 }
91
92 pub fn add_slide(&mut self, slide_number: usize) {
94 self.add_override(
95 format!("/ppt/slides/slide{}.xml", slide_number),
96 "application/vnd.openxmlformats-officedocument.presentationml.slide+xml",
97 );
98 }
99
100 pub fn add_slide_layout(&mut self, layout_number: usize) {
102 self.add_override(
103 format!("/ppt/slideLayouts/slideLayout{}.xml", layout_number),
104 "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml",
105 );
106 }
107
108 pub fn add_slide_master(&mut self, master_number: usize) {
110 self.add_override(
111 format!("/ppt/slideMasters/slideMaster{}.xml", master_number),
112 "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml",
113 );
114 }
115
116 pub fn add_theme(&mut self, theme_number: usize) {
118 self.add_override(
119 format!("/ppt/theme/theme{}.xml", theme_number),
120 "application/vnd.openxmlformats-officedocument.theme+xml",
121 );
122 }
123
124 pub fn add_notes_slide(&mut self, notes_number: usize) {
126 self.add_override(
127 format!("/ppt/notesSlides/notesSlide{}.xml", notes_number),
128 "application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml",
129 );
130 }
131
132 pub fn add_chart(&mut self, chart_number: usize) {
134 self.add_override(
135 format!("/ppt/charts/chart{}.xml", chart_number),
136 "application/vnd.openxmlformats-officedocument.drawingml.chart+xml",
137 );
138 }
139
140 pub fn add_core_properties(&mut self) {
142 self.add_override(
143 "/docProps/core.xml",
144 "application/vnd.openxmlformats-package.core-properties+xml",
145 );
146 }
147
148 pub fn add_app_properties(&mut self) {
150 self.add_override(
151 "/docProps/app.xml",
152 "application/vnd.openxmlformats-officedocument.extended-properties+xml",
153 );
154 }
155
156 fn generate_xml(&self) -> String {
157 let defaults_xml: String = self
158 .defaults
159 .iter()
160 .map(|d| {
161 format!(
162 r#"<Default Extension="{}" ContentType="{}"/>"#,
163 d.extension, d.content_type
164 )
165 })
166 .collect::<Vec<_>>()
167 .join("\n ");
168
169 let overrides_xml: String = self
170 .overrides
171 .iter()
172 .map(|o| {
173 format!(
174 r#"<Override PartName="{}" ContentType="{}"/>"#,
175 o.part_name, o.content_type
176 )
177 })
178 .collect::<Vec<_>>()
179 .join("\n ");
180
181 format!(
182 r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
183<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
184 {}
185 {}
186</Types>"#,
187 defaults_xml, overrides_xml
188 )
189 }
190}
191
192impl Default for ContentTypesPart {
193 fn default() -> Self {
194 Self::new()
195 }
196}
197
198impl Part for ContentTypesPart {
199 fn path(&self) -> &str {
200 "[Content_Types].xml"
201 }
202
203 fn part_type(&self) -> PartType {
204 PartType::Relationships
205 }
206
207 fn content_type(&self) -> ContentType {
208 ContentType::Xml
209 }
210
211 fn to_xml(&self) -> Result<String, PptxError> {
212 Ok(self.generate_xml())
213 }
214
215 fn from_xml(_xml: &str) -> Result<Self, PptxError> {
216 Ok(ContentTypesPart::new())
218 }
219}
220
221#[cfg(test)]
222mod tests {
223 use super::*;
224
225 #[test]
226 fn test_content_types_new() {
227 let ct = ContentTypesPart::new();
228 assert!(!ct.defaults.is_empty());
229 }
230
231 #[test]
232 fn test_content_types_add_slide() {
233 let mut ct = ContentTypesPart::new();
234 ct.add_slide(1);
235 ct.add_slide(2);
236 assert_eq!(ct.overrides.len(), 2);
237 }
238
239 #[test]
240 fn test_content_types_to_xml() {
241 let mut ct = ContentTypesPart::new();
242 ct.add_presentation();
243 ct.add_slide(1);
244 let xml = ct.to_xml().unwrap();
245 assert!(xml.contains("<Types"));
246 assert!(xml.contains("Default Extension"));
247 assert!(xml.contains("Override PartName"));
248 }
249
250 #[test]
251 fn test_content_types_path() {
252 let ct = ContentTypesPart::new();
253 assert_eq!(ct.path(), "[Content_Types].xml");
254 }
255
256 #[test]
257 fn test_content_types_add_all() {
258 let mut ct = ContentTypesPart::new();
259 ct.add_presentation();
260 ct.add_slide(1);
261 ct.add_slide_layout(1);
262 ct.add_slide_master(1);
263 ct.add_theme(1);
264 ct.add_core_properties();
265 ct.add_app_properties();
266 assert_eq!(ct.overrides.len(), 7);
267 }
268}