Skip to main content

umya_spreadsheet/structs/
data_bar.rs

1use std::io::Cursor;
2
3use quick_xml::{
4    Reader,
5    Writer,
6    events::{
7        BytesStart,
8        Event,
9    },
10};
11
12use super::{
13    Color,
14    ConditionalFormatValueObject,
15};
16use crate::{
17    reader::driver::xml_read_loop,
18    writer::driver::{
19        write_end_tag,
20        write_start_tag,
21    },
22};
23
24#[derive(Clone, Default, Debug)]
25pub struct DataBar {
26    cfvo_collection:  Vec<ConditionalFormatValueObject>,
27    color_collection: Vec<Color>,
28}
29
30impl DataBar {
31    #[inline]
32    #[must_use]
33    pub fn cfvo_collection(&self) -> &[ConditionalFormatValueObject] {
34        &self.cfvo_collection
35    }
36
37    #[inline]
38    #[must_use]
39    #[deprecated(since = "3.0.0", note = "Use cfvo_collection()")]
40    pub fn get_cfvo_collection(&self) -> &[ConditionalFormatValueObject] {
41        self.cfvo_collection()
42    }
43
44    #[inline]
45    pub fn set_cfvo_collection(&mut self, value: Vec<ConditionalFormatValueObject>) -> &mut Self {
46        self.cfvo_collection = value;
47        self
48    }
49
50    #[inline]
51    pub fn add_cfvo_collection(&mut self, value: ConditionalFormatValueObject) -> &mut Self {
52        self.cfvo_collection.push(value);
53        self
54    }
55
56    #[inline]
57    #[must_use]
58    pub fn color_collection(&self) -> &[Color] {
59        &self.color_collection
60    }
61
62    #[inline]
63    #[must_use]
64    #[deprecated(since = "3.0.0", note = "Use color_collection()")]
65    pub fn get_color_collection(&self) -> &[Color] {
66        self.color_collection()
67    }
68
69    #[inline]
70    pub fn set_color_collection(&mut self, value: impl Into<Vec<Color>>) -> &mut Self {
71        self.color_collection = value.into();
72        self
73    }
74
75    #[inline]
76    pub fn add_color_collection(&mut self, value: Color) -> &mut Self {
77        self.color_collection.push(value);
78        self
79    }
80
81    pub(crate) fn set_attributes<R: std::io::BufRead>(
82        &mut self,
83        reader: &mut Reader<R>,
84        _e: &BytesStart,
85    ) {
86        xml_read_loop!(
87            reader,
88            ref n @ (Event::Empty(ref e) | Event::Start(ref e)) => {
89                let is_empty = matches!(n, Event::Empty(_));
90                match e.name().into_inner() {
91                    b"cfvo" => {
92                        let mut obj = ConditionalFormatValueObject::default();
93                        obj.set_attributes(reader, e, is_empty);
94                        self.cfvo_collection.push(obj);
95                    }
96                    b"color" => {
97                        let mut obj = Color::default();
98                        obj.set_attributes(reader, e, is_empty);
99                        self.color_collection.push(obj);
100                    }
101                    _ => (),
102                }
103            },
104            Event::End(ref e) => {
105                if e.name().into_inner() == b"dataBar" {
106                    return
107                }
108            },
109            Event::Eof => return
110        );
111    }
112
113    pub(crate) fn write_to(&self, writer: &mut Writer<Cursor<Vec<u8>>>) {
114        // dataBar
115        write_start_tag(writer, "dataBar", vec![], false);
116
117        // cfvo
118        for v in &self.cfvo_collection {
119            v.write_to(writer);
120        }
121
122        // color
123        for v in &self.color_collection {
124            v.write_to_color(writer);
125        }
126
127        write_end_tag(writer, "dataBar");
128    }
129}
130
131#[cfg(test)]
132mod tests {
133    use super::*;
134
135    fn read_data_bar(xml: &str) -> DataBar {
136        let mut reader = Reader::from_reader(std::io::BufReader::new(xml.as_bytes()));
137        let mut buf = Vec::new();
138        loop {
139            match reader.read_event_into(&mut buf) {
140                Ok(Event::Start(ref e) | Event::Empty(ref e))
141                    if e.name().into_inner() == b"dataBar" =>
142                {
143                    let mut obj = DataBar::default();
144                    obj.set_attributes(&mut reader, e);
145                    return obj;
146                }
147                Ok(Event::Eof) => panic!("dataBar element not found"),
148                _ => (),
149            }
150            buf.clear();
151        }
152    }
153
154    #[test]
155    fn read_child_elements_with_end_tags() {
156        // Writers such as openpyxl emit <cfvo .../> children as
157        // <cfvo ...></cfvo> (Start + End events instead of Empty).
158        let obj = read_data_bar(
159            r#"<dataBar showValue="1" minLength="10" maxLength="90"><cfvo type="num" val="0"></cfvo><cfvo type="num" val="1400"></cfvo><color rgb="FF1E2761"></color></dataBar>"#,
160        );
161        assert_eq!(obj.cfvo_collection().len(), 2);
162        assert_eq!(obj.color_collection().len(), 1);
163        assert_eq!(obj.color_collection()[0].argb_str(), "FF1E2761");
164    }
165
166    #[test]
167    fn read_child_elements_self_closing() {
168        let obj = read_data_bar(
169            r#"<dataBar><cfvo type="min"/><cfvo type="max"/><color rgb="FF638EC6"/></dataBar>"#,
170        );
171        assert_eq!(obj.cfvo_collection().len(), 2);
172        assert_eq!(obj.color_collection().len(), 1);
173        assert_eq!(obj.color_collection()[0].argb_str(), "FF638EC6");
174    }
175}