FIX: Export views and showGridLines properly (#72)

This commit is contained in:
Nicolás Hatcher Andrés
2024-05-28 21:52:10 +02:00
committed by GitHub
parent b37397acb8
commit c3a9b006d2
4 changed files with 98 additions and 17 deletions

View File

@@ -68,6 +68,10 @@ pub fn save_to_xlsx(model: &Model, file_name: &str) -> Result<(), XlsxError> {
pub fn save_xlsx_to_writer<W: Write + Seek>(model: &Model, writer: W) -> Result<W, XlsxError> { pub fn save_xlsx_to_writer<W: Write + Seek>(model: &Model, writer: W) -> Result<W, XlsxError> {
let workbook = &model.workbook; let workbook = &model.workbook;
let selected_sheet = match workbook.views.get(&0) {
Some(view) => view.sheet,
_ => 0,
};
let mut zip = zip::ZipWriter::new(writer); let mut zip = zip::ZipWriter::new(writer);
let options = zip::write::FileOptions::default(); let options = zip::write::FileOptions::default();
@@ -94,7 +98,7 @@ pub fn save_xlsx_to_writer<W: Write + Seek>(model: &Model, writer: W) -> Result<
zip.start_file("xl/styles.xml", options)?; zip.start_file("xl/styles.xml", options)?;
zip.write_all(styles::get_styles_xml(workbook).as_bytes())?; zip.write_all(styles::get_styles_xml(workbook).as_bytes())?;
zip.start_file("xl/workbook.xml", options)?; zip.start_file("xl/workbook.xml", options)?;
zip.write_all(workbook::get_workbook_xml(workbook).as_bytes())?; zip.write_all(workbook::get_workbook_xml(workbook, selected_sheet).as_bytes())?;
zip.add_directory("xl/_rels", options)?; zip.add_directory("xl/_rels", options)?;
zip.start_file("xl/_rels/workbook.xml.rels", options)?; zip.start_file("xl/_rels/workbook.xml.rels", options)?;
@@ -114,11 +118,13 @@ pub fn save_xlsx_to_writer<W: Write + Seek>(model: &Model, writer: W) -> Result<
let min_row = dimension.min_row; let min_row = dimension.min_row;
let max_row = dimension.max_row; let max_row = dimension.max_row;
let sheet_dimension_str = &format!("{column_min_str}{min_row}:{column_max_str}{max_row}"); let sheet_dimension_str = &format!("{column_min_str}{min_row}:{column_max_str}{max_row}");
let is_sheet_selected = selected_sheet as usize == sheet_index;
zip.write_all( zip.write_all(
worksheets::get_worksheet_xml( worksheets::get_worksheet_xml(
worksheet, worksheet,
&model.parsed_formulas[sheet_index], &model.parsed_formulas[sheet_index],
sheet_dimension_str, sheet_dimension_str,
is_sheet_selected,
) )
.as_bytes(), .as_bytes(),
)?; )?;

View File

@@ -34,7 +34,7 @@ use ironcalc_base::types::{SheetState, Workbook};
use super::escape::escape_xml; use super::escape::escape_xml;
use super::xml_constants::XML_DECLARATION; use super::xml_constants::XML_DECLARATION;
pub(crate) fn get_workbook_xml(workbook: &Workbook) -> String { pub(crate) fn get_workbook_xml(workbook: &Workbook, selected_sheet: u32) -> String {
// sheets // sheets
// <sheet name="Sheet1" sheetId="1" r:id="rId1"/> // <sheet name="Sheet1" sheetId="1" r:id="rId1"/>
let mut sheets_str: Vec<String> = vec![]; let mut sheets_str: Vec<String> = vec![];
@@ -80,6 +80,9 @@ pub(crate) fn get_workbook_xml(workbook: &Workbook) -> String {
let defined_names = defined_names_str.join(""); let defined_names = defined_names_str.join("");
format!("{XML_DECLARATION}\n\ format!("{XML_DECLARATION}\n\
<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">\ <workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">\
<bookViews>
<workbookView activeTab=\"{selected_sheet}\"/>\
</bookViews>
<sheets>\ <sheets>\
{sheets}\ {sheets}\
</sheets>\ </sheets>\

View File

@@ -55,6 +55,7 @@ pub(crate) fn get_worksheet_xml(
worksheet: &Worksheet, worksheet: &Worksheet,
parsed_formulas: &[Node], parsed_formulas: &[Node],
dimension: &str, dimension: &str,
is_sheet_selected: bool,
) -> String { ) -> String {
let mut sheet_data_str: Vec<String> = vec![]; let mut sheet_data_str: Vec<String> = vec![];
let mut cols_str: Vec<String> = vec![]; let mut cols_str: Vec<String> = vec![];
@@ -247,6 +248,38 @@ pub(crate) fn get_worksheet_xml(
format!("<cols>{cols}</cols>") format!("<cols>{cols}</cols>")
}; };
let tab_selected = if is_sheet_selected {
" tabSelected=\"1\""
} else {
""
};
let show_grid_lines = if !worksheet.show_grid_lines {
" showGridLines=\"0\""
} else {
""
};
let mut active_cell = "A1".to_string();
let mut sqref = "A1".to_string();
let views = &worksheet.views;
if let Some(view) = views.get(&0) {
let range = view.range;
let row = view.row;
let column = view.column;
let column_name = number_to_column(column).unwrap_or("A".to_string());
active_cell = format!("{column_name}{row}");
let column_start = number_to_column(range[1]).unwrap_or("A".to_string());
let column_end = number_to_column(range[3]).unwrap_or("A".to_string());
if range[0] == range[2] && range[1] == range[3] {
sqref = format!("{column_start}{}", range[0]);
} else {
sqref = format!("{}{}:{}{}", column_start, range[0], column_end, range[2]);
}
}
format!( format!(
"{XML_DECLARATION} "{XML_DECLARATION}
<worksheet \ <worksheet \
@@ -254,8 +287,8 @@ xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" \
xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">\ xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">\
<dimension ref=\"{dimension}\"/>\ <dimension ref=\"{dimension}\"/>\
<sheetViews>\ <sheetViews>\
<sheetView workbookViewId=\"0\">\ <sheetView workbookViewId=\"0\"{show_grid_lines}{tab_selected}>\
<selection activeCell=\"A1\" sqref=\"A1\"/>\ <selection activeCell=\"{active_cell}\" sqref=\"{sqref}\"/>\
</sheetView>\ </sheetView>\
</sheetViews>\ </sheetViews>\
{cols}\ {cols}\

View File

@@ -51,22 +51,47 @@ fn test_example() {
#[test] #[test]
fn no_grid() { fn no_grid() {
let model = load_from_xlsx("tests/NoGrid.xlsx", "en", "UTC").unwrap(); let model = load_from_xlsx("tests/NoGrid.xlsx", "en", "UTC").unwrap();
let workbook = model.workbook; {
let ws = &workbook.worksheets; let workbook = &model.workbook;
let ws = &workbook.worksheets;
// NoGrid does not show grid lines // NoGrid does not show grid lines
let no_grid_sheet = &ws[0]; let no_grid_sheet = &ws[0];
assert_eq!(no_grid_sheet.name, "NoGrid".to_string()); assert_eq!(no_grid_sheet.name, "NoGrid".to_string());
assert!(!no_grid_sheet.show_grid_lines); assert!(!no_grid_sheet.show_grid_lines);
let sheet2 = &ws[1]; let sheet2 = &ws[1];
assert_eq!(no_grid_sheet.name, "NoGrid".to_string()); assert_eq!(no_grid_sheet.name, "NoGrid".to_string());
assert!(sheet2.show_grid_lines); assert!(sheet2.show_grid_lines);
let no_grid_no_headers_sheet = &ws[2]; let no_grid_no_headers_sheet = &ws[2];
assert_eq!(no_grid_sheet.name, "NoGrid".to_string()); assert_eq!(no_grid_sheet.name, "NoGrid".to_string());
// There is also no headers // There is also no headers
assert!(!no_grid_no_headers_sheet.show_grid_lines); assert!(!no_grid_no_headers_sheet.show_grid_lines);
}
{
// save it and check again
let temp_file_name = "temp_file_no_grid.xlsx";
save_to_xlsx(&model, temp_file_name).unwrap();
let model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
let workbook = &model.workbook;
let ws = &workbook.worksheets;
// NoGrid does not show grid lines
let no_grid_sheet = &ws[0];
assert_eq!(no_grid_sheet.name, "NoGrid".to_string());
assert!(!no_grid_sheet.show_grid_lines);
let sheet2 = &ws[1];
assert_eq!(no_grid_sheet.name, "NoGrid".to_string());
assert!(sheet2.show_grid_lines);
let no_grid_no_headers_sheet = &ws[2];
assert_eq!(no_grid_sheet.name, "NoGrid".to_string());
// There is also no headers
assert!(!no_grid_no_headers_sheet.show_grid_lines);
fs::remove_file(temp_file_name).unwrap();
}
} }
#[test] #[test]
@@ -82,6 +107,20 @@ fn test_save_to_xlsx() {
assert_eq!(metadata.application, "IronCalc Sheets"); assert_eq!(metadata.application, "IronCalc Sheets");
// FIXME: This will need to be updated once we fix versioning // FIXME: This will need to be updated once we fix versioning
assert_eq!(metadata.app_version, "10.0000"); assert_eq!(metadata.app_version, "10.0000");
let workbook = model.workbook;
let ws = &workbook.worksheets;
assert_eq!(workbook.views[&0].sheet, 7);
// Test selection:
// First sheet (Sheet1)
// E13 and E13:N20
assert_eq!(ws[0].frozen_rows, 0);
assert_eq!(ws[0].frozen_columns, 0);
assert_eq!(ws[0].views[&0].row, 13);
assert_eq!(ws[0].views[&0].column, 5);
assert_eq!(ws[0].views[&0].range, [13, 5, 20, 14]);
// TODO: can we show it is the 'same' model? // TODO: can we show it is the 'same' model?
fs::remove_file(temp_file_name).unwrap(); fs::remove_file(temp_file_name).unwrap();
} }