Skip to main content

easyofd_core/page_obj/
ct_common_data.rs

1//! CT_CommonData 文档公共数据。
2
3use super::{CT_PageArea, CT_TemplatePage};
4
5/// 对应 Java: org.ofdrw.core.basicStructure.doc.CT_CommonData
6///
7/// 文档公共数据结构,包含页面区域、资源引用、模板页等全局配置。
8/// 对应 GB/T 33190-2016 图 6。
9#[allow(non_camel_case_types)]
10#[derive(Debug, Clone)]
11pub struct CT_CommonData {
12    /// 最大对象 ID。
13    pub max_unit_id: Option<u32>,
14    /// 页面区域。
15    pub page_area: Option<CT_PageArea>,
16    /// 公共资源引用路径列表。
17    pub public_res: Vec<String>,
18    /// 文档资源引用路径列表。
19    pub document_res: Vec<String>,
20    /// 模板页列表。
21    pub template_pages: Vec<CT_TemplatePage>,
22    /// 默认颜色空间 ID。
23    pub default_cs: Option<u32>,
24}
25
26impl CT_CommonData {
27    /// 创建空的文档公共数据。
28    #[must_use]
29    pub fn new() -> Self {
30        Self {
31            max_unit_id: None,
32            page_area: None,
33            public_res: Vec::new(),
34            document_res: Vec::new(),
35            template_pages: Vec::new(),
36            default_cs: None,
37        }
38    }
39
40    /// 设置最大对象 ID。
41    #[must_use]
42    pub fn max_unit_id(mut self, id: u32) -> Self {
43        self.max_unit_id = Some(id);
44        self
45    }
46
47    /// 设置页面区域。
48    #[must_use]
49    pub fn page_area(mut self, page_area: CT_PageArea) -> Self {
50        self.page_area = Some(page_area);
51        self
52    }
53
54    /// 添加公共资源引用。
55    pub fn add_public_res(&mut self, res: impl Into<String>) {
56        self.public_res.push(res.into());
57    }
58
59    /// 设置公共资源引用(替换所有)。
60    #[must_use]
61    pub fn public_res(mut self, res: impl Into<String>) -> Self {
62        self.public_res = vec![res.into()];
63        self
64    }
65
66    /// 添加文档资源引用。
67    pub fn add_document_res(&mut self, res: impl Into<String>) {
68        self.document_res.push(res.into());
69    }
70
71    /// 设置文档资源引用(替换所有)。
72    #[must_use]
73    pub fn document_res(mut self, res: impl Into<String>) -> Self {
74        self.document_res = vec![res.into()];
75        self
76    }
77
78    /// 添加模板页。
79    pub fn add_template_page(&mut self, tpl: CT_TemplatePage) {
80        self.template_pages.push(tpl);
81    }
82
83    /// 设置默认颜色空间 ID。
84    #[must_use]
85    pub fn default_cs(mut self, id: u32) -> Self {
86        self.default_cs = Some(id);
87        self
88    }
89
90    /// 获取最大对象 ID。
91    #[must_use]
92    pub fn get_max_unit_id(&self) -> Option<u32> {
93        self.max_unit_id
94    }
95
96    /// 获取页面区域。
97    #[must_use]
98    pub fn get_page_area(&self) -> Option<&CT_PageArea> {
99        self.page_area.as_ref()
100    }
101
102    /// 获取公共资源列表。
103    #[must_use]
104    pub fn get_public_res(&self) -> &[String] {
105        &self.public_res
106    }
107
108    /// 获取文档资源列表。
109    #[must_use]
110    pub fn get_document_res(&self) -> &[String] {
111        &self.document_res
112    }
113
114    /// 获取模板页列表。
115    #[must_use]
116    pub fn get_template_pages(&self) -> &[CT_TemplatePage] {
117        &self.template_pages
118    }
119
120    /// 序列化为 OFD XML 字符串。
121    #[must_use]
122    pub fn to_xml_string(&self) -> String {
123        use std::fmt::Write;
124        let mut xml = String::from("<ofd:CommonData>\n");
125        if let Some(id) = self.max_unit_id {
126            writeln!(xml, "  <ofd:MaxUnitID>{id}</ofd:MaxUnitID>").expect("写入内存缓冲区不会失败");
127        }
128        if let Some(ref pa) = self.page_area {
129            writeln!(xml, "  {}", pa.to_xml_string()).expect("写入内存缓冲区不会失败");
130        }
131        for res in &self.public_res {
132            writeln!(xml, "  <ofd:PublicRes>{res}</ofd:PublicRes>")
133                .expect("写入内存缓冲区不会失败");
134        }
135        for res in &self.document_res {
136            writeln!(xml, "  <ofd:DocumentRes>{res}</ofd:DocumentRes>")
137                .expect("写入内存缓冲区不会失败");
138        }
139        for tpl in &self.template_pages {
140            writeln!(xml, "  {}", tpl.to_xml_string()).expect("写入内存缓冲区不会失败");
141        }
142        if let Some(cs) = self.default_cs {
143            writeln!(xml, "  <ofd:DefaultCS>{cs}</ofd:DefaultCS>").expect("写入内存缓冲区不会失败");
144        }
145        xml.push_str("</ofd:CommonData>\n");
146        xml
147    }
148}
149
150impl Default for CT_CommonData {
151    fn default() -> Self {
152        Self::new()
153    }
154}
155
156#[cfg(test)]
157mod tests {
158    use super::*;
159
160    #[test]
161    fn test_ct_common_data_new() {
162        let cd = CT_CommonData::new();
163        assert!(cd.max_unit_id.is_none());
164        assert!(cd.page_area.is_none());
165        assert!(cd.public_res.is_empty());
166        assert!(cd.document_res.is_empty());
167        assert!(cd.template_pages.is_empty());
168        assert!(cd.default_cs.is_none());
169    }
170
171    #[test]
172    fn test_ct_common_data_builder() {
173        let cd = CT_CommonData::new()
174            .max_unit_id(100)
175            .page_area(CT_PageArea::with_physical(0.0, 0.0, 210.0, 297.0))
176            .public_res("PublicRes.xml")
177            .document_res("DocumentRes.xml")
178            .default_cs(1);
179        assert_eq!(cd.get_max_unit_id(), Some(100));
180        assert!(cd.get_page_area().is_some());
181        assert_eq!(cd.get_public_res(), &["PublicRes.xml"]);
182        assert_eq!(cd.get_document_res(), &["DocumentRes.xml"]);
183    }
184
185    #[test]
186    fn test_ct_common_data_add_resources() {
187        let mut cd = CT_CommonData::new();
188        cd.add_public_res("res1.xml");
189        cd.add_public_res("res2.xml");
190        cd.add_document_res("doc_res.xml");
191        assert_eq!(cd.get_public_res().len(), 2);
192        assert_eq!(cd.get_document_res().len(), 1);
193    }
194
195    #[test]
196    fn test_ct_common_data_add_template_page() {
197        let mut cd = CT_CommonData::new();
198        cd.add_template_page(CT_TemplatePage::new(1).name("tpl1"));
199        cd.add_template_page(CT_TemplatePage::new(2).name("tpl2"));
200        assert_eq!(cd.get_template_pages().len(), 2);
201    }
202
203    #[test]
204    fn test_ct_common_data_to_xml_basic() {
205        let cd = CT_CommonData::new();
206        let xml = cd.to_xml_string();
207        assert!(xml.contains("<ofd:CommonData>"));
208        assert!(xml.contains("</ofd:CommonData>"));
209    }
210
211    #[test]
212    fn test_ct_common_data_to_xml_full() {
213        let mut cd = CT_CommonData::new()
214            .max_unit_id(50)
215            .page_area(CT_PageArea::with_physical(0.0, 0.0, 210.0, 297.0))
216            .default_cs(2);
217        cd.add_public_res("PublicRes.xml");
218        cd.add_template_page(CT_TemplatePage::new(1).name("bg"));
219        let xml = cd.to_xml_string();
220        assert!(xml.contains("<ofd:MaxUnitID>50</ofd:MaxUnitID>"));
221        assert!(xml.contains("ofd:PageArea"));
222        assert!(xml.contains("<ofd:PublicRes>PublicRes.xml</ofd:PublicRes>"));
223        assert!(xml.contains("<ofd:DefaultCS>2</ofd:DefaultCS>"));
224        assert!(xml.contains("TemplatePageName=\"bg\""));
225    }
226
227    #[test]
228    fn test_ct_common_data_clone_debug() {
229        let cd = CT_CommonData::new().max_unit_id(1);
230        let cd2 = cd.clone();
231        assert_eq!(cd2.get_max_unit_id(), Some(1));
232        assert!(format!("{cd:?}").contains("CT_CommonData"));
233    }
234}