From db5abec89457d14c9c4ba1744c9915854feafa7c Mon Sep 17 00:00:00 2001 From: Kostas Dizas <254960+kostasdizas@users.noreply.github.com> Date: Fri, 19 Oct 2018 20:47:35 +0100 Subject: [PATCH 1/4] Worksheet dimension should include lowest props --- source/worksheet/worksheet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/worksheet/worksheet.cpp b/source/worksheet/worksheet.cpp index 33386f84..35888975 100644 --- a/source/worksheet/worksheet.cpp +++ b/source/worksheet/worksheet.cpp @@ -574,7 +574,7 @@ column_t worksheet::highest_column_or_props() const range_reference worksheet::calculate_dimension() const { - return range_reference(lowest_column(), lowest_row(), + return range_reference(lowest_column(), lowest_row_or_props(), highest_column(), highest_row_or_props()); } From 3ab49c8af67509c7544b9132c2c9cecac9445a29 Mon Sep 17 00:00:00 2001 From: Kostas Dizas <254960+kostasdizas@users.noreply.github.com> Date: Fri, 19 Oct 2018 20:48:54 +0100 Subject: [PATCH 2/4] Importing row spans in the row_properties object --- include/xlnt/worksheet/row_properties.hpp | 10 +++++++++- source/detail/serialization/xlsx_consumer.cpp | 12 ++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/include/xlnt/worksheet/row_properties.hpp b/include/xlnt/worksheet/row_properties.hpp index d78c4313..a2e92e25 100644 --- a/include/xlnt/worksheet/row_properties.hpp +++ b/include/xlnt/worksheet/row_properties.hpp @@ -63,6 +63,13 @@ public: /// The index to the style used by all cells in this row /// optional style; + + /// + /// The row column span, used as part of the row block optimisation. + /// This used for loading this attribute from existing excel files mainly for inspecting + /// and not used when saving, it is calculated in the xlsx_producer. + /// + optional spans; }; inline bool operator==(const row_properties &lhs, const row_properties &rhs) @@ -72,7 +79,8 @@ inline bool operator==(const row_properties &lhs, const row_properties &rhs) && lhs.custom_height == rhs.custom_height && lhs.hidden == rhs.hidden && lhs.custom_format == rhs.custom_format - && lhs.style == rhs.style; + && lhs.style == rhs.style + && lhs.spans == rhs.spans; } } // namespace xlnt diff --git a/source/detail/serialization/xlsx_consumer.cpp b/source/detail/serialization/xlsx_consumer.cpp index 3ac9eb0b..33841f84 100644 --- a/source/detail/serialization/xlsx_consumer.cpp +++ b/source/detail/serialization/xlsx_consumer.cpp @@ -221,9 +221,13 @@ cell xlsx_consumer::read_cell() row_properties.dy_descent = parser().attribute(qn("x14ac", "dyDescent")); } + if (parser().attribute_present("spans")) { + row_properties.spans = parser().attribute("spans"); + } + skip_attributes({"customFormat", "s", "customFont", "outlineLevel", "collapsed", "thickTop", "thickBot", - "ph", "spans"}); + "ph"}); } if (!in_element(qn("spreadsheetml", "row"))) @@ -713,9 +717,13 @@ void xlsx_consumer::read_worksheet_sheetdata() row_properties.custom_format.set(parser().attribute("customFormat")); } + if (parser().attribute_present("spans")) { + row_properties.spans = parser().attribute("spans"); + } + skip_attributes({"customFont", "outlineLevel", "collapsed", "thickTop", "thickBot", - "ph", "spans"}); + "ph"}); while (in_element(qn("spreadsheetml", "row"))) { From dde45fd17f742f10e507a8eab2f542fc7d84059a Mon Sep 17 00:00:00 2001 From: Kostas Dizas <254960+kostasdizas@users.noreply.github.com> Date: Fri, 19 Oct 2018 23:19:23 +0100 Subject: [PATCH 3/4] Fixed block calculation in xlsx_producer --- source/detail/serialization/xlsx_producer.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/source/detail/serialization/xlsx_producer.cpp b/source/detail/serialization/xlsx_producer.cpp index f8172c16..202a1d0d 100644 --- a/source/detail/serialization/xlsx_producer.cpp +++ b/source/detail/serialization/xlsx_producer.cpp @@ -2439,6 +2439,10 @@ void xlsx_producer::write_worksheet(const relationship &rel) // See note for CT_Row, span attribute about block optimization if (first_row_in_block) { + // reset block column range + first_block_column = constants::max_column(); + last_block_column = constants::min_column(); + first_check_row = row; // round up to the next multiple of 16 last_check_row = ((row / 16) + 1) * 16; @@ -2448,8 +2452,8 @@ void xlsx_producer::write_worksheet(const relationship &rel) { for (auto column = dimension.top_left().column(); column <= dimension.bottom_right().column(); ++column) { - if (!ws.has_cell(cell_reference(column, row))) continue; - auto cell = ws.cell(cell_reference(column, row)); + if (!ws.has_cell(cell_reference(column, check_row))) continue; + auto cell = ws.cell(cell_reference(column, check_row)); if (cell.garbage_collectible()) continue; first_block_column = std::min(first_block_column, cell.column()); From 5decf9cf895023f299fb398e289860a671283149 Mon Sep 17 00:00:00 2001 From: Kostas Dizas <254960+kostasdizas@users.noreply.github.com> Date: Fri, 19 Oct 2018 23:20:45 +0100 Subject: [PATCH 4/4] Test to confirm that the row spans are calculated correctly --- .../Issue353_first_row_empty_w_properties.xlsx | Bin 0 -> 10062 bytes tests/workbook/workbook_test_suite.cpp | 14 ++++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/data/Issue353_first_row_empty_w_properties.xlsx diff --git a/tests/data/Issue353_first_row_empty_w_properties.xlsx b/tests/data/Issue353_first_row_empty_w_properties.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..65cdbe872ceb1d122f3ba3cfe537442ff7e6313d GIT binary patch literal 10062 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 BtUmw% literal 0 HcmV?d00001 diff --git a/tests/workbook/workbook_test_suite.cpp b/tests/workbook/workbook_test_suite.cpp index 9f155087..f883e359 100644 --- a/tests/workbook/workbook_test_suite.cpp +++ b/tests/workbook/workbook_test_suite.cpp @@ -67,6 +67,7 @@ public: register_test(test_id_gen); register_test(test_load_file); register_test(test_Issue279); + register_test(test_Issue353); } void test_active_sheet() @@ -495,5 +496,18 @@ public: //save a copy file wb.save("temp.xlsx"); } + + void test_Issue353() + { + xlnt::workbook wb1; + wb1.load(path_helper::test_file("Issue353_first_row_empty_w_properties.xlsx")); + wb1.save("temp_issue353.xlsx"); + + xlnt::workbook wb2; + wb2.load("temp_issue353.xlsx"); + auto ws = wb2.active_sheet(); + xlnt_assert_equals(ws.row_properties(1).spans.get(), "1:8"); + xlnt_assert_equals(ws.row_properties(17).spans.get(), "2:7"); + } }; static workbook_test_suite x; \ No newline at end of file