spreadsheet_ods/
validation.rs

1//!
2//! Content validation.
3//!
4
5use get_size::GetSize;
6use std::convert::TryFrom;
7use std::fmt::{Display, Formatter};
8
9use crate::condition::Condition;
10use crate::style::AnyStyleRef;
11use crate::text::TextTag;
12use crate::{CellRef, OdsError};
13use get_size_derive::GetSize;
14use std::borrow::Borrow;
15use std::str::from_utf8;
16
17/// This defines how lists of entries are displayed to the user.
18#[derive(Copy, Clone, Debug, Default, GetSize)]
19pub enum ValidationDisplay {
20    /// Don't show.
21    NoDisplay,
22    /// Show the entries in the original order.
23    #[default]
24    Unsorted,
25    /// Sort the entries.
26    SortAscending,
27}
28
29impl TryFrom<&str> for ValidationDisplay {
30    type Error = OdsError;
31
32    fn try_from(value: &str) -> Result<Self, Self::Error> {
33        match value {
34            "unsorted" => Ok(ValidationDisplay::Unsorted),
35            "sort-ascending" => Ok(ValidationDisplay::SortAscending),
36            "none" => Ok(ValidationDisplay::NoDisplay),
37            _ => Err(OdsError::Parse(
38                "invalid table:display-list ",
39                Some(value.to_string()),
40            )),
41        }
42    }
43}
44
45impl TryFrom<&[u8]> for ValidationDisplay {
46    type Error = OdsError;
47
48    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
49        match value {
50            b"unsorted" => Ok(ValidationDisplay::Unsorted),
51            b"sort-ascending" => Ok(ValidationDisplay::SortAscending),
52            b"none" => Ok(ValidationDisplay::NoDisplay),
53            _ => Err(OdsError::Parse(
54                "invalid table:display-list ",
55                Some(from_utf8(value)?.into()),
56            )),
57        }
58    }
59}
60
61/// Help text for a validation.
62#[derive(Clone, Debug, GetSize)]
63pub struct ValidationHelp {
64    display: bool,
65    title: Option<String>,
66    text: Option<Box<TextTag>>,
67}
68
69impl Default for ValidationHelp {
70    fn default() -> Self {
71        Self::new()
72    }
73}
74
75impl ValidationHelp {
76    /// Empty message.
77    pub fn new() -> Self {
78        Self {
79            display: true,
80            title: None,
81            text: None,
82        }
83    }
84
85    /// Show the help text.
86    pub fn set_display(&mut self, display: bool) {
87        self.display = display;
88    }
89
90    /// Show the help text.
91    pub fn display(&self) -> bool {
92        self.display
93    }
94
95    /// Title for the help text.
96    pub fn set_title(&mut self, title: Option<String>) {
97        self.title = title;
98    }
99
100    /// Title for the help text.
101    pub fn title(&self) -> Option<&str> {
102        self.title.as_deref()
103    }
104
105    /// Help text as formatted text.
106    pub fn set_text(&mut self, text: Option<TextTag>) {
107        if let Some(txt) = text {
108            self.text = Some(Box::new(txt));
109        } else {
110            self.text = None;
111        };
112    }
113
114    /// Help text as formatted text.
115    pub fn text(&self) -> Option<&TextTag> {
116        self.text.as_deref()
117    }
118}
119
120/// Determines the severity of a validation error.
121/// When this is error the entered value is discarded, otherwise
122/// the error is just shown as a warning or a hint.
123#[derive(Copy, Clone, Debug, GetSize)]
124pub enum MessageType {
125    /// Hard error.
126    Error,
127    /// Warning.
128    Warning,
129    /// Informational.
130    Info,
131}
132
133impl Display for MessageType {
134    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
135        match self {
136            MessageType::Error => write!(f, "stop"),
137            MessageType::Warning => write!(f, "warning"),
138            MessageType::Info => write!(f, "information"),
139        }
140    }
141}
142
143/// Error handling for content validations.
144#[derive(Clone, Debug, GetSize)]
145pub struct ValidationError {
146    display: bool,
147    msg_type: MessageType,
148    title: Option<String>,
149    text: Option<Box<TextTag>>,
150}
151
152impl Default for ValidationError {
153    fn default() -> Self {
154        Self::new()
155    }
156}
157
158impl ValidationError {
159    /// Empty message.
160    pub fn new() -> Self {
161        Self {
162            display: true,
163            msg_type: MessageType::Error,
164            title: None,
165            text: None,
166        }
167    }
168
169    /// Is the error text shown.
170    pub fn set_display(&mut self, display: bool) {
171        self.display = display;
172    }
173
174    /// Is the error text shown.
175    pub fn display(&self) -> bool {
176        self.display
177    }
178
179    /// Type of error.
180    pub fn set_msg_type(&mut self, msg_type: MessageType) {
181        self.msg_type = msg_type;
182    }
183
184    /// Type of error.
185    pub fn msg_type(&self) -> &MessageType {
186        &self.msg_type
187    }
188
189    /// Title for the message.
190    pub fn set_title(&mut self, title: Option<String>) {
191        self.title = title;
192    }
193
194    /// Title for the message.
195    pub fn title(&self) -> Option<&str> {
196        self.title.as_deref()
197    }
198
199    /// Styled text for the message.
200    pub fn set_text(&mut self, text: Option<TextTag>) {
201        if let Some(txt) = text {
202            self.text = Some(Box::new(txt));
203        } else {
204            self.text = None;
205        };
206    }
207
208    /// Styled text for the message.
209    pub fn text(&self) -> Option<&TextTag> {
210        self.text.as_deref()
211    }
212}
213
214style_ref2!(ValidationRef);
215
216/// Cell content validations.
217///
218/// This defines a validity constraint via the contained condition.
219/// It can be applied to a cell by setting the validation name.
220#[derive(Clone, Debug, Default, GetSize)]
221pub struct Validation {
222    name: String,
223    condition: Condition,
224    base_cell: CellRef,
225    allow_empty: bool,
226    display_list: ValidationDisplay,
227    err: Option<ValidationError>,
228    help: Option<ValidationHelp>,
229}
230
231impl Validation {
232    /// Empty validation.
233    pub fn new() -> Self {
234        Self {
235            name: Default::default(),
236            condition: Default::default(),
237            base_cell: Default::default(),
238            allow_empty: true,
239            display_list: Default::default(),
240            err: Some(ValidationError {
241                display: true,
242                msg_type: MessageType::Error,
243                title: None,
244                text: None,
245            }),
246            help: None,
247        }
248    }
249
250    /// Validation name.
251    pub fn set_name<S: AsRef<str>>(&mut self, name: S) {
252        self.name = name.as_ref().to_string();
253    }
254
255    /// Validation name.
256    pub fn name(&self) -> &str {
257        self.name.as_str()
258    }
259
260    /// Creates a reference struct for this one.
261    pub fn validation_ref(&self) -> ValidationRef {
262        ValidationRef::from(self.name.clone())
263    }
264
265    /// Sets the condition that is checked for new values.
266    pub fn set_condition(&mut self, cond: Condition) {
267        self.condition = cond;
268    }
269
270    /// Condition for new values.
271    pub fn condition(&self) -> &Condition {
272        &self.condition
273    }
274
275    /// Base-cell for the validation. Relative CellReferences in the
276    /// condition are relative to this cell. They are moved with the
277    /// actual cell this condition is applied to.
278    pub fn set_base_cell(&mut self, base: CellRef) {
279        self.base_cell = base;
280    }
281
282    /// Base-cell for the validation.
283    pub fn base_cell(&self) -> &CellRef {
284        &self.base_cell
285    }
286
287    /// Empty ok?
288    pub fn set_allow_empty(&mut self, allow: bool) {
289        self.allow_empty = allow;
290    }
291
292    /// Empty ok?
293    pub fn allow_empty(&self) -> bool {
294        self.allow_empty
295    }
296
297    /// Display list of choices.
298    pub fn set_display(&mut self, display: ValidationDisplay) {
299        self.display_list = display;
300    }
301
302    /// Display list of choices.
303    pub fn display(&self) -> ValidationDisplay {
304        self.display_list
305    }
306
307    /// Error message.
308    pub fn set_err(&mut self, err: Option<ValidationError>) {
309        self.err = err;
310    }
311
312    /// Error message.
313    pub fn err(&self) -> Option<&ValidationError> {
314        self.err.as_ref()
315    }
316
317    /// Help message.
318    pub fn set_help(&mut self, help: Option<ValidationHelp>) {
319        self.help = help;
320    }
321
322    /// Help message.
323    pub fn help(&self) -> Option<&ValidationHelp> {
324        self.help.as_ref()
325    }
326}