ppt_rs/parts/
content_types.rs1use super::base::{Part, PartType, ContentType};
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("rels", "application/vnd.openxmlformats-package.relationships+xml"),
53 DefaultType::new("xml", "application/xml"),
54 DefaultType::new("jpeg", "image/jpeg"),
55 DefaultType::new("jpg", "image/jpeg"),
56 DefaultType::new("png", "image/png"),
57 DefaultType::new("gif", "image/gif"),
58 DefaultType::new("bmp", "image/bmp"),
59 DefaultType::new("tiff", "image/tiff"),
60 DefaultType::new("svg", "image/svg+xml"),
61 DefaultType::new("mp4", "video/mp4"),
62 DefaultType::new("mp3", "audio/mpeg"),
63 DefaultType::new("wav", "audio/wav"),
64 ],
65 overrides: vec![],
66 }
67 }
68
69 pub fn add_default(&mut self, extension: impl Into<String>, content_type: impl Into<String>) {
71 self.defaults.push(DefaultType::new(extension, content_type));
72 }
73
74 pub fn add_override(&mut self, part_name: impl Into<String>, content_type: impl Into<String>) {
76 self.overrides.push(OverrideType::new(part_name, content_type));
77 }
78
79 pub fn add_presentation(&mut self) {
81 self.add_override(
82 "/ppt/presentation.xml",
83 "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml"
84 );
85 }
86
87 pub fn add_slide(&mut self, slide_number: usize) {
89 self.add_override(
90 format!("/ppt/slides/slide{}.xml", slide_number),
91 "application/vnd.openxmlformats-officedocument.presentationml.slide+xml"
92 );
93 }
94
95 pub fn add_slide_layout(&mut self, layout_number: usize) {
97 self.add_override(
98 format!("/ppt/slideLayouts/slideLayout{}.xml", layout_number),
99 "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"
100 );
101 }
102
103 pub fn add_slide_master(&mut self, master_number: usize) {
105 self.add_override(
106 format!("/ppt/slideMasters/slideMaster{}.xml", master_number),
107 "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml"
108 );
109 }
110
111 pub fn add_theme(&mut self, theme_number: usize) {
113 self.add_override(
114 format!("/ppt/theme/theme{}.xml", theme_number),
115 "application/vnd.openxmlformats-officedocument.theme+xml"
116 );
117 }
118
119 pub fn add_notes_slide(&mut self, notes_number: usize) {
121 self.add_override(
122 format!("/ppt/notesSlides/notesSlide{}.xml", notes_number),
123 "application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml"
124 );
125 }
126
127 pub fn add_chart(&mut self, chart_number: usize) {
129 self.add_override(
130 format!("/ppt/charts/chart{}.xml", chart_number),
131 "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"
132 );
133 }
134
135 pub fn add_core_properties(&mut self) {
137 self.add_override(
138 "/docProps/core.xml",
139 "application/vnd.openxmlformats-package.core-properties+xml"
140 );
141 }
142
143 pub fn add_app_properties(&mut self) {
145 self.add_override(
146 "/docProps/app.xml",
147 "application/vnd.openxmlformats-officedocument.extended-properties+xml"
148 );
149 }
150
151 fn generate_xml(&self) -> String {
152 let defaults_xml: String = self.defaults.iter()
153 .map(|d| format!(r#"<Default Extension="{}" ContentType="{}"/>"#, d.extension, d.content_type))
154 .collect::<Vec<_>>()
155 .join("\n ");
156
157 let overrides_xml: String = self.overrides.iter()
158 .map(|o| format!(r#"<Override PartName="{}" ContentType="{}"/>"#, o.part_name, o.content_type))
159 .collect::<Vec<_>>()
160 .join("\n ");
161
162 format!(
163 r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
164<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
165 {}
166 {}
167</Types>"#,
168 defaults_xml,
169 overrides_xml
170 )
171 }
172}
173
174impl Default for ContentTypesPart {
175 fn default() -> Self {
176 Self::new()
177 }
178}
179
180impl Part for ContentTypesPart {
181 fn path(&self) -> &str {
182 "[Content_Types].xml"
183 }
184
185 fn part_type(&self) -> PartType {
186 PartType::Relationships
187 }
188
189 fn content_type(&self) -> ContentType {
190 ContentType::Xml
191 }
192
193 fn to_xml(&self) -> Result<String, PptxError> {
194 Ok(self.generate_xml())
195 }
196
197 fn from_xml(_xml: &str) -> Result<Self, PptxError> {
198 Ok(ContentTypesPart::new())
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206
207 #[test]
208 fn test_content_types_new() {
209 let ct = ContentTypesPart::new();
210 assert!(!ct.defaults.is_empty());
211 }
212
213 #[test]
214 fn test_content_types_add_slide() {
215 let mut ct = ContentTypesPart::new();
216 ct.add_slide(1);
217 ct.add_slide(2);
218 assert_eq!(ct.overrides.len(), 2);
219 }
220
221 #[test]
222 fn test_content_types_to_xml() {
223 let mut ct = ContentTypesPart::new();
224 ct.add_presentation();
225 ct.add_slide(1);
226 let xml = ct.to_xml().unwrap();
227 assert!(xml.contains("<Types"));
228 assert!(xml.contains("Default Extension"));
229 assert!(xml.contains("Override PartName"));
230 }
231
232 #[test]
233 fn test_content_types_path() {
234 let ct = ContentTypesPart::new();
235 assert_eq!(ct.path(), "[Content_Types].xml");
236 }
237
238 #[test]
239 fn test_content_types_add_all() {
240 let mut ct = ContentTypesPart::new();
241 ct.add_presentation();
242 ct.add_slide(1);
243 ct.add_slide_layout(1);
244 ct.add_slide_master(1);
245 ct.add_theme(1);
246 ct.add_core_properties();
247 ct.add_app_properties();
248 assert_eq!(ct.overrides.len(), 7);
249 }
250}