FIX: Export views and showGridLines properly (#72)
This commit is contained in:
committed by
GitHub
parent
b37397acb8
commit
c3a9b006d2
@@ -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(),
|
||||||
)?;
|
)?;
|
||||||
|
|||||||
@@ -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>\
|
||||||
|
|||||||
@@ -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}\
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user