umya_spreadsheet/structs/
numbering_format.rs1use std::io::Cursor;
2
3use phf::phf_map;
4use quick_xml::{
5 Reader,
6 Writer,
7 escape,
8 events::BytesStart,
9};
10
11use crate::{
12 reader::driver::get_attribute,
13 writer::driver::write_start_tag,
14};
15
16#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
17pub struct NumberingFormat {
18 number_format_id: u32,
19 format_code: Box<str>,
20 is_build_in: bool,
21}
22
23impl Default for NumberingFormat {
24 #[inline]
25 fn default() -> Self {
26 Self {
27 number_format_id: 0,
28 format_code: NumberingFormat::FORMAT_GENERAL.into(),
29 is_build_in: true,
30 }
31 }
32}
33
34impl NumberingFormat {
35 pub const FORMAT_ACCOUNTING_EUR: &'static str =
36 r#"_("€"* #,##0.00_);_("€"* \(#,##0.00\);_("€"* "-"??_);_(@_)"#;
37 pub const FORMAT_ACCOUNTING_USD: &'static str =
38 r#"_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)"#;
39 pub const FORMAT_CURRENCY_EUR: &'static str = r#"#,##0_-"€""#;
40 pub const FORMAT_CURRENCY_EUR_SIMPLE: &'static str = r#"#,##0.00_-"€""#;
41 pub const FORMAT_CURRENCY_USD: &'static str = r"$#,##0_-";
42 pub const FORMAT_CURRENCY_USD_SIMPLE: &'static str = r##""$"#,##0.00_-"##;
43 pub const FORMAT_DATE_DATETIME: &'static str = "d/m/yy h:mm";
44 pub const FORMAT_DATE_DDMMYYYY: &'static str = "dd-mm-yyyy";
45 pub const FORMAT_DATE_DDMMYYYYSLASH: &'static str = "dd/mm/yyyy";
46 pub const FORMAT_DATE_DMMINUS: &'static str = "d-m";
47 pub const FORMAT_DATE_DMYMINUS: &'static str = "d-m-yy";
48 pub const FORMAT_DATE_DMYSLASH: &'static str = "d/m/yy";
49 pub const FORMAT_DATE_MYMINUS: &'static str = "m-yy";
50 pub const FORMAT_DATE_TIME1: &'static str = "h:mm AM/PM";
51 pub const FORMAT_DATE_TIME2: &'static str = "h:mm:ss AM/PM";
52 pub const FORMAT_DATE_TIME3: &'static str = "h:mm";
53 pub const FORMAT_DATE_TIME4: &'static str = "h:mm:ss";
54 pub const FORMAT_DATE_TIME5: &'static str = "mm:ss";
55 pub const FORMAT_DATE_TIME6: &'static str = "h:mm:ss";
56 pub const FORMAT_DATE_TIME8: &'static str = "h:mm:ss;@";
57 pub const FORMAT_DATE_XLSX14: &'static str = "mm-dd-yy";
58 pub const FORMAT_DATE_XLSX15: &'static str = "d-mmm-yy";
59 pub const FORMAT_DATE_XLSX16: &'static str = "d-mmm";
60 pub const FORMAT_DATE_XLSX17: &'static str = "mmm-yy";
61 pub const FORMAT_DATE_XLSX22: &'static str = "m/d/yy h:mm";
62 pub const FORMAT_DATE_YYYYMMDD: &'static str = "yyyy-mm-dd";
63 pub const FORMAT_DATE_YYYYMMDD2: &'static str = "yyyy-mm-dd";
64 pub const FORMAT_DATE_YYYYMMDDSLASH: &'static str = "yyyy/mm/dd;@";
65 pub const FORMAT_GENERAL: &'static str = "General";
67 pub const FORMAT_NUMBER: &'static str = "0";
68 pub const FORMAT_NUMBER_00: &'static str = "0.00";
69 pub const FORMAT_NUMBER_COMMA_SEPARATED1: &'static str = "#,##0.00";
70 pub const FORMAT_NUMBER_COMMA_SEPARATED2: &'static str = "#,##0.00_-";
71 pub const FORMAT_PERCENTAGE: &'static str = "0%";
72 pub const FORMAT_PERCENTAGE_00: &'static str = "0.00%";
73 pub const FORMAT_TEXT: &'static str = "@";
74
75 #[inline]
76 #[must_use]
77 pub fn number_format_id(&self) -> u32 {
78 self.number_format_id
79 }
80
81 #[inline]
82 #[must_use]
83 #[deprecated(since = "3.0.0", note = "Use number_format_id()")]
84 pub fn get_number_format_id(&self) -> u32 {
85 self.number_format_id()
86 }
87
88 pub fn set_number_format_id(&mut self, value: u32) -> &mut Self {
89 let format_code_result = FILL_BUILT_IN_FORMAT_CODES.entries().find_map(|(key, val)| {
90 if key == &value {
91 Some(val.to_owned())
92 } else {
93 None
94 }
95 });
96
97 self.format_code = format_code_result
98 .expect("Not Found NumberFormatId.")
99 .to_owned()
100 .into_boxed_str();
101 self.number_format_id = value;
102 self.is_build_in = true;
103 self
104 }
105
106 #[inline]
107 pub(crate) fn set_number_format_id_crate(&mut self, value: u32) -> &mut Self {
108 self.number_format_id = value;
109 self
110 }
111
112 pub fn set_format_code<S: Into<String>>(&mut self, value: S) -> &mut Self {
125 self.format_code = value.into().into_boxed_str();
126 for (index, format) in FILL_BUILT_IN_FORMAT_CODES.entries() {
127 if &&*self.format_code == format {
128 self.number_format_id = *index;
129 self.is_build_in = true;
130 return self;
131 }
132 }
133 self.number_format_id = 999_999;
134 self.is_build_in = false;
135 self
136 }
137
138 #[inline]
139 pub(crate) fn set_format_code_crate<S: Into<String>>(&mut self, value: S) -> &mut Self {
140 self.format_code = value.into().into_boxed_str();
141 self
142 }
143
144 #[inline]
145 #[must_use]
146 pub fn format_code(&self) -> &str {
147 &self.format_code
148 }
149
150 #[inline]
151 #[must_use]
152 #[deprecated(since = "3.0.0", note = "Use format_code()")]
153 pub fn get_format_code(&self) -> &str {
154 self.format_code()
155 }
156
157 #[inline]
158 pub(crate) fn is_build_in(&self) -> bool {
159 self.is_build_in
160 }
161
162 #[inline]
163 #[deprecated(since = "3.0.0", note = "Use is_build_in()")]
164 pub(crate) fn get_is_build_in(&self) -> bool {
165 self.is_build_in()
166 }
167
168 #[inline]
169 pub(crate) fn hash_code(&self) -> String {
170 crate::helper::utils::md5_hash(&*self.format_code)
171 }
172
173 #[inline]
174 #[deprecated(since = "3.0.0", note = "Use hash_code()")]
175 pub(crate) fn get_hash_code(&self) -> String {
176 self.hash_code()
177 }
178
179 pub(crate) fn set_attributes<R: std::io::BufRead>(
180 &mut self,
181 _reader: &mut Reader<R>,
182 e: &BytesStart,
183 ) {
184 self.number_format_id = get_attribute(e, b"numFmtId")
185 .unwrap()
186 .parse::<u32>()
187 .unwrap();
188 self.format_code = escape::unescape(get_attribute(e, b"formatCode").unwrap().as_str())
189 .unwrap()
190 .to_string()
191 .into_boxed_str();
192 self.is_build_in = false;
193 }
194
195 pub(crate) fn write_to(&self, writer: &mut Writer<Cursor<Vec<u8>>>, number_format_id: u32) {
196 write_start_tag(
198 writer,
199 "numFmt",
200 vec![
201 ("numFmtId", number_format_id.to_string()).into(),
202 ("formatCode", &self.format_code).into(),
203 ],
204 true,
205 );
206 }
207}
208
209pub(crate) static FILL_BUILT_IN_FORMAT_CODES: phf::Map<u32, &'static str> = phf_map! {
210 0u32 => NumberingFormat::FORMAT_GENERAL,
211 1u32 => "0",
212 2u32 => "0.00",
213 3u32 => "#,##0",
214 4u32 => "#,##0.00",
215
216 9u32 => "0%",
217 10u32 => "0.00%",
218 11u32 => "0.00E+00",
219 12u32 => "# ?/?",
220 13u32 => "# ??/??",
221 14u32 => "m/d/yyyy",
222 15u32 => "d-mmm-yy",
223 16u32 => "d-mmm",
224 17u32 => "mmm-yy",
225 18u32 => "h:mm AM/PM",
226 19u32 => "h:mm:ss AM/PM",
227 20u32 => "h:mm",
228 21u32 => "h:mm:ss",
229 22u32 => "m/d/yyyy h:mm",
230
231 37u32 => "#,##0_);(#,##0)",
232 38u32 => "#,##0_);[Red](#,##0)",
233 39u32 => "#,##0.00_);(#,##0.00)",
234 40u32 => "#,##0.00_);[Red](#,##0.00)",
235
236 44u32 => r#"_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)"#,
237 45u32 => "mm:ss",
238 46u32 => "[h]:mm:ss",
239 47u32 => "mm:ss.0",
240 48u32 => "##0.0E+0",
241 49u32 => "@",
242
243 27u32 => "[$-404]e/m/d",
245 30u32 => "m/d/yy",
246 36u32 => "[$-404]e/m/d",
247 50u32 => "[$-404]e/m/d",
248 57u32 => "[$-404]e/m/d",
249
250 59u32 => "t0",
252 60u32 => "t0.00",
253 61u32 => "t#,##0",
254 62u32 => "t#,##0.00",
255 67u32 => "t0%",
256 68u32 => "t0.00%",
257 69u32 => "t# ?/?",
258 70u32 => "t# ??/??",
259
260 28u32 => r#"[$-411]ggge"年"m"月"d"日""#,
262 29u32 => r#"[$-411]ggge"年"m"月"d"日""#,
263 31u32 => r#"yyyy"年"m"月"d"日""#,
264 32u32 => r#"h"時"mm"分""#,
265 33u32 => r#"h"時"mm"分"ss"秒""#,
266 34u32 => r#"yyyy"年"m"月""#,
267 35u32 => r#"m"月"d"日""#,
268 51u32 => r#"[$-411]ggge"年"m"月"d"日""#,
269 52u32 => r#"yyyy"年"m"月""#,
270 53u32 => r#"m"月"d"日""#,
271 54u32 => r#"[$-411]ggge"年"m"月"d"日""#,
272 55u32 => r#"yyyy"年"m"月""#,
273 56u32 => r#"m"月"d"日""#,
274 58u32 => r#"[$-411]ggge"年"m"月"d"日""#,
275};
276
277#[cfg(test)]
278mod tests {
279 use super::*;
280
281 #[test]
282 fn set_number_format_id() {
283 let mut obj = NumberingFormat::default();
284
285 obj.set_number_format_id(0);
286 assert_eq!(obj.format_code(), "General");
287
288 obj.set_number_format_id(1);
289 assert_eq!(obj.format_code(), "0");
290 }
291}