From cb5a9d8802b32210ceaf15e5a33633c97fc82bf3 Mon Sep 17 00:00:00 2001 From: Thomas Fussell Date: Sat, 10 Sep 2016 10:05:06 -0400 Subject: [PATCH] continue fixing up border and fill round tripping --- include/xlnt/styles/base_format.hpp | 12 ++--- include/xlnt/styles/format.hpp | 8 ++++ include/xlnt/utils/optional.hpp | 2 +- source/detail/stylesheet.hpp | 56 +++++++++++++++++++++++ source/detail/xlsx_consumer.cpp | 53 +++++++++++++++++++-- source/detail/xlsx_producer.cpp | 17 ++++++- source/styles/format.cpp | 45 +++++++++++++++++- source/workbook/tests/test_round_trip.hpp | 10 ++-- source/workbook/workbook.cpp | 1 + 9 files changed, 186 insertions(+), 18 deletions(-) diff --git a/include/xlnt/styles/base_format.hpp b/include/xlnt/styles/base_format.hpp index 428503b5..d78769cd 100644 --- a/include/xlnt/styles/base_format.hpp +++ b/include/xlnt/styles/base_format.hpp @@ -46,15 +46,15 @@ public: bool alignment_applied() const; // Border - class border &border(); - const class border &border() const; - void border(const xlnt::border &new_border, bool applied); + virtual class border &border(); + virtual const class border &border() const; + virtual void border(const xlnt::border &new_border, bool applied); bool border_applied() const; // Fill - class fill &fill(); - const class fill &fill() const; - void fill(const xlnt::fill &new_fill, bool applied); + virtual class fill &fill(); + virtual const class fill &fill() const; + virtual void fill(const xlnt::fill &new_fill, bool applied); bool fill_applied() const; // Font diff --git a/include/xlnt/styles/format.hpp b/include/xlnt/styles/format.hpp index c575c65a..68c50884 100644 --- a/include/xlnt/styles/format.hpp +++ b/include/xlnt/styles/format.hpp @@ -54,6 +54,14 @@ public: void style(const std::string &name); void style(const xlnt::style &new_style); const class style &style() const; + + class border &border() override; + const class border &border() const override; + void border(const xlnt::border &new_border, bool applied) override; + + class fill &fill() override; + const class fill &fill() const override; + void fill(const xlnt::fill &new_fill, bool applied) override; class font &font() override; const class font &font() const override; diff --git a/include/xlnt/utils/optional.hpp b/include/xlnt/utils/optional.hpp index e84a8a76..020a86e5 100644 --- a/include/xlnt/utils/optional.hpp +++ b/include/xlnt/utils/optional.hpp @@ -9,7 +9,7 @@ template class XLNT_CLASS optional { public: - optional() : has_value_(false) + optional() : has_value_(false), value_(T()) { } diff --git a/source/detail/stylesheet.hpp b/source/detail/stylesheet.hpp index 7c96c7c5..b9bb9bc6 100644 --- a/source/detail/stylesheet.hpp +++ b/source/detail/stylesheet.hpp @@ -139,6 +139,44 @@ struct stylesheet return id; } + std::size_t add_border(const border &new_border) + { + std::size_t index = 0; + + for (const border &f : borders) + { + if (f == new_border) + { + return index; + } + + ++index; + } + + borders.push_back(new_border); + + return index; + } + + std::size_t add_fill(const fill &new_fill) + { + std::size_t index = 0; + + for (const fill &f : fills) + { + if (f == new_fill) + { + return index; + } + + ++index; + } + + fills.push_back(new_fill); + + return index; + } + std::size_t add_font(const font &new_font) { std::size_t index = 0; @@ -157,6 +195,24 @@ struct stylesheet return index; } + + void clear() + { + format_impls.clear(); + formats.clear(); + + style_impls.clear(); + styles.clear(); + + alignments.clear(); + borders.clear(); + fills.clear(); + fonts.clear(); + number_formats.clear(); + protections.clear(); + + colors.clear(); + } std::list format_impls; std::vector formats; diff --git a/source/detail/xlsx_consumer.cpp b/source/detail/xlsx_consumer.cpp index d80874c2..54864eba 100644 --- a/source/detail/xlsx_consumer.cpp +++ b/source/detail/xlsx_consumer.cpp @@ -213,8 +213,8 @@ std::string to_string(xlnt::border_side side) { case xlnt::border_side::bottom: return "bottom"; case xlnt::border_side::top: return "top"; - case xlnt::border_side::start: return "start"; - case xlnt::border_side::end: return "end"; + case xlnt::border_side::start: return "left"; + case xlnt::border_side::end: return "right"; case xlnt::border_side::horizontal: return "horizontal"; case xlnt::border_side::vertical: return "vertical"; default: @@ -669,6 +669,15 @@ void xlsx_consumer::populate_workbook() case relationship::type::worksheet: read_worksheet(document.root(), rel.get_id()); break; + case relationship::type::shared_string_table: + read_shared_string_table(document); + break; + case relationship::type::styles: + read_stylesheet(document); + break; + case relationship::type::theme: + read_theme(document); + break; default: break; } @@ -1046,7 +1055,9 @@ void xlsx_consumer::read_stylesheet(const pugi::xml_node root) for (auto xf_node : cell_style_xfs_node.children("xf")) { auto cell_style_node = *(cell_style_iter++); - auto &style = destination_.create_style(cell_style_node.attribute("Name").value()); + auto &style = destination_.create_style(cell_style_node.attribute("name").value()); + + style.builtin_id(string_to_size_t(cell_style_node.attribute("builtinId").value())); // Alignment auto alignment_node = xf_node.child("alignment"); @@ -1076,7 +1087,23 @@ void xlsx_consumer::read_stylesheet(const pugi::xml_node root) // Number Format auto number_format_applied = is_true(xf_node.attribute("applyNumberFormat").value()); auto number_format_id = xf_node.attribute("numFmtId") ? string_to_size_t(xf_node.attribute("numFmtId").value()) : 0; - auto number_format = stylesheet.number_formats.at(number_format_id); + auto number_format = number_format::general(); + bool is_custom_number_format = false; + + for (const auto &nf : stylesheet.number_formats) + { + if (nf.get_id() == number_format_id) + { + number_format = nf; + is_custom_number_format = true; + break; + } + } + if (number_format_id < 164 && !is_custom_number_format) + { + number_format = number_format::from_builtin_id(number_format_id); + } + style.number_format(number_format, number_format_applied); // Protection @@ -1119,7 +1146,23 @@ void xlsx_consumer::read_stylesheet(const pugi::xml_node root) // Number Format auto number_format_applied = is_true(xf_node.attribute("applyNumberFormat").value()); auto number_format_id = xf_node.attribute("numFmtId") ? string_to_size_t(xf_node.attribute("numFmtId").value()) : 0; - auto number_format = stylesheet.number_formats.at(number_format_id); + auto number_format = number_format::general(); + bool is_custom_number_format = false; + + for (const auto &nf : stylesheet.number_formats) + { + if (nf.get_id() == number_format_id) + { + number_format = nf; + is_custom_number_format = true; + break; + } + } + if (number_format_id < 164 && !is_custom_number_format) + { + number_format = number_format::from_builtin_id(number_format_id); + } + format.number_format(number_format, number_format_applied); // Protection diff --git a/source/detail/xlsx_producer.cpp b/source/detail/xlsx_producer.cpp index c88a0dfc..bd436097 100644 --- a/source/detail/xlsx_producer.cpp +++ b/source/detail/xlsx_producer.cpp @@ -1070,12 +1070,27 @@ void xlsx_producer::write_styles(const relationship &rel, pugi::xml_node root) xf_node.append_attribute("numFmtId").set_value(std::to_string(current_format.number_format().get_id()).c_str()); - auto font_id = std::distance(stylesheet.fonts.begin(), std::find(stylesheet.fonts.begin(), stylesheet.fonts.end(), current_format.font())); + auto font_iter = std::find(stylesheet.fonts.begin(), stylesheet.fonts.end(), current_format.font()); + if (font_iter == stylesheet.fonts.end()) + { + throw xlnt::exception("font not found"); + } + auto font_id = std::distance(stylesheet.fonts.begin(), font_iter); xf_node.append_attribute("fontId").set_value(std::to_string(font_id).c_str()); + auto fill_iter = std::find(stylesheet.fills.begin(), stylesheet.fills.end(), current_format.fill()); + if (fill_iter == stylesheet.fills.end()) + { + throw xlnt::exception("fill not found"); + } auto fill_id = std::distance(stylesheet.fills.begin(), std::find(stylesheet.fills.begin(), stylesheet.fills.end(), current_format.fill())); xf_node.append_attribute("fillId").set_value(std::to_string(fill_id).c_str()); + auto border_iter = std::find(stylesheet.borders.begin(), stylesheet.borders.end(), current_format.border()); + if (border_iter == stylesheet.borders.end()) + { + throw xlnt::exception("border not found"); + } auto border_id = std::distance(stylesheet.borders.begin(), std::find(stylesheet.borders.begin(), stylesheet.borders.end(), current_format.border())); xf_node.append_attribute("borderId").set_value(std::to_string(border_id).c_str()); diff --git a/source/styles/format.cpp b/source/styles/format.cpp index 63754a7f..1a67595a 100644 --- a/source/styles/format.cpp +++ b/source/styles/format.cpp @@ -72,6 +72,38 @@ const style &format::style() const return d_->parent->get_style(*d_->style); } +xlnt::border &format::border() +{ + return base_format::border(); +} + +const xlnt::border &format::border() const +{ + return base_format::border(); +} + +void format::border(const xlnt::border &new_border, bool applied) +{ + border_id(d_->parent->add_border(new_border)); + base_format::border(new_border, applied); +} + +xlnt::fill &format::fill() +{ + return base_format::fill(); +} + +const xlnt::fill &format::fill() const +{ + return base_format::fill(); +} + +void format::fill(const xlnt::fill &new_fill, bool applied) +{ + fill_id(d_->parent->add_fill(new_fill)); + base_format::fill(new_fill, applied); +} + xlnt::font &format::font() { return base_format::font(); @@ -88,7 +120,6 @@ void format::font(const xlnt::font &new_font, bool applied) base_format::font(new_font, applied); } - xlnt::number_format &format::number_format() { return base_format::number_format(); @@ -112,6 +143,18 @@ void format::number_format(const xlnt::number_format &new_number_format, bool ap base_format::number_format(copy, applied); } +format &format::border_id(std::size_t id) +{ + d_->border_id = id; + return *this; +} + +format &format::fill_id(std::size_t id) +{ + d_->fill_id = id; + return *this; +} + format &format::font_id(std::size_t id) { d_->font_id = id; diff --git a/source/workbook/tests/test_round_trip.hpp b/source/workbook/tests/test_round_trip.hpp index bd852214..39d3e33d 100644 --- a/source/workbook/tests/test_round_trip.hpp +++ b/source/workbook/tests/test_round_trip.hpp @@ -20,6 +20,7 @@ public: { std::vector buffer; original.save(buffer); + original.save("a.xlsx"); xlnt::zip_file original_archive; original_archive.load(buffer); @@ -29,6 +30,7 @@ public: buffer.clear(); resulting_workbook.save(buffer); + resulting_workbook.save("b.xlsx"); xlnt::zip_file resulting_archive; resulting_archive.load(buffer); @@ -57,26 +59,26 @@ public: return xml_helper::xlsx_archives_match(original_archive, resulting_archive); } - void test_round_trip_minimal_wr() + void test_round_trip_minimal_wrw() { xlnt::workbook wb = xlnt::workbook::minimal(); TS_ASSERT(round_trip_matches_wrw(wb)); } - void test_round_trip_empty_excel_wr() + void test_round_trip_empty_excel_wrw() { xlnt::workbook wb = xlnt::workbook::empty_excel(); TS_ASSERT(round_trip_matches_wrw(wb)); } - void _test_round_trip_empty_libre_office_wr() + void _test_round_trip_empty_libre_office_wrw() { TS_SKIP(""); xlnt::workbook wb = xlnt::workbook::empty_libre_office(); TS_ASSERT(round_trip_matches_wrw(wb)); } - void _test_round_trip_empty_pages_wr() + void _test_round_trip_empty_pages_wrw() { TS_SKIP(""); xlnt::workbook wb = xlnt::workbook::empty_numbers(); diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp index 70b4c0c9..96313fcb 100644 --- a/source/workbook/workbook.cpp +++ b/source/workbook/workbook.cpp @@ -766,6 +766,7 @@ worksheet workbook::operator[](std::size_t index) void workbook::clear() { *d_ = detail::workbook_impl(); + d_->stylesheet_.clear(); } bool workbook::operator==(const workbook &rhs) const