use super::base::{ContentType, Part, PartType};
use crate::exc::PptxError;
#[derive(Debug, Clone)]
pub struct DefaultType {
pub extension: String,
pub content_type: String,
}
impl DefaultType {
pub fn new(extension: impl Into<String>, content_type: impl Into<String>) -> Self {
DefaultType {
extension: extension.into(),
content_type: content_type.into(),
}
}
}
#[derive(Debug, Clone)]
pub struct OverrideType {
pub part_name: String,
pub content_type: String,
}
impl OverrideType {
pub fn new(part_name: impl Into<String>, content_type: impl Into<String>) -> Self {
OverrideType {
part_name: part_name.into(),
content_type: content_type.into(),
}
}
}
#[derive(Debug, Clone)]
pub struct ContentTypesPart {
defaults: Vec<DefaultType>,
overrides: Vec<OverrideType>,
}
impl ContentTypesPart {
pub fn new() -> Self {
ContentTypesPart {
defaults: vec![
DefaultType::new(
"rels",
"application/vnd.openxmlformats-package.relationships+xml",
),
DefaultType::new("xml", "application/xml"),
DefaultType::new("jpeg", "image/jpeg"),
DefaultType::new("jpg", "image/jpeg"),
DefaultType::new("png", "image/png"),
DefaultType::new("gif", "image/gif"),
DefaultType::new("bmp", "image/bmp"),
DefaultType::new("tiff", "image/tiff"),
DefaultType::new("svg", "image/svg+xml"),
DefaultType::new("mp4", "video/mp4"),
DefaultType::new("mp3", "audio/mpeg"),
DefaultType::new("wav", "audio/wav"),
],
overrides: vec![],
}
}
pub fn add_default(&mut self, extension: impl Into<String>, content_type: impl Into<String>) {
self.defaults
.push(DefaultType::new(extension, content_type));
}
pub fn add_override(&mut self, part_name: impl Into<String>, content_type: impl Into<String>) {
self.overrides
.push(OverrideType::new(part_name, content_type));
}
pub fn add_presentation(&mut self) {
self.add_override(
"/ppt/presentation.xml",
"application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml",
);
}
pub fn add_slide(&mut self, slide_number: usize) {
self.add_override(
format!("/ppt/slides/slide{}.xml", slide_number),
"application/vnd.openxmlformats-officedocument.presentationml.slide+xml",
);
}
pub fn add_slide_layout(&mut self, layout_number: usize) {
self.add_override(
format!("/ppt/slideLayouts/slideLayout{}.xml", layout_number),
"application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml",
);
}
pub fn add_slide_master(&mut self, master_number: usize) {
self.add_override(
format!("/ppt/slideMasters/slideMaster{}.xml", master_number),
"application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml",
);
}
pub fn add_theme(&mut self, theme_number: usize) {
self.add_override(
format!("/ppt/theme/theme{}.xml", theme_number),
"application/vnd.openxmlformats-officedocument.theme+xml",
);
}
pub fn add_notes_slide(&mut self, notes_number: usize) {
self.add_override(
format!("/ppt/notesSlides/notesSlide{}.xml", notes_number),
"application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml",
);
}
pub fn add_chart(&mut self, chart_number: usize) {
self.add_override(
format!("/ppt/charts/chart{}.xml", chart_number),
"application/vnd.openxmlformats-officedocument.drawingml.chart+xml",
);
}
pub fn add_core_properties(&mut self) {
self.add_override(
"/docProps/core.xml",
"application/vnd.openxmlformats-package.core-properties+xml",
);
}
pub fn add_app_properties(&mut self) {
self.add_override(
"/docProps/app.xml",
"application/vnd.openxmlformats-officedocument.extended-properties+xml",
);
}
fn generate_xml(&self) -> String {
let defaults_xml: String = self
.defaults
.iter()
.map(|d| {
format!(
r#"<Default Extension="{}" ContentType="{}"/>"#,
d.extension, d.content_type
)
})
.collect::<Vec<_>>()
.join("\n ");
let overrides_xml: String = self
.overrides
.iter()
.map(|o| {
format!(
r#"<Override PartName="{}" ContentType="{}"/>"#,
o.part_name, o.content_type
)
})
.collect::<Vec<_>>()
.join("\n ");
format!(
r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
{}
{}
</Types>"#,
defaults_xml, overrides_xml
)
}
}
impl Default for ContentTypesPart {
fn default() -> Self {
Self::new()
}
}
impl Part for ContentTypesPart {
fn path(&self) -> &str {
"[Content_Types].xml"
}
fn part_type(&self) -> PartType {
PartType::Relationships
}
fn content_type(&self) -> ContentType {
ContentType::Xml
}
fn to_xml(&self) -> Result<String, PptxError> {
Ok(self.generate_xml())
}
fn from_xml(_xml: &str) -> Result<Self, PptxError> {
Ok(ContentTypesPart::new())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_content_types_new() {
let ct = ContentTypesPart::new();
assert!(!ct.defaults.is_empty());
}
#[test]
fn test_content_types_add_slide() {
let mut ct = ContentTypesPart::new();
ct.add_slide(1);
ct.add_slide(2);
assert_eq!(ct.overrides.len(), 2);
}
#[test]
fn test_content_types_to_xml() {
let mut ct = ContentTypesPart::new();
ct.add_presentation();
ct.add_slide(1);
let xml = ct.to_xml().unwrap();
assert!(xml.contains("<Types"));
assert!(xml.contains("Default Extension"));
assert!(xml.contains("Override PartName"));
}
#[test]
fn test_content_types_path() {
let ct = ContentTypesPart::new();
assert_eq!(ct.path(), "[Content_Types].xml");
}
#[test]
fn test_content_types_add_all() {
let mut ct = ContentTypesPart::new();
ct.add_presentation();
ct.add_slide(1);
ct.add_slide_layout(1);
ct.add_slide_master(1);
ct.add_theme(1);
ct.add_core_properties();
ct.add_app_properties();
assert_eq!(ct.overrides.len(), 7);
}
}