1use crate::error::Result;
4use crate::parts::presentation::PresentationPart;
5use crate::parts::slide::SlidePart;
6use crate::shapes::Shape;
7
8pub struct Slides<'a> {
10 presentation_part: &'a mut PresentationPart,
11}
12
13impl<'a> Slides<'a> {
14 pub fn new(presentation_part: &'a mut PresentationPart) -> Self {
15 Self {
16 presentation_part,
17 }
18 }
19
20 pub fn add_slide(&mut self, slide_layout: &SlidePart) -> Result<Slide> {
22 use crate::opc::part::Part;
23 use crate::opc::packuri::PackURI;
24 let r_id = self.presentation_part.add_slide(slide_layout as &dyn Part)?;
26
27 let rels = self.presentation_part.relationships();
29 if let Some(rel) = rels.get(&r_id) {
30 let slide_uri = PackURI::new(&format!("/{}", rel.target))?;
31 let slide_part = crate::parts::slide::SlidePart::new(slide_uri, slide_layout as &dyn Part)?;
32 Ok(Slide::with_part(slide_part))
33 } else {
34 Ok(Slide::new())
35 }
36 }
37
38 pub fn get(&self, index: usize) -> Option<Slide> {
40 use crate::opc::part::Part;
41
42 if let Ok(blob) = Part::blob(self.presentation_part) {
44 if let Ok(xml) = String::from_utf8(blob) {
45 let re = regex::Regex::new(r#"<p:sldId\s+[^>]*r:id="([^"]+)""#).ok()?;
47 let r_ids: Vec<&str> = re.captures_iter(&xml)
48 .map(|cap| cap.get(1).map(|m| m.as_str()))
49 .collect::<Option<Vec<_>>>()?;
50
51 if index < r_ids.len() {
52 let r_id = r_ids[index];
53 let rels = self.presentation_part.relationships();
54 if let Some(rel) = rels.get(r_id) {
55 use crate::opc::packuri::PackURI;
56 if let Ok(slide_uri) = PackURI::new(&format!("/{}", rel.target)) {
57 if let Ok(slide_part) = crate::parts::slide::SlidePart::new(slide_uri, self.presentation_part as &dyn Part) {
59 return Some(Slide::with_part(slide_part));
60 }
61 }
62 }
63 }
64 }
65 }
66 None
67 }
68
69 pub fn len(&self) -> usize {
71 use crate::opc::part::Part;
72 if let Ok(blob) = Part::blob(self.presentation_part) {
74 if let Ok(xml) = String::from_utf8(blob) {
75 let pattern = r#"<p:sldId\s"#;
78 return xml.matches(pattern).count();
79 }
80 }
81 0
82 }
83
84 pub fn is_empty(&self) -> bool {
86 self.len() == 0
87 }
88
89 pub fn iter(&self) -> SlideIterator {
91 SlideIterator {
92 slides: self,
93 index: 0,
94 }
95 }
96}
97
98pub struct SlideIterator<'a> {
100 slides: &'a Slides<'a>,
101 index: usize,
102}
103
104impl<'a> Iterator for SlideIterator<'a> {
105 type Item = Slide;
106
107 fn next(&mut self) -> Option<Self::Item> {
108 if self.index < self.slides.len() {
109 let slide = self.slides.get(self.index);
110 self.index += 1;
111 slide
112 } else {
113 None
114 }
115 }
116}
117
118pub struct Slide {
120 part: Option<SlidePart>,
121 name: String,
122}
123
124impl Slide {
125 pub fn new() -> Self {
126 Self {
127 part: None,
128 name: String::new(),
129 }
130 }
131
132 pub fn with_part(part: SlidePart) -> Self {
133 Self {
134 part: Some(part),
135 name: String::new(),
136 }
137 }
138
139 pub fn name(&self) -> &str {
141 &self.name
142 }
143
144 pub fn set_name(&mut self, name: String) {
146 self.name = name;
147 }
148
149 pub fn shapes(&self) -> Vec<Box<dyn Shape>> {
151 use crate::opc::part::Part;
152 use crate::shapes::xml::parse_shapes_from_xml;
153
154 if let Some(ref part) = self.part {
156 if let Ok(blob) = Part::blob(part) {
157 if let Ok(xml) = String::from_utf8(blob) {
158 if let Ok(shapes) = parse_shapes_from_xml(&xml) {
160 return shapes;
161 }
162 }
163 }
164 }
165 Vec::new()
166 }
167
168 pub fn add_shape(&mut self, shape: Box<dyn Shape>) -> Result<()> {
170 use crate::opc::part::Part;
171 use crate::shapes::xml::{shape_to_xml, next_shape_id};
172
173 if let Some(ref mut part) = self.part {
174 let mut xml = Part::to_xml(part)?;
176
177 let next_id = next_shape_id(&xml);
179
180 let shape_xml = shape_to_xml(shape.as_ref(), next_id);
182
183 if let Some(pos) = xml.find("</p:spTree>") {
185 xml.insert_str(pos, &format!(" {}\n ", shape_xml));
186 } else {
187 if let Some(pos) = xml.find("<p:cSld>") {
189 let sp_tree = format!(
190 r#"<p:spTree>
191 <p:nvGrpSpPr>
192 <p:cNvPr id="1" name=""/>
193 <p:cNvGrpSpPr/>
194 <p:nvPr/>
195 </p:nvGrpSpPr>
196 <p:grpSpPr/>
197 {}
198 </p:spTree>"#,
199 shape_xml
200 );
201 xml.insert_str(pos + 8, &format!("\n {}", sp_tree));
202 }
203 }
204
205 part.update_xml(xml)?;
207 }
208 Ok(())
209 }
210}
211
212pub struct SlideMasters {
214 presentation_part: *const PresentationPart, }
216
217impl SlideMasters {
218 pub fn new(_presentation_part: &PresentationPart) -> Self {
219 Self {
220 presentation_part: std::ptr::null(),
221 }
222 }
223
224 pub fn len(&self) -> usize {
226 0
229 }
230
231 pub fn is_empty(&self) -> bool {
233 self.len() == 0
234 }
235}
236
237pub struct SlideLayouts {
239 slide_master_part: *const crate::parts::slide::SlideMasterPart,
240}
241
242impl SlideLayouts {
243 pub fn new(_slide_master_part: &crate::parts::slide::SlideMasterPart) -> Self {
244 Self {
245 slide_master_part: std::ptr::null(),
246 }
247 }
248
249 pub fn get_by_name(&self, _name: &str) -> Option<crate::parts::slide::SlideLayoutPart> {
251 None
254 }
255
256 pub fn len(&self) -> usize {
258 0
261 }
262
263 pub fn is_empty(&self) -> bool {
265 self.len() == 0
266 }
267}
268
269#[cfg(test)]
270mod tests {
271 use super::*;
272 use crate::parts::presentation::PresentationPart;
273
274 #[test]
275 fn test_slide_new() {
276 let slide = Slide::new();
277 assert_eq!(slide.name(), "");
278 assert_eq!(slide.shapes().len(), 0);
279 }
280
281 #[test]
282 fn test_slide_name() {
283 let mut slide = Slide::new();
284 slide.set_name("Test Slide".to_string());
285 assert_eq!(slide.name(), "Test Slide");
286 }
287
288 #[test]
289 fn test_slide_masters_new() {
290 let part = PresentationPart::new().unwrap();
291 let masters = SlideMasters::new(&part);
292 assert_eq!(masters.len(), 0);
293 assert!(masters.is_empty());
294 }
295
296 #[test]
297 fn test_slide_layouts_new() {
298 use crate::parts::slide::SlideMasterPart;
299 use crate::opc::packuri::PackURI;
300
301 let master_part = SlideMasterPart::new(PackURI::new("/ppt/slideMasters/slideMaster1.xml").unwrap()).unwrap();
302 let layouts = SlideLayouts::new(&master_part);
303 assert_eq!(layouts.len(), 0);
304 assert!(layouts.is_empty());
305 }
306
307 #[test]
308 fn test_slides_len_empty() {
309 let mut part = PresentationPart::new().unwrap();
310 let slides = Slides::new(&mut part);
311 assert_eq!(slides.len(), 0);
312 assert!(slides.is_empty());
313 }
314}
315