spreadsheet_ods/
validation.rs

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