spreadsheet_ods/format/
mod.rs

1//!
2//! Defines one ValueFormatXX per ValueType for textual formatting of those values.
3//!
4//! ```
5//! use spreadsheet_ods::{ValueType};
6//! use spreadsheet_ods::format::{FormatCalendarStyle, FormatNumberStyle, ValueFormatDateTime, ValueFormatNumber};
7//!
8//! let mut v = ValueFormatDateTime::new_named("dt0");
9//! v.part_day().long_style().build();
10//! v.part_text(".").build();
11//! v.part_month().long_style().build();
12//! v.part_text(".").build();
13//! v.part_year().long_style().build();
14//! v.part_text(" ").build();
15//! v.part_hours().long_style().build();
16//! v.part_text(":").build();
17//! v.part_minutes().long_style().build();
18//! v.part_text(":").build();
19//! v.part_seconds().long_style().build();
20//!
21//! let mut v = ValueFormatNumber::new_named("n3");
22//! v.part_number().decimal_places(3).build();
23//! ```
24//!
25
26// This cares about the following parts of office:styles and office:automatic-styles.
27//
28// <number:boolean-style> 16.29.24,
29// <number:currency-style> 16.29.8,
30// <number:date-style> 16.29.11,
31// <number:number-style> 16.29.2,
32// <number:percentage-style> 16.29.10,
33// <number:text-style> 16.29.26,
34// <number:time-style> 16.29.19,
35//
36
37mod builder;
38mod create;
39mod stylemap;
40
41pub use builder::*;
42pub use create::*;
43pub use stylemap::*;
44
45use crate::attrmap2::AttrMap2;
46use crate::color::Rgb;
47use crate::style::units::{
48    Angle, FontSize, FontStyle, FontVariant, FontWeight, FormatSource, Length, LetterSpacing,
49    LineMode, LineStyle, LineType, LineWidth, Percent, RotationScale, TextCombine, TextCondition,
50    TextDisplay, TextEmphasize, TextEmphasizePosition, TextPosition, TextRelief, TextTransform,
51    TransliterationStyle,
52};
53use crate::style::AnyStyleRef;
54use crate::style::ParseStyleAttr;
55use crate::style::{
56    color_string, shadow_string, text_position, StyleOrigin, StyleUse, TextStyleRef,
57};
58use crate::{OdsError, ValueType};
59use core::borrow::Borrow;
60use get_size2::GetSize;
61use icu_locale_core::subtags::{Language, Region, Script};
62use icu_locale_core::{LanguageIdentifier, Locale};
63use std::fmt::{Display, Formatter};
64use std::str::FromStr;
65
66style_ref2!(ValueFormatRef);
67
68/// Trait used by the builder types.
69pub trait ValueFormatTrait {
70    /// Returns a reference name for this value format.
71    fn format_ref(&self) -> ValueFormatRef;
72
73    /// The style:name attribute specifies names that reference style mechanisms.
74    fn set_name<S: Into<String>>(&mut self, name: S);
75
76    /// The style:name attribute specifies names that reference style mechanisms.
77    fn name(&self) -> &String;
78
79    /// Returns the value type.
80    fn value_type(&self) -> ValueType;
81
82    /// Sets the storage location for this ValueFormat. Either content.xml
83    /// or styles.xml.
84    fn set_origin(&mut self, origin: StyleOrigin);
85
86    /// Returns the storage location.
87    fn origin(&self) -> StyleOrigin;
88
89    /// How is the style used in the document.
90    fn set_styleuse(&mut self, styleuse: StyleUse);
91
92    /// How is the style used in the document.
93    fn styleuse(&self) -> StyleUse;
94
95    /// All direct attributes of the number:xxx-style tag.
96    fn attrmap(&self) -> &AttrMap2;
97
98    /// All direct attributes of the number:xxx-style tag.
99    fn attrmap_mut(&mut self) -> &mut AttrMap2;
100
101    /// Text style attributes.
102    fn textstyle(&self) -> &AttrMap2;
103
104    /// Text style attributes.
105    fn textstyle_mut(&mut self) -> &mut AttrMap2;
106
107    /// Adds a format part.
108    fn push_part(&mut self, part: FormatPart);
109
110    /// Adds all format parts.
111    fn push_parts(&mut self, partvec: &mut Vec<FormatPart>);
112
113    /// Returns the parts.
114    fn parts(&self) -> &Vec<FormatPart>;
115
116    /// Returns the mutable parts.
117    fn parts_mut(&mut self) -> &mut Vec<FormatPart>;
118
119    /// Adds a stylemap.
120    fn push_stylemap(&mut self, stylemap: ValueStyleMap);
121
122    /// Returns the stylemaps
123    fn stylemaps(&self) -> Option<&Vec<ValueStyleMap>>;
124
125    /// Returns the mutable stylemap.
126    fn stylemaps_mut(&mut self) -> &mut Vec<ValueStyleMap>;
127}
128
129valueformat!(ValueFormatBoolean, ValueType::Boolean);
130
131// 16.29.24 <number:boolean-style>
132impl ValueFormatBoolean {
133    part_boolean!();
134
135    push_boolean!();
136}
137
138// 16.29.2 <number:number-style>
139valueformat!(ValueFormatNumber, ValueType::Number);
140
141impl ValueFormatNumber {
142    part_fill_character!();
143    part_fraction!();
144    part_number!();
145    part_scientific!();
146    part_text!();
147
148    push_fraction!();
149    push_number!();
150    push_number_fix!();
151    push_scientific!();
152    push_text!();
153}
154
155// 16.29.10 <number:percentage-style>
156valueformat!(ValueFormatPercentage, ValueType::Percentage);
157
158impl ValueFormatPercentage {
159    part_fill_character!();
160    part_number!();
161    part_text!();
162
163    push_number!();
164    push_number_fix!();
165    push_text!();
166}
167
168// 16.29.8 <number:currency-style>
169valueformat!(ValueFormatCurrency, ValueType::Currency);
170
171impl ValueFormatCurrency {
172    number_automatic_order!(attr);
173
174    part_currency!();
175    part_fill_character!();
176    part_number!();
177    part_text!();
178
179    push_currency_symbol!();
180    push_number!();
181    push_number_fix!();
182    push_text!();
183}
184
185// 16.29.26 <number:text-style>
186valueformat!(ValueFormatText, ValueType::Text);
187
188impl ValueFormatText {
189    part_fill_character!();
190    part_text!();
191    part_text_content!();
192
193    push_text!();
194    push_text_content!();
195}
196
197// 16.29.11 <number:date-style>
198valueformat!(ValueFormatDateTime, ValueType::DateTime);
199
200impl ValueFormatDateTime {
201    number_automatic_order!(attr);
202    number_format_source!(attr);
203
204    part_am_pm!();
205    part_day!();
206    part_day_of_week!();
207    part_era!();
208    part_fill_character!();
209    part_hours!();
210    part_minutes!();
211    part_month!();
212    part_quarter!();
213    part_seconds!();
214    part_text!();
215    part_week_of_year!();
216    part_year!();
217
218    push_am_pm!();
219    push_day!();
220    push_day_of_week!();
221    push_era!();
222    push_hours!();
223    push_minutes!();
224    push_month!();
225    push_quarter!();
226    push_seconds!();
227    push_text!();
228    push_week_of_year!();
229    push_year!();
230}
231
232// 16.29.19 <number:time-style>
233valueformat!(ValueFormatTimeDuration, ValueType::TimeDuration);
234
235impl ValueFormatTimeDuration {
236    number_format_source!(attr);
237    number_truncate_on_overflow!(attr);
238
239    part_am_pm!();
240    part_fill_character!();
241    part_hours!();
242    part_minutes!();
243    part_seconds!();
244    part_text!();
245
246    push_am_pm!();
247    push_hours!();
248    push_minutes!();
249    push_seconds!();
250    push_text!();
251}
252
253/// Identifies the structural parts of a value format.
254#[derive(Debug, Clone, Copy, Eq, PartialEq, GetSize)]
255#[allow(missing_docs)]
256pub enum FormatPartType {
257    Number,
258    FillCharacter,
259    ScientificNumber,
260    Fraction,
261    CurrencySymbol,
262    Day,
263    Month,
264    Year,
265    Era,
266    DayOfWeek,
267    WeekOfYear,
268    Quarter,
269    Hours,
270    Minutes,
271    Seconds,
272    AmPm,
273    Boolean,
274    Text,
275    TextContent,
276}
277
278/// One structural part of a value format.
279#[derive(Debug, Clone, GetSize)]
280pub struct FormatPart {
281    /// What kind of format part is this?
282    part_type: FormatPartType,
283    /// Properties of this part.
284    attr: AttrMap2,
285    /// Textposition for embedded text when acting as a number format part.
286    ///
287    /// The number:position attribute specifies the position where text appears.
288    /// The index of a position starts with 1 and is counted by digits from right to left in the integer part of
289    /// a number, starting left from a decimal separator if one exists, or from the last digit of the number.
290    /// Text is inserted before the digit at the specified position. If the value of number:position
291    /// attribute is greater than the value of number:min-integer-digits and greater than
292    /// the number of integer digits in the number, text is prepended to the number.
293    position: Option<i32>,
294    /// Some content.
295    content: Option<String>,
296}
297
298/// Flag for several PartTypes.
299#[derive(Debug, Clone, Copy, Eq, PartialEq)]
300#[allow(missing_docs)]
301pub enum FormatNumberStyle {
302    Short,
303    Long,
304}
305
306impl Display for FormatNumberStyle {
307    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
308        match self {
309            FormatNumberStyle::Short => write!(f, "short"),
310            FormatNumberStyle::Long => write!(f, "long"),
311        }
312    }
313}
314
315/// Calendar types.
316#[derive(Debug, Clone, Copy, Eq, PartialEq)]
317#[allow(missing_docs)]
318pub enum FormatCalendarStyle {
319    Gregorian,
320    Gengou,
321    Roc,
322    Hanja,
323    Hijri,
324    Jewish,
325    Buddhist,
326}
327
328impl Display for FormatCalendarStyle {
329    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
330        match self {
331            FormatCalendarStyle::Gregorian => write!(f, "gregorian"),
332            FormatCalendarStyle::Gengou => write!(f, "gengou"),
333            FormatCalendarStyle::Roc => write!(f, "ROC"),
334            FormatCalendarStyle::Hanja => write!(f, "hanja"),
335            FormatCalendarStyle::Hijri => write!(f, "hijri"),
336            FormatCalendarStyle::Jewish => write!(f, "jewish"),
337            FormatCalendarStyle::Buddhist => write!(f, "buddhist"),
338        }
339    }
340}
341
342impl FormatPart {
343    /// New, empty
344    pub fn new(ftype: FormatPartType) -> Self {
345        FormatPart {
346            part_type: ftype,
347            attr: Default::default(),
348            position: None,
349            content: None,
350        }
351    }
352
353    /// Sets the kind of the part.
354    pub fn set_part_type(&mut self, p_type: FormatPartType) {
355        self.part_type = p_type;
356    }
357
358    /// What kind of part?
359    pub fn part_type(&self) -> FormatPartType {
360        self.part_type
361    }
362
363    /// General attributes.
364    pub(crate) fn attrmap(&self) -> &AttrMap2 {
365        &self.attr
366    }
367
368    /// General attributes.
369    pub(crate) fn attrmap_mut(&mut self) -> &mut AttrMap2 {
370        &mut self.attr
371    }
372
373    /// Adds an attribute.
374    pub fn set_attr(&mut self, name: &str, value: String) {
375        self.attr.set_attr(name, value);
376    }
377
378    /// Returns a property or a default.
379    pub fn attr_def<'a, 'b, S>(&'a self, name: &'b str, default: S) -> &'a str
380    where
381        S: Into<&'a str>,
382    {
383        self.attr.attr_def(name, default)
384    }
385
386    /// Sets the position for embedded text in a number format part.
387    pub fn set_position(&mut self, pos: i32) {
388        self.position = Some(pos);
389    }
390
391    /// Clear the position for embedded text in a number format part.
392    pub fn clear_position(&mut self) {
393        self.position = None;
394    }
395
396    /// The position for embedded text in a number format part.
397    pub fn position(&self) -> Option<i32> {
398        self.position
399    }
400
401    /// Sets a textual content for this part. This is only used
402    /// for text and currency-symbol.
403    pub fn set_content<S: Into<String>>(&mut self, content: S) {
404        self.content = Some(content.into());
405    }
406
407    /// Append to the textual content of this part.
408    pub fn append_content<S: AsRef<str>>(&mut self, content: S) {
409        match &mut self.content {
410            None => {
411                self.content = Some(content.as_ref().to_string());
412            }
413            Some(v) => {
414                v.push_str(content.as_ref());
415            }
416        }
417    }
418
419    /// Clear the textual content for this part. This is only used
420    /// for text and currency-symbol.
421    pub fn clear_content(&mut self) {
422        self.content = None;
423    }
424
425    /// Returns the text content.
426    pub fn content(&self) -> Option<&String> {
427        self.content.as_ref()
428    }
429}