Skip to main content

easyofd_core/action/
ct_action.rs

1//! 动作基类。
2//!
3//! 对应 Java: org.ofdrw.core.action.CT_Action
4
5use super::EventType;
6use super::OfdAction;
7
8/// 动作基类。
9///
10/// 所有具体动作类型的基类,包含事件类型和关联的动作列表。
11///
12/// 对应 Java: org.ofdrw.core.action.CT_Action
13#[derive(Debug, Clone)]
14pub struct CTAction {
15    /// 触发动作的事件类型。
16    ///
17    /// 对应 Java: CT_Action.eventType (EventType)
18    pub event_type: EventType,
19
20    /// 子动作列表。
21    ///
22    /// 一个事件可以触发多个动作。
23    /// 对应 Java: CT_Action 中的子 Action 元素列表
24    pub actions: Vec<Box<dyn OfdAction>>,
25}
26
27impl CTAction {
28    /// 创建一个新的动作基类实例。
29    ///
30    /// 对应 Java: new CT_Action(EventType)
31    #[must_use]
32    pub fn new(event_type: EventType) -> Self {
33        Self {
34            event_type,
35            actions: Vec::new(),
36        }
37    }
38
39    /// 添加一个子动作。
40    ///
41    /// 对应 Java: CT_Action.add(CT_Action)
42    pub fn add_action(&mut self, action: Box<dyn OfdAction>) {
43        self.actions.push(action);
44    }
45
46    /// 序列化为 OFD XML 字符串。
47    ///
48    /// 输出标准 OFD XML 格式的动作元素。
49    #[must_use]
50    pub fn to_xml_string(&self) -> String {
51        let mut xml = format!("<ofd:CT_Action EventType=\"{}\">", self.event_type);
52        for action in &self.actions {
53            xml.push_str(&action.to_xml_string());
54        }
55        xml.push_str("</ofd:CT_Action>");
56        xml
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    /// 简单的测试用动作实现。
65    #[derive(Debug, Clone)]
66    struct TestAction {
67        name: String,
68    }
69
70    impl OfdAction for TestAction {
71        fn to_xml_string(&self) -> String {
72            format!("<ofd:TestAction Name=\"{}\"/>", self.name)
73        }
74
75        fn clone_box(&self) -> Box<dyn OfdAction> {
76            Box::new(self.clone())
77        }
78    }
79
80    #[test]
81    fn test_ct_action_new() {
82        let action = CTAction::new(EventType::PO_DocumentOpen);
83        assert_eq!(action.event_type, EventType::PO_DocumentOpen);
84        assert!(action.actions.is_empty());
85    }
86
87    #[test]
88    fn test_ct_action_to_xml_empty() {
89        let action = CTAction::new(EventType::PO_ButtonClick);
90        let xml = action.to_xml_string();
91        assert!(xml.contains("EventType=\"PO_ButtonClick\""));
92        assert!(xml.contains("<ofd:CT_Action"));
93        assert!(xml.contains("</ofd:CT_Action>"));
94    }
95
96    #[test]
97    fn test_ct_action_with_children() {
98        let mut action = CTAction::new(EventType::PO_DocumentOpen);
99        action.add_action(Box::new(TestAction {
100            name: "test".to_string(),
101        }));
102        let xml = action.to_xml_string();
103        assert!(xml.contains("Name=\"test\""));
104        assert!(xml.contains("<ofd:TestAction"));
105    }
106
107    #[test]
108    fn test_ct_action_clone() {
109        let action = CTAction::new(EventType::PO_PageVisible);
110        let action2 = action.clone();
111        assert_eq!(action2.event_type, EventType::PO_PageVisible);
112    }
113}