1use crate::exc::{Result, PptxError};
6use crate::opc::Package;
7use crate::generator::{SlideContent, create_pptx_with_content};
8use std::io::{Read, Seek};
9use std::path::Path;
10
11#[derive(Debug, Clone, Default)]
13pub struct Presentation {
14 title: String,
15 slides: Vec<SlideContent>,
16}
17
18impl Presentation {
19 pub fn new() -> Self {
21 Presentation {
22 title: String::new(),
23 slides: Vec::new(),
24 }
25 }
26
27 pub fn with_title(title: &str) -> Self {
29 Presentation {
30 title: title.to_string(),
31 slides: Vec::new(),
32 }
33 }
34
35 pub fn title(mut self, title: &str) -> Self {
37 self.title = title.to_string();
38 self
39 }
40
41 pub fn add_slide(mut self, slide: SlideContent) -> Self {
43 self.slides.push(slide);
44 self
45 }
46
47 pub fn slide_count(&self) -> usize {
49 self.slides.len()
50 }
51
52 pub fn get_title(&self) -> &str {
54 &self.title
55 }
56
57 pub fn build(&self) -> Result<Vec<u8>> {
59 if self.slides.is_empty() {
60 return Err(PptxError::InvalidState("Presentation has no slides".into()));
61 }
62 create_pptx_with_content(&self.title, self.slides.clone())
63 .map_err(|e| PptxError::Generic(e.to_string()))
64 }
65
66 pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()> {
68 let data = self.build()?;
69 std::fs::write(path, data)?;
70 Ok(())
71 }
72}
73
74pub fn open<P: AsRef<Path>>(path: P) -> Result<Package> {
76 Package::open(path)
77}
78
79pub fn open_reader<R: Read + Seek>(reader: R) -> Result<Package> {
81 Package::open_reader(reader)
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn test_presentation_builder() {
90 let pres = Presentation::with_title("Test")
91 .add_slide(SlideContent::new("Slide 1").add_bullet("Point 1"));
92
93 assert_eq!(pres.get_title(), "Test");
94 assert_eq!(pres.slide_count(), 1);
95 }
96
97 #[test]
98 fn test_presentation_build() {
99 let pres = Presentation::with_title("Test")
100 .add_slide(SlideContent::new("Slide 1"));
101
102 let result = pres.build();
103 assert!(result.is_ok());
104 }
105}