From 713bd1ea12e9113c0186e86c9e169e56134ee974 Mon Sep 17 00:00:00 2001 From: Thomas Fussell Date: Tue, 3 May 2016 15:37:34 -0400 Subject: [PATCH] almost done finally. still need to figure out the interaction between styles and named styles, maybe improve naming --- .../xlnt/serialization/style_serializer.hpp | 13 ++- include/xlnt/workbook/workbook.hpp | 3 + source/cell/tests/test_cell.hpp | 81 ++++++++++--------- source/detail/workbook_impl.hpp | 4 - source/serialization/style_serializer.cpp | 74 ++++++++++++++--- .../serialization/tests/test_style_writer.hpp | 5 +- source/styles/cell_style.cpp | 33 ++++---- source/styles/common_style.cpp | 46 ++++++++++- source/styles/named_style.cpp | 17 ++++ source/styles/number_format.cpp | 2 +- source/styles/tests/test_stylesheet.hpp | 10 +-- source/workbook/workbook.cpp | 34 +++++++- 12 files changed, 238 insertions(+), 84 deletions(-) diff --git a/include/xlnt/serialization/style_serializer.hpp b/include/xlnt/serialization/style_serializer.hpp index 7e690048..988f2e47 100644 --- a/include/xlnt/serialization/style_serializer.hpp +++ b/include/xlnt/serialization/style_serializer.hpp @@ -28,6 +28,7 @@ #include #include +#include #include namespace xlnt { @@ -256,6 +257,16 @@ public: bool write_ext_list(xml_node &ext_list_node) const; + const std::vector &get_borders() const; + + const std::vector &get_fills() const; + + const std::vector &get_fonts() const; + + const std::vector &get_number_formats() const; + + const std::vector &get_colors() const; + private: void initialize_vectors(); @@ -270,7 +281,7 @@ private: std::vector fonts_; std::vector number_formats_; std::vector cell_styles_; - std::vector named_styles_; + std::unordered_map named_styles_; }; } // namespace xlnt diff --git a/include/xlnt/workbook/workbook.hpp b/include/xlnt/workbook/workbook.hpp index f7421dbc..6dc7d179 100644 --- a/include/xlnt/workbook/workbook.hpp +++ b/include/xlnt/workbook/workbook.hpp @@ -83,6 +83,8 @@ public: workbook &operator=(workbook other); workbook(workbook &&other); workbook(const workbook &other); + + ~workbook(); friend void swap(workbook &left, workbook &right); @@ -190,6 +192,7 @@ public: named_style &get_named_style(const std::string &name); const named_style &get_named_style(const std::string &name) const; named_style &create_named_style(const std::string &name); + const std::vector &get_named_styles() const; manifest &get_manifest(); const manifest &get_manifest() const; diff --git a/source/cell/tests/test_cell.hpp b/source/cell/tests/test_cell.hpp index da64bdd8..3d1ea986 100644 --- a/source/cell/tests/test_cell.hpp +++ b/source/cell/tests/test_cell.hpp @@ -358,87 +358,90 @@ public: void test_font() { + auto ws = wb.create_sheet(); + auto cell = ws.get_cell("A1"); + xlnt::font font; font.set_bold(true); - auto ws = wb.create_sheet(); - auto cell = xlnt::cell(ws, "A1"); + cell.set_font(font); + + TS_ASSERT(cell.has_style()); + TS_ASSERT(cell.get_font().apply()); TS_ASSERT_EQUALS(cell.get_font(), font); } void test_fill() { + auto ws = wb.create_sheet(); + auto cell = ws.get_cell("A1"); + xlnt::fill f; f.set_pattern_type(xlnt::fill::pattern_type::solid); f.set_foreground_color(xlnt::color(xlnt::color::type::rgb, "FF0000")); - auto ws = wb.create_sheet(); - xlnt::cell cell(ws, "A1"); + cell.set_fill(f); - TS_ASSERT(cell.get_fill() == f); + + TS_ASSERT(cell.has_style()); + TS_ASSERT(cell.get_fill().apply()); + TS_ASSERT_EQUALS(cell.get_fill(), f); } void test_border() { - xlnt::border border; auto ws = wb.create_sheet(); + auto cell = ws.get_cell("A1"); - auto cell = ws.get_cell(xlnt::cell_reference(1, 1)); + xlnt::border border; + cell.set_border(border); - TS_ASSERT(cell.get_border() == border); + TS_ASSERT(cell.has_style()); + TS_ASSERT(cell.get_border().apply()); + TS_ASSERT_EQUALS(cell.get_border(), border); } void test_number_format() { auto ws = wb.create_sheet(); - ws.get_parent().add_number_format(xlnt::number_format("dd--hh--mm")); + auto cell = ws.get_cell("A1"); + + xlnt::number_format format("dd--hh--mm"); - xlnt::cell cell(ws, "A1"); - cell.set_number_format(xlnt::number_format("dd--hh--mm")); - TS_ASSERT(cell.get_number_format().get_format_string() == "dd--hh--mm"); + cell.set_number_format(format); + + TS_ASSERT(cell.has_style()); + TS_ASSERT(cell.get_number_format().apply()); + TS_ASSERT_EQUALS(cell.get_number_format().get_format_string(), "dd--hh--mm"); } void test_alignment() { + auto ws = wb.create_sheet(); + auto cell = ws.get_cell("A1"); + xlnt::alignment align; align.set_wrap_text(true); - - auto ws = wb.create_sheet(); - xlnt::cell cell(ws, "A1"); cell.set_alignment(align); - TS_ASSERT(cell.get_alignment() == align); + TS_ASSERT(cell.has_style()); + TS_ASSERT(cell.get_alignment().apply()); + TS_ASSERT_EQUALS(cell.get_alignment(), align); } void test_protection() { + auto ws = wb.create_sheet(); + auto cell = ws.get_cell("A1"); + xlnt::protection prot; prot.set_locked(xlnt::protection::type::protected_); - - auto ws = wb.create_sheet(); - - xlnt::cell cell(ws, "A1"); + cell.set_protection(prot); - TS_ASSERT(cell.get_protection() == prot); - } - - void test_pivot_button() - { - auto ws = wb.create_sheet(); - - xlnt::cell cell(ws, "A1"); - cell.set_pivot_button(true); - TS_ASSERT(cell.pivot_button()); - } - - void test_quote_prefix() - { - auto ws = wb.create_sheet(); - - xlnt::cell cell(ws, "A1"); - cell.set_quote_prefix(true); - TS_ASSERT(cell.quote_prefix()); + TS_ASSERT(cell.has_style()); + TS_ASSERT(cell.get_protection().apply()); + TS_ASSERT_EQUALS(cell.get_protection(), prot); } }; diff --git a/source/detail/workbook_impl.hpp b/source/detail/workbook_impl.hpp index 318d707d..1d5c1ae0 100644 --- a/source/detail/workbook_impl.hpp +++ b/source/detail/workbook_impl.hpp @@ -37,7 +37,6 @@ struct workbook_impl worksheets_(other.worksheets_), relationships_(other.relationships_), root_relationships_(other.root_relationships_), - drawings_(other.drawings_), shared_strings_(other.shared_strings_), properties_(other.properties_), app_properties_(other.app_properties_), @@ -60,8 +59,6 @@ struct workbook_impl root_relationships_.clear(); std::copy(other.root_relationships_.begin(), other.root_relationships_.end(), std::back_inserter(root_relationships_)); - drawings_.clear(); - std::copy(other.drawings_.begin(), other.drawings_.end(), back_inserter(drawings_)); shared_strings_.clear(); std::copy(other.shared_strings_.begin(), other.shared_strings_.end(), std::back_inserter(shared_strings_)); properties_ = other.properties_; @@ -78,7 +75,6 @@ struct workbook_impl std::vector worksheets_; std::vector relationships_; std::vector root_relationships_; - std::vector drawings_; std::vector shared_strings_; document_properties properties_; diff --git a/source/serialization/style_serializer.cpp b/source/serialization/style_serializer.cpp index 6bbf6868..e3fa3383 100644 --- a/source/serialization/style_serializer.cpp +++ b/source/serialization/style_serializer.cpp @@ -346,13 +346,20 @@ named_style style_serializer::read_named_style(const xml_node &named_style_node, auto base_style_node = style_parent_node.get_children().at(base_style_id); auto base_style = read_cell_style(base_style_node); + //TODO shouldn't have to set apply after set_X() s.set_alignment(base_style.get_alignment()); + s.get_alignment().apply(base_style.get_alignment().apply()); s.set_border(base_style.get_border()); + s.get_border().apply(base_style.get_border().apply()); s.set_fill(base_style.get_fill()); + s.get_fill().apply(base_style.get_fill().apply()); s.set_font(base_style.get_font()); + s.get_font().apply(base_style.get_font().apply()); s.set_number_format(base_style.get_number_format()); + s.get_number_format().apply(base_style.get_number_format().apply()); s.set_protection(base_style.get_protection()); - + s.get_protection().apply(base_style.get_protection().apply()); + return s; } @@ -368,6 +375,16 @@ bool style_serializer::read_stylesheet(const xml_document &xml) read_named_styles(stylesheet_node.get_child("cellStyles"), stylesheet_node.get_child("cellStyleXfs")); read_cell_styles(stylesheet_node.get_child("cellXfs")); + for (const auto &ns : named_styles_) + { + workbook_.create_named_style(ns.second.get_name()) = ns.second; + } + + for (const auto &s : cell_styles_) + { + workbook_.add_style(s); + } + return true; } @@ -386,7 +403,24 @@ bool style_serializer::read_cell_styles(const xlnt::xml_node &cell_styles_node) { auto named_style_index = std::stoull(style_node.get_attribute("xfId")); auto named_style = named_styles_.at(named_style_index); + + style.set_named_style(named_style.get_name()); } + + cell_styles_.push_back(style); + } + + return true; +} + +bool style_serializer::read_named_styles(const xlnt::xml_node &named_styles_node, const xlnt::xml_node &cell_styles_node) +{ + for (auto named_style_node : named_styles_node.get_children()) + { + auto ns = read_named_style(named_style_node, cell_styles_node); + auto named_style_index = std::stoull(named_style_node.get_attribute("xfId")); + + named_styles_[named_style_index] = ns; } return true; @@ -1115,23 +1149,23 @@ bool style_serializer::write_named_styles(xml_node &cell_styles_node, xml_node & { styles_node.add_attribute("count", std::to_string(named_styles_.size())); - for(auto &style : named_styles_) + for(auto &key_style : named_styles_) { auto xf_node = styles_node.add_child("xf"); - write_named_style(style, xf_node); + write_named_style(key_style.second, xf_node); } cell_styles_node.add_attribute("count", std::to_string(named_styles_.size())); - for(auto &style : named_styles_) + for(auto &key_style : named_styles_) { auto cell_style_node = cell_styles_node.add_child("cellStyle"); - cell_style_node.add_attribute("name", style.get_name()); -// cell_style_node.add_attribute("xfId", std::to_string(style.get_format_id())); - cell_style_node.add_attribute("builtinId", std::to_string(style.get_builtin_id())); + cell_style_node.add_attribute("name", key_style.second.get_name()); + cell_style_node.add_attribute("xfId", std::to_string(key_style.first)); + cell_style_node.add_attribute("builtinId", std::to_string(key_style.second.get_builtin_id())); - if (style.get_hidden()) + if (key_style.second.get_hidden()) { cell_style_node.add_attribute("hidden", "1"); } @@ -1253,9 +1287,29 @@ bool style_serializer::write_number_formats(xml_node &number_formats_node) const return true; } -bool style_serializer::read_named_styles(const xlnt::xml_node &named_styles_node, const xlnt::xml_node &cell_styles_node) +const std::vector &style_serializer::get_borders() const { - return false; + return borders_; +} + +const std::vector &style_serializer::get_fills() const +{ + return fills_; +} + +const std::vector &style_serializer::get_fonts() const +{ + return fonts_; +} + +const std::vector &style_serializer::get_number_formats() const +{ + return number_formats_; +} + +const std::vector &style_serializer::get_colors() const +{ + return colors_; } } // namespace xlnt diff --git a/source/serialization/tests/test_style_writer.hpp b/source/serialization/tests/test_style_writer.hpp index fdece5ad..72b7519f 100644 --- a/source/serialization/tests/test_style_writer.hpp +++ b/source/serialization/tests/test_style_writer.hpp @@ -11,10 +11,11 @@ public: void test_write_number_formats() { xlnt::workbook wb; - wb.add_number_format(xlnt::number_format("YYYY")); + wb.get_active_sheet().get_cell("A1").set_number_format(xlnt::number_format("YYYY")); xlnt::style_serializer writer(wb); xlnt::xml_document observed; - writer.write_number_formats(observed.add_child("numFmts")); + auto num_fmts_node = observed.add_child("numFmts"); + writer.write_number_formats(num_fmts_node); std::string expected = " " " " diff --git a/source/styles/cell_style.cpp b/source/styles/cell_style.cpp index 083bfd8b..a42646e0 100644 --- a/source/styles/cell_style.cpp +++ b/source/styles/cell_style.cpp @@ -56,27 +56,24 @@ cell_style &cell_style::operator=(const cell_style &other) std::string cell_style::to_hash_string() const { - std::string hash_string("style"); + auto hash_string = common_style::to_hash_string(); + hash_string.append(":cell_style:"); - hash_string.append(std::to_string(alignment_.apply())); - hash_string.append(alignment_.apply() ? std::to_string(alignment_.hash()) : " "); - - hash_string.append(std::to_string(border_.apply())); - hash_string.append(border_.apply() ? std::to_string(border_.hash()) : " "); - - hash_string.append(std::to_string(font_.apply())); - hash_string.append(font_.apply() ? std::to_string(font_.hash()) : " "); - - hash_string.append(std::to_string(fill_.apply())); - hash_string.append(fill_.apply() ? std::to_string(fill_.hash()) : " "); - - hash_string.append(std::to_string(number_format_.apply())); - hash_string.append(number_format_.apply() ? std::to_string(number_format_.hash()) : " "); - - hash_string.append(std::to_string(protection_.apply())); - hash_string.append(protection_.apply() ? std::to_string(protection_.hash()) : " "); + if (!named_style_name_.empty()) + { + hash_string.append(named_style_name_); + } + else + { + hash_string.append(":"); + } return hash_string; } +void cell_style::set_named_style(const std::string &style_name) +{ + named_style_name_ = style_name; +} + } // namespace xlnt diff --git a/source/styles/common_style.cpp b/source/styles/common_style.cpp index 98cf423f..c738b145 100644 --- a/source/styles/common_style.cpp +++ b/source/styles/common_style.cpp @@ -30,9 +30,27 @@ common_style::common_style() } common_style::common_style(const common_style &other) + : alignment_(other.alignment_), + border_(other.border_), + fill_(other.fill_), + font_(other.font_), + number_format_(other.number_format_), + protection_(other.protection_) { } +common_style &common_style::operator=(const xlnt::common_style &other) +{ + alignment_ = other.alignment_; + border_ = other.border_; + fill_ = other.fill_; + font_ = other.font_; + number_format_ = other.number_format_; + protection_ = other.protection_; + + return *this; +} + alignment &common_style::get_alignment() { return alignment_; @@ -46,6 +64,7 @@ const alignment &common_style::get_alignment() const void common_style::set_alignment(const xlnt::alignment &new_alignment) { alignment_ = new_alignment; + alignment_.apply(true); } number_format &common_style::get_number_format() @@ -61,6 +80,7 @@ const number_format &common_style::get_number_format() const void common_style::set_number_format(const xlnt::number_format &new_number_format) { number_format_ = new_number_format; + number_format_.apply(true); } border &common_style::get_border() @@ -76,6 +96,7 @@ const border &common_style::get_border() const void common_style::set_border(const xlnt::border &new_border) { border_ = new_border; + border_.apply(true); } fill &common_style::get_fill() @@ -91,6 +112,7 @@ const fill &common_style::get_fill() const void common_style::set_fill(const xlnt::fill &new_fill) { fill_ = new_fill; + fill_.apply(true); } font &common_style::get_font() @@ -106,6 +128,7 @@ const font &common_style::get_font() const void common_style::set_font(const xlnt::font &new_font) { font_ = new_font; + font_.apply(true); } protection &common_style::get_protection() @@ -121,11 +144,32 @@ const protection &common_style::get_protection() const void common_style::set_protection(const xlnt::protection &new_protection) { protection_ = new_protection; + protection_.apply(true); } std::string common_style::to_hash_string() const { - return "common_style"; + std::string hash_string("common_style:"); + + hash_string.append(std::to_string(alignment_.apply())); + hash_string.append(alignment_.apply() ? std::to_string(alignment_.hash()) : ":"); + + hash_string.append(std::to_string(border_.apply())); + hash_string.append(border_.apply() ? std::to_string(border_.hash()) : ":"); + + hash_string.append(std::to_string(font_.apply())); + hash_string.append(font_.apply() ? std::to_string(font_.hash()) : ":"); + + hash_string.append(std::to_string(fill_.apply())); + hash_string.append(fill_.apply() ? std::to_string(fill_.hash()) : ":"); + + hash_string.append(std::to_string(number_format_.apply())); + hash_string.append(number_format_.apply() ? std::to_string(number_format_.hash()) : ":"); + + hash_string.append(std::to_string(protection_.apply())); + hash_string.append(protection_.apply() ? std::to_string(protection_.hash()) : ":"); + + return hash_string; } } // namespace xlnt diff --git a/source/styles/named_style.cpp b/source/styles/named_style.cpp index 3e599651..e10d10ef 100644 --- a/source/styles/named_style.cpp +++ b/source/styles/named_style.cpp @@ -26,13 +26,30 @@ namespace xlnt { named_style::named_style() + : hidden_(false), + builtin_id_(0) { } named_style::named_style(const named_style &other) + : common_style(other), + name_(other.name_), + hidden_(other.hidden_), + builtin_id_(other.builtin_id_) { } +named_style &named_style::operator=(const named_style &other) +{ + common_style::operator=(other); + + name_ = other.name_; + hidden_ = other.hidden_; + builtin_id_ = other.builtin_id_; + + return *this; +} + bool named_style::get_hidden() const { return hidden_; diff --git a/source/styles/number_format.cpp b/source/styles/number_format.cpp index 525d595d..1f1be61f 100644 --- a/source/styles/number_format.cpp +++ b/source/styles/number_format.cpp @@ -1095,7 +1095,7 @@ std::string number_format::to_hash_string() const { std::string hash_string("number_format"); - hash_string.append(std::to_string(id_)); +// hash_string.append(std::to_string(id_)); hash_string.append(format_string_); return hash_string; diff --git a/source/styles/tests/test_stylesheet.hpp b/source/styles/tests/test_stylesheet.hpp index 981b2496..de95d9db 100644 --- a/source/styles/tests/test_stylesheet.hpp +++ b/source/styles/tests/test_stylesheet.hpp @@ -57,7 +57,7 @@ public: xlnt::workbook wb; xlnt::style_serializer s(wb); TS_ASSERT(s.read_stylesheet(doc)); - TS_ASSERT_EQUALS(wb.get_number_formats().size(), 1); + TS_ASSERT_EQUALS(s.get_number_formats().size(), 1); } void test_from_complex() @@ -68,10 +68,10 @@ public: xlnt::workbook wb; xlnt::style_serializer s(wb); TS_ASSERT(s.read_stylesheet(doc)); - TS_ASSERT_EQUALS(wb.get_borders().size(), 7); - TS_ASSERT_EQUALS(wb.get_fills().size(), 6); - TS_ASSERT_EQUALS(wb.get_fonts().size(), 8); - TS_ASSERT_EQUALS(wb.get_number_formats().size(), 1); + TS_ASSERT_EQUALS(s.get_borders().size(), 7); + TS_ASSERT_EQUALS(s.get_fills().size(), 6); + TS_ASSERT_EQUALS(s.get_fonts().size(), 8); + TS_ASSERT_EQUALS(s.get_number_formats().size(), 1); } void test_merge_named_styles() diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp index 14872e2e..87b28be4 100644 --- a/source/workbook/workbook.cpp +++ b/source/workbook/workbook.cpp @@ -27,7 +27,6 @@ #include #include -#include #include #include #include @@ -86,6 +85,8 @@ workbook::workbook() : d_(new detail::workbook_impl()) d_->manifest_.add_override_type("/xl/sharedStrings.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"); d_->manifest_.add_override_type("/docProps/core.xml", "application/vnd.openxmlformats-package.core-properties+xml"); d_->manifest_.add_override_type("/docProps/app.xml", "application/vnd.openxmlformats-officedocument.extended-properties+xml"); + + add_style(cell_style()); } workbook::workbook(encoding e) : workbook() @@ -454,7 +455,6 @@ void workbook::clear() d_->worksheets_.clear(); d_->relationships_.clear(); d_->active_sheet_index_ = 0; - d_->drawings_.clear(); d_->properties_ = document_properties(); } @@ -547,6 +547,15 @@ workbook::workbook(const workbook &other) : workbook() } } +workbook::~workbook() +{ +} + +const std::vector &workbook::get_named_styles() const +{ + return d_->named_styles_; +} + bool workbook::get_data_only() const { return d_->data_only_; @@ -598,8 +607,17 @@ std::vector workbook::get_named_ranges() const std::size_t workbook::add_style(const cell_style &style) { + for (std::size_t i = 0; i < d_->cell_styles_.size(); i++) + { + if (d_->cell_styles_[i] == style) + { + return i; + } + } + d_->cell_styles_.push_back(style); - return d_->cell_styles_.size(); + + return d_->cell_styles_.size() - 1; } cell_style &workbook::get_style(std::size_t style_index) @@ -680,4 +698,14 @@ const std::vector &workbook::get_thumbnail() const return d_->thumbnail_; } +named_style &workbook::create_named_style(const std::string &name) +{ + named_style style; + style.set_name(name); + + d_->named_styles_.push_back(style); + + return d_->named_styles_.back(); +} + } // namespace xlnt