Skip to main content

easyofd_core/annotation/
appearance.rs

1//! 注释静态外观。
2
3use std::fmt::Write;
4
5/// 对应 Java: org.ofdrw.core.annotation.Appearance
6///
7/// 注释的静态外观,描述注释在页面上的绘制方式。
8#[derive(Debug, Clone, PartialEq)]
9pub struct Appearance {
10    /// 外观标识符。
11    pub id: String,
12    /// 外观类型(Normal / Rollover / Down)。
13    pub appearance_type: String,
14    /// 外观资源文件路径。
15    pub resource_path: Option<String>,
16}
17
18impl Appearance {
19    /// 创建一个新的外观对象。
20    #[must_use]
21    pub fn new(id: impl Into<String>, appearance_type: impl Into<String>) -> Self {
22        Self {
23            id: id.into(),
24            appearance_type: appearance_type.into(),
25            resource_path: None,
26        }
27    }
28
29    /// 设置资源路径。
30    #[must_use]
31    pub fn resource_path(mut self, path: impl Into<String>) -> Self {
32        self.resource_path = Some(path.into());
33        self
34    }
35
36    /// 序列化为 XML 字符串。
37    #[must_use]
38    pub fn to_xml_string(&self) -> String {
39        let mut xml = format!(
40            r#"<ofd:Appearance ID="{}" Type="{}""#,
41            self.id, self.appearance_type
42        );
43        if let Some(ref path) = self.resource_path {
44            let _ = write!(xml, r#" ResourcePath="{path}""#);
45        }
46        xml.push_str(" />");
47        xml
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn test_appearance_new() {
57        let a = Appearance::new("app1", "Normal");
58        assert_eq!(a.id, "app1");
59        assert_eq!(a.appearance_type, "Normal");
60        assert!(a.resource_path.is_none());
61    }
62
63    #[test]
64    fn test_appearance_builder() {
65        let a = Appearance::new("app2", "Rollover").resource_path("/res/appearance.xml");
66        assert_eq!(a.resource_path.as_deref(), Some("/res/appearance.xml"));
67    }
68
69    #[test]
70    fn test_appearance_to_xml_string_basic() {
71        let a = Appearance::new("app1", "Normal");
72        let xml = a.to_xml_string();
73        assert!(xml.contains(r#"ID="app1""#));
74        assert!(xml.contains(r#"Type="Normal""#));
75        assert!(!xml.contains("ResourcePath"));
76    }
77
78    #[test]
79    fn test_appearance_to_xml_string_with_resource() {
80        let a = Appearance::new("app1", "Normal").resource_path("/res/a.xml");
81        let xml = a.to_xml_string();
82        assert!(xml.contains(r#"ResourcePath="/res/a.xml""#));
83    }
84
85    #[test]
86    fn test_appearance_clone_debug() {
87        let a = Appearance::new("x", "Normal");
88        let a2 = a.clone();
89        assert_eq!(a2.id, "x");
90        assert!(format!("{a:?}").contains("Appearance"));
91    }
92}