text_document/
text.rs

1use std::{
2    cell::{Cell, RefCell},
3    rc::{Rc, Weak},
4};
5
6use crate::{
7    format::{FormatChangeResult, FormattedElement, IsFormat, TextFormat},
8    text_document::{Element, ElementManager, ElementTrait, ModelError},
9    Block,
10};
11
12#[derive(Default, Clone, Debug)]
13pub struct Text {
14    uuid: Cell<usize>,
15    element_manager: Weak<ElementManager>,
16    text: RefCell<String>,
17    text_format: RefCell<TextFormat>,
18}
19
20impl PartialEq for Text {
21    fn eq(&self, other: &Self) -> bool {
22        self.uuid == other.uuid && self.text_format == other.text_format
23    }
24}
25
26impl Text {
27    pub(crate) fn new(element_manager: Weak<ElementManager>) -> Self {
28        Text {
29            element_manager,
30            uuid: Default::default(),
31            text_format: RefCell::new(TextFormat {
32                ..Default::default()
33            }),
34            text: RefCell::new(String::new()),
35        }
36    }
37
38    pub fn uuid(&self) -> usize {
39        self.uuid.get()
40    }
41    pub(crate) fn text_format(&self) -> TextFormat {
42        self.format()
43    }
44
45    pub fn plain_text(&self) -> String {
46        self.text.borrow().clone()
47    }
48
49    pub(crate) fn set_text<S: Into<String>>(&self, text: S) {
50        let plain_text: String = text.into();
51        self.text.replace(plain_text);
52    }
53
54    pub(crate) fn insert_plain_text<S: Into<String>>(&self, position_in_text: usize, text: S) {
55        let plain_text: String = text.into();
56        self.text
57            .borrow_mut()
58            .insert_str(position_in_text, plain_text.as_str())
59    }
60
61    pub(crate) fn split(&self, position_in_text: usize) -> Element {
62        // create new element
63        let element_manager = self.element_manager.upgrade().unwrap();
64        let new_text_rc = element_manager
65            .insert_new_text(self.uuid(), crate::text_document::InsertMode::After)
66            .unwrap();
67
68        let new_element = element_manager.get(new_text_rc.uuid()).unwrap();
69
70        // populate text
71        let original_text = self.plain_text();
72        let split = original_text.split_at(position_in_text);
73        self.set_text(&split.0.to_string());
74        new_text_rc.set_text(&split.1.to_string());
75        new_text_rc.set_format(&self.text_format()).unwrap();
76
77        new_element
78    }
79
80    pub(crate) fn remove_text(
81        &self,
82        left_position_in_text: usize,
83        right_position_in_text: usize,
84    ) -> Result<(), ModelError> {
85        let mut text = self.plain_text();
86
87        if left_position_in_text > text.len() || right_position_in_text > text.len() {
88            return Err(ModelError::OutsideElementBounds);
89        }
90
91        text.replace_range(left_position_in_text..right_position_in_text, "");
92        self.set_text(&text);
93
94        Ok(())
95    }
96
97    pub fn text_length(&self) -> usize {
98        self.text.borrow().len()
99    }
100
101    fn parent_bloc_rc(&self) -> Rc<Block> {
102        let element_manager = self.element_manager.upgrade().unwrap();
103
104        match element_manager
105            .get_parent_element_using_uuid(self.uuid())
106            .unwrap()
107        {
108            Element::BlockElement(block) => block,
109            _ => unreachable!(),
110        }
111    }
112    pub fn position_in_block(&self) -> usize {
113        let parent_block = self.parent_bloc_rc();
114        parent_block.position_of_child(self.uuid())
115    }
116
117    pub fn start(&self) -> usize {
118        let parent_block = self.parent_bloc_rc();
119
120        parent_block.position() + self.position_in_block()
121    }
122
123    pub fn end(&self) -> usize {
124        self.start() + self.text_length()
125    }
126}
127
128impl ElementTrait for Text {
129    fn set_uuid(&self, uuid: usize) {
130        self.uuid.set(uuid);
131    }
132
133    fn verify_rule_with_parent(&self, parent_element: &Element) -> Result<(), ModelError> {
134        match parent_element {
135            Element::FrameElement(_) => Err(ModelError::WrongParent),
136            Element::BlockElement(_) => Ok(()),
137            Element::TextElement(_) => Err(ModelError::WrongParent),
138            Element::ImageElement(_) => Err(ModelError::WrongParent),
139        }
140    }
141}
142impl FormattedElement<TextFormat> for Text {
143    fn format(&self) -> TextFormat {
144        self.text_format.borrow().clone()
145    }
146
147    fn set_format(&self, format: &TextFormat) -> FormatChangeResult {
148        if &*self.text_format.borrow() == format {
149            Ok(None)
150        } else {
151            self.text_format.replace(format.clone());
152            Ok(Some(()))
153        }
154    }
155
156    fn merge_format(&self, format: &TextFormat) -> FormatChangeResult {
157        self.text_format.borrow_mut().merge_with(format)
158    }
159}
160
161#[cfg(test)]
162mod tests {
163
164    use super::*;
165
166    #[test]
167    fn remove_text() {
168        let text = Text::new(Weak::new());
169        text.set_text("plain_text");
170        text.remove_text(0, 10).unwrap();
171
172        assert_eq!(text.plain_text(), "");
173
174        text.set_text("plain_text");
175        text.remove_text(1, 9).unwrap();
176        assert_eq!(text.plain_text(), "pt");
177    }
178}