1use std::cmp;
2use std::io::BufWriter;
3use std::io::Error;
4use std::io::Write;
5use std::path::Path;
6
7use std::fs::File;
8
9use edit_xlsx::Read;
10use edit_xlsx::WorkSheet;
11use edit_xlsx::WorkSheetCol;
12use edit_xlsx::{FormatColor, Workbook, WorkbookResult};
13use std::ops::RangeInclusive;
14
15
16use std::io::{ErrorKind};
17
18pub fn error_text(text: &str) -> Error {
19 Error::new(ErrorKind::Other, text)
20}
21
22pub fn tab_header(widths: &Vec<f64>) -> String {
23 let mut out = "[cols=\"".to_owned();
24
25 for w in widths.iter().enumerate() {
26 let w100 = w.1 * 100.0;
27 let w100 = w100.round();
28 let w100 = w100 as u32;
29 out += &format!("{}", w100);
30 if w.0 < widths.len() - 1 {
31 out += ", ";
32 };
33 }
34 out + "\"]\r"
35}
36#[derive(Default)]
37pub struct Xlsx2AdocTestResults {
38 v1: u8,
40 pub v2: u8,
41}
42
43pub(crate) fn to_col(col: &str) -> u32 {
44 let mut col = col.as_bytes();
45 let mut num = 0;
46 while !col.is_empty() {
47 if col[0] > 64 && col[0] < 91 {
48 num *= 26;
49 num += (col[0] - 64) as u32;
50 }
51 col = &col[1..];
52 }
53 num
54}
55
56fn decode_col_range(column_name: &str, length: usize) -> RangeInclusive<usize> {
57 let mut nn = column_name.split(':');
58 let nl = nn.next();
59 let nl = nl.unwrap();
60 let cl = to_col(nl) as usize;
61 let nh = nn.next();
62 let nh = nh.unwrap();
63 let ch = cmp::min(to_col(nh) as usize, length);
64 cl - 1..=ch - 1
65}
66
67fn find_col_width(sheet: &WorkSheet) -> Result<Vec<f64>, Error> {
68 let mut widths = Vec::<f64>::new();
69 let default_col_width = sheet.get_default_column().unwrap_or(1.0);
70
71 for _ in 0..sheet.max_column() {
72 widths.push(default_col_width);
73 }
74
75 let formatted_col_result = sheet.get_columns_with_format((1, 1, 1, 16384));
76 let formatted_col = match formatted_col_result {
77 Ok(f) => f,
78 Err(e) => return Err(error_text(&format!("{:?}", e))),
79 };
80
81 for w in formatted_col.iter() {
82 let column_name = w.0;
83 let a = w.1;
84 let columns_specs = a.0;
85 let column_width = columns_specs.width;
86 match column_width {
87 Some(width) => {
88 let col_range = decode_col_range(column_name, widths.len());
89 for c in col_range {
90 widths[c] = width;
91 }
92 }
93 None => {},
94 };
95}
96 Ok(widths)
97}
98
99pub fn xlsx_convert(
100 in_file_name: &Path,
101 out_file_name: &Path,
102) -> Result<Xlsx2AdocTestResults, Error> {
103 let workbook = Workbook::from_path(in_file_name);
104 let mut workbook = workbook.unwrap();
105 workbook.finish();
106
107 let reading_sheet = workbook.get_worksheet(1);
108 let sheet = reading_sheet.unwrap();
109 let default_row_hight = sheet.get_default_row();
110
111 println!(
112 "Rows {} -> ? ( {} )",
113 sheet.max_row(),
114 default_row_hight
116 );
117
118 let mut hights = Vec::<f64>::new();
119 for _ in 0..sheet.max_row() {
120 hights.push(default_row_hight);
121 }
122
123 let widths = find_col_width(sheet)?;
124 let bounds = "|===\r";
125 let line = tab_header(&widths);
126
127 let mut output_file = File::create(out_file_name)?; let mut writer = BufWriter::new(&mut output_file);
129
130 writer.write(line.as_bytes())?;
131 writer.write(bounds.as_bytes())?;
132
133 for row in 0..sheet.max_row() {
140 println!("Row {} ({})", row, hights[row as usize]);
141 for col in 0..sheet.max_column() {
142 if col < sheet.max_column() {
143 writer.write("|".as_bytes())?;
144 }
145
146 let cell_content = sheet.read_cell((row + 1, col + 1)).unwrap_or_default();
147 let format = cell_content.format;
148 let mut text_color = FormatColor::Default;
149 let mut bg_color = FormatColor::Default;
150 let mut bg_bg_color = FormatColor::Default;
151 if format.is_some() {
152 let format = format.unwrap();
153 text_color = format.get_color().clone();
154 let ff = format.get_background().clone();
155 bg_color = ff.fg_color.clone();
156 bg_bg_color = ff.bg_color.clone();
157 }
158
159 let cell_format_string = format!(
160 "Text-Color = {:?} bg = {:?} bg_bg = {:?}",
161 text_color, bg_color, bg_bg_color
162 );
163 let cell_text = cell_content.text;
164 let text = match cell_text {
165 Some(t) => t,
166 None => "-".to_owned(),
167 };
168
169 println!(
170 "{} ({}) -> {} Format: {}",
171 col,
172 widths[(col) as usize],
173 text,
174 cell_format_string
175 );
176 writer.write(text.as_bytes())?;
177 }
178
179 writer.write("\r".as_bytes())?;
180 }
181 writer.write(bounds.as_bytes())?;
182
183 let xlsx_2_adoc_test_results = Xlsx2AdocTestResults { v1: 0, v2: 0 };
184 Ok(xlsx_2_adoc_test_results)
185}
186
187const CARGO_PKG_NAME: &str = env!("CARGO_PKG_NAME");
188fn main() -> std::io::Result<()> {
189 let (in_file_name, out_file_name) = (
190 Path::new("./tests/xlsx/business-budget.xlsx"),
191 Path::new("./examples/accounting.adoc"),
192 );
193
194 println!(
195 "{} {} -> {}",
196 CARGO_PKG_NAME,
197 in_file_name.display(),
198 out_file_name.display()
199 );
200
201 xlsx_convert(&in_file_name, &out_file_name)?;
202 Ok(())
203}