use std::{fmt::Debug, num::ParseFloatError, str::FromStr};
-use enum_map::enum_map;
+use enum_map::{EnumMap, enum_map};
use serde::{Deserialize, de::Visitor};
use crate::output::pivot::{
Axis2, FootnoteMarkerPosition, FootnoteMarkerType,
look::{
- self, Area, AreaStyle, Border, BorderStyle, BoxBorder, Color, HeadingRegion, HorzAlign,
- LabelPosition, Look, RowColBorder, RowParity, VertAlign,
+ self, Area, AreaStyle, Border, BoxBorder, Color, HeadingRegion, HorzAlign, LabelPosition,
+ Look, RowColBorder, RowParity, Stroke, VertAlign,
},
};
use thiserror::Error as ThisError;
Area::Data(row) => table_properties.cell_format_properties.data.style.as_area_style(row),
Area::Layers => table_properties.cell_format_properties.layers.style.as_area_style(RowParity::Even),
},
- borders: enum_map! {
- Border::Title => table_properties.border_properties.title_layer_separator,
- Border::OuterFrame(BoxBorder::Left) => table_properties.border_properties.left_outer_frame,
- Border::OuterFrame(BoxBorder::Top) => table_properties.border_properties.top_outer_frame,
- Border::OuterFrame(BoxBorder::Right) => table_properties.border_properties.right_outer_frame,
- Border::OuterFrame(BoxBorder::Bottom) => table_properties.border_properties.bottom_outer_frame,
- Border::InnerFrame(BoxBorder::Left) => table_properties.border_properties.left_inner_frame,
- Border::InnerFrame(BoxBorder::Top) => table_properties.border_properties.top_inner_frame,
- Border::InnerFrame(BoxBorder::Right) => table_properties.border_properties.right_inner_frame,
- Border::InnerFrame(BoxBorder::Bottom) => table_properties.border_properties.bottom_inner_frame,
- Border::Dimension(RowColBorder(HeadingRegion::Columns, Axis2::X)) => table_properties.border_properties.horizontal_dimension_border_columns,
- Border::Dimension(RowColBorder(HeadingRegion::Columns, Axis2::Y)) => table_properties.border_properties.vertical_category_border_columns,
- Border::Dimension(RowColBorder(HeadingRegion::Rows, Axis2::X)) => table_properties.border_properties.horizontal_dimension_border_rows,
- Border::Dimension(RowColBorder(HeadingRegion::Rows, Axis2::Y)) => table_properties.border_properties.vertical_category_border_rows,
- Border::Category(RowColBorder(HeadingRegion::Columns, Axis2::X)) => table_properties.border_properties.horizontal_category_border_columns,
- Border::Category(RowColBorder(HeadingRegion::Columns, Axis2::Y)) => table_properties.border_properties.vertical_category_border_columns,
- Border::Category(RowColBorder(HeadingRegion::Rows, Axis2::X)) => table_properties.border_properties.horizontal_category_border_rows,
- Border::Category(RowColBorder(HeadingRegion::Rows, Axis2::Y)) => table_properties.border_properties.vertical_category_border_rows,
- Border::DataLeft => table_properties.border_properties.data_area_left,
- Border::DataTop => table_properties.border_properties.data_area_top,
- },
+ borders: table_properties.border_properties.decode(),
print_all_layers: table_properties.printing_properties.print_all_layers,
paginate_layers: table_properties
.printing_properties
}
#[derive(Clone, Debug, Deserialize)]
+#[serde(default)]
struct GeneralProperties {
#[serde(rename = "@hideEmptyRows")]
hide_empty_rows: bool,
row_label_position: LabelPosition,
}
-#[derive(Clone, Deserialize, Debug)]
-#[serde(rename_all = "camelCase")]
+impl Default for GeneralProperties {
+ fn default() -> Self {
+ Self {
+ hide_empty_rows: true,
+ maximum_column_width: 120,
+ minimum_column_width: 36,
+ maximum_row_width: 72,
+ minimum_row_width: 36,
+ row_label_position: LabelPosition::Corner,
+ }
+ }
+}
+
+#[derive(Clone, Deserialize, Debug, Default)]
+#[serde(rename_all = "camelCase", default)]
struct FootnoteProperties {
#[serde(rename = "@markerPosition")]
marker_position: FootnoteMarkerPosition,
Center,
}
-#[derive(Clone, Debug, Deserialize)]
-#[serde(rename_all = "camelCase")]
+#[derive(Clone, Debug, Deserialize, Default)]
+#[serde(rename_all = "camelCase", default)]
struct BorderProperties {
- bottom_inner_frame: BorderStyle,
- bottom_outer_frame: BorderStyle,
- data_area_left: BorderStyle,
- data_area_top: BorderStyle,
- horizontal_category_border_columns: BorderStyle,
- horizontal_category_border_rows: BorderStyle,
- horizontal_dimension_border_columns: BorderStyle,
- horizontal_dimension_border_rows: BorderStyle,
- left_inner_frame: BorderStyle,
- left_outer_frame: BorderStyle,
- right_inner_frame: BorderStyle,
- right_outer_frame: BorderStyle,
- title_layer_separator: BorderStyle,
- top_inner_frame: BorderStyle,
- top_outer_frame: BorderStyle,
- vertical_category_border_columns: BorderStyle,
- vertical_category_border_rows: BorderStyle,
- vertical_dimension_border_rows: BorderStyle,
- vertical_dimension_border_columns: BorderStyle,
+ bottom_inner_frame: Option<BorderStyle>,
+ bottom_outer_frame: Option<BorderStyle>,
+ data_area_left: Option<BorderStyle>,
+ data_area_top: Option<BorderStyle>,
+ horizontal_category_border_columns: Option<BorderStyle>,
+ horizontal_category_border_rows: Option<BorderStyle>,
+ horizontal_dimension_border_columns: Option<BorderStyle>,
+ horizontal_dimension_border_rows: Option<BorderStyle>,
+ left_inner_frame: Option<BorderStyle>,
+ left_outer_frame: Option<BorderStyle>,
+ right_inner_frame: Option<BorderStyle>,
+ right_outer_frame: Option<BorderStyle>,
+ title_layer_separator: Option<BorderStyle>,
+ top_inner_frame: Option<BorderStyle>,
+ top_outer_frame: Option<BorderStyle>,
+ vertical_category_border_columns: Option<BorderStyle>,
+ vertical_category_border_rows: Option<BorderStyle>,
+ vertical_dimension_border_rows: Option<BorderStyle>,
+ vertical_dimension_border_columns: Option<BorderStyle>,
+}
+
+impl BorderProperties {
+ fn get_style(&self, border: Border) -> &Option<BorderStyle> {
+ match border {
+ Border::Title => &self.title_layer_separator,
+ Border::OuterFrame(BoxBorder::Left) => &self.left_outer_frame,
+ Border::OuterFrame(BoxBorder::Top) => &self.top_outer_frame,
+ Border::OuterFrame(BoxBorder::Right) => &self.right_outer_frame,
+ Border::OuterFrame(BoxBorder::Bottom) => &self.bottom_outer_frame,
+ Border::InnerFrame(BoxBorder::Left) => &self.left_inner_frame,
+ Border::InnerFrame(BoxBorder::Top) => &self.top_inner_frame,
+ Border::InnerFrame(BoxBorder::Right) => &self.right_inner_frame,
+ Border::InnerFrame(BoxBorder::Bottom) => &self.bottom_inner_frame,
+ Border::Dimension(RowColBorder(HeadingRegion::Columns, Axis2::X)) => {
+ &self.horizontal_dimension_border_columns
+ }
+ Border::Dimension(RowColBorder(HeadingRegion::Columns, Axis2::Y)) => {
+ &self.vertical_category_border_columns
+ }
+ Border::Dimension(RowColBorder(HeadingRegion::Rows, Axis2::X)) => {
+ &self.horizontal_dimension_border_rows
+ }
+ Border::Dimension(RowColBorder(HeadingRegion::Rows, Axis2::Y)) => {
+ &self.vertical_category_border_rows
+ }
+ Border::Category(RowColBorder(HeadingRegion::Columns, Axis2::X)) => {
+ &self.horizontal_category_border_columns
+ }
+ Border::Category(RowColBorder(HeadingRegion::Columns, Axis2::Y)) => {
+ &self.vertical_category_border_columns
+ }
+ Border::Category(RowColBorder(HeadingRegion::Rows, Axis2::X)) => {
+ &self.horizontal_category_border_rows
+ }
+ Border::Category(RowColBorder(HeadingRegion::Rows, Axis2::Y)) => {
+ &self.vertical_category_border_rows
+ }
+ Border::DataLeft => &self.data_area_left,
+ Border::DataTop => &self.data_area_top,
+ }
+ }
+
+ fn decode(&self) -> EnumMap<Border, look::BorderStyle> {
+ EnumMap::from_fn(|border: Border| {
+ let mut base = border.default_border_style();
+ if let Some(style) = self.get_style(border) {
+ if let Some(stroke) = style.stroke {
+ base.stroke = stroke;
+ }
+ if let Some(color) = style.color {
+ base.color = color;
+ }
+ }
+ base
+ })
+ }
+}
+
+#[derive(Clone, Debug, Deserialize, Default)]
+#[serde(rename_all = "camelCase", default)]
+struct BorderStyle {
+ /// The kind of line to draw.
+ #[serde(rename = "@borderStyleType")]
+ pub stroke: Option<Stroke>,
+
+ /// Line color.
+ #[serde(rename = "@color")]
+ pub color: Option<Color>,
}
#[derive(Clone, Debug, Default, Deserialize)]