diff --git a/.gitignore b/.gitignore index 3d14ded3..2e899152 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ bin/ lib/ -build/premake/*/ +build/genie/*/ +build/cmake/build/ docs/_*/ docs/doxyxml/ *.obj diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..79db66af --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: C++ +compiler: +- clang +- gcc +script: +- mkdir build/cmake/build && cd build/cmake/build && cmake .. && make && cd ../../../bin && xlnt.test +install: ./build/install-dependencies.sh + diff --git a/build/install-dependencies.sh b/build/install-dependencies.sh new file mode 100755 index 00000000..3ce7ab92 --- /dev/null +++ b/build/install-dependencies.sh @@ -0,0 +1,3 @@ +cd .. +git submodule init +git submodule update diff --git a/include/xlnt/styles/fill.hpp b/include/xlnt/styles/fill.hpp index 54c8d17c..cfde640a 100644 --- a/include/xlnt/styles/fill.hpp +++ b/include/xlnt/styles/fill.hpp @@ -70,6 +70,7 @@ public: type get_type() const { return type_; } void set_type(type t) { type_ = t; } + std::string get_pattern_type_string() const { if(type_ != type::pattern) @@ -101,12 +102,50 @@ public: default: throw std::runtime_error("invalid type"); } } + + std::string get_gradient_type_string() const + { + if(type_ != type::gradient) + { + throw std::runtime_error("not gradient fill"); + } + + switch(gradient_type_) + { + case gradient_type::linear: return "linear"; + case gradient_type::path: return "path"; + default: throw std::runtime_error("invalid type"); + } + } + pattern_type get_pattern_type() const { return pattern_type_; } - void set_pattern_type(pattern_type t) { pattern_type_ = t; } - void set_gradient_type(gradient_type t) { gradient_type_ = t; } + + void set_pattern_type(pattern_type t) + { + type_ = type::pattern; + pattern_type_ = t; + } + + void set_gradient_type(gradient_type t) + { + type_ = type::gradient; + gradient_type_ = t; + } + + void set_start_color(const color &c) + { + start_color_ = c; + start_color_assigned_ = true; + } + + void set_end_color(const color &c) + { + end_color_ = c; + end_color_assigned_ = true; + } void set_foreground_color(const color &c) { @@ -145,6 +184,16 @@ public: return hash() == other.hash(); } + void set_rotation(double rotation) + { + rotation_ = rotation; + } + + double get_rotation() const + { + return rotation_; + } + std::size_t hash() const { auto seed = static_cast(type_); @@ -157,17 +206,28 @@ public: return seed; } + double get_gradient_left() const { return gradient_path_left_; } + double get_gradient_right() const { return gradient_path_right_; } + double get_gradient_top() const { return gradient_path_top_; } + double get_gradient_bottom() const { return gradient_path_bottom_; } + private: type type_ = type::none; pattern_type pattern_type_; gradient_type gradient_type_; - int rotation_ = 0; + double rotation_ = 0; bool foreground_color_assigned_ = false; color foreground_color_ = color::black; bool background_color_assigned_ = false; color background_color_ = color::white; + bool start_color_assigned_ = false; color start_color_ = color::white; + bool end_color_assigned_ = false; color end_color_ = color::black; + double gradient_path_left_ = 0; + double gradient_path_right_ = 0; + double gradient_path_top_ = 0; + double gradient_path_bottom_ = 0; }; } // namespace xlnt diff --git a/source/cell/cell.cpp b/source/cell/cell.cpp index 839273df..da41cbb2 100644 --- a/source/cell/cell.cpp +++ b/source/cell/cell.cpp @@ -305,21 +305,6 @@ const std::unordered_map known_locales = {0x3801, "Arabic - United Arab Emirates"}, {0x4001, "Arabic - Qatar"} }; - -std::string get_currency_symbol(const std::string &locale_string) -{ - if(locale_string.substr(1, 1) == "$") - { - return "$"; - } - else if(locale_string.substr(1, 3) == "€") - { - return "€"; - } - -// auto code_page = std::stoi(locale_string.substr(3), nullptr, 16); - throw std::runtime_error("locale specific characters aren't supported yet"); -} bool is_valid_locale(const std::string &locale_string) { diff --git a/source/reader/style_reader.cpp b/source/reader/style_reader.cpp index dd271f03..0ca43afd 100644 --- a/source/reader/style_reader.cpp +++ b/source/reader/style_reader.cpp @@ -296,6 +296,99 @@ void style_reader::read_fills(pugi::xml_node fills_node) fills_.push_back(new_fill); } } + +void read_side(pugi::xml_node side_node, side &side, bool &assigned) +{ + + if(side_node != nullptr) + { + assigned = true; + + if(side_node.attribute("style") != nullptr) + { + std::string border_style_string = side_node.attribute("style").as_string(); + + if(border_style_string == "none") + { + side.set_border_style(border_style::none); + } + else if(border_style_string == "dashdot") + { + side.set_border_style(border_style::dashdot); + } + else if(border_style_string == "dashdotdot") + { + side.set_border_style(border_style::dashdotdot); + } + else if(border_style_string == "dashed") + { + side.set_border_style(border_style::dashed); + } + else if(border_style_string == "dotted") + { + side.set_border_style(border_style::dotted); + } + else if(border_style_string == "double") + { + side.set_border_style(border_style::double_); + } + else if(border_style_string == "hair") + { + side.set_border_style(border_style::hair); + } + else if(border_style_string == "medium") + { + side.set_border_style(border_style::medium); + } + else if(border_style_string == "mediumdashdot") + { + side.set_border_style(border_style::mediumdashdot); + } + else if(border_style_string == "mediumdashdotdot") + { + side.set_border_style(border_style::mediumdashdotdot); + } + else if(border_style_string == "mediumdashed") + { + side.set_border_style(border_style::mediumdashed); + } + else if(border_style_string == "slantdashdot") + { + side.set_border_style(border_style::slantdashdot); + } + else if(border_style_string == "thick") + { + side.set_border_style(border_style::thick); + } + else if(border_style_string == "thin") + { + side.set_border_style(border_style::thin); + } + else + { + throw std::runtime_error("unknown border style"); + } + } + + auto color_node = side_node.child("color"); + + if(color_node != nullptr) + { + if(color_node.attribute("indexed") != nullptr) + { + side.set_color(side::color_type::indexed, color_node.attribute("indexed").as_int()); + } + else if(color_node.attribute("theme") != nullptr) + { + side.set_color(side::color_type::theme, color_node.attribute("theme").as_int()); + } + else + { + throw std::runtime_error("invalid color type"); + } + } + } +} void style_reader::read_borders(pugi::xml_node borders_node) { @@ -303,180 +396,22 @@ void style_reader::read_borders(pugi::xml_node borders_node) { border new_border; - if(border_node.child("left") != nullptr) + const std::vector> sides = { - new_border.left_assigned = true; - auto left_node = border_node.child("left"); - - if(left_node.attribute("style") != nullptr) - { - if(left_node.attribute("style").as_string() == std::string("thin")) - { - new_border.left.set_border_style(border_style::thin); - } - else - { - throw std::runtime_error("unknown border style"); - } - } - - auto color_node = left_node.child("color"); - - if(color_node != nullptr) - { - if(color_node.attribute("indexed") != nullptr) - { - new_border.left.set_color(side::color_type::indexed, color_node.attribute("indexed").as_int()); - } - else if(color_node.attribute("theme") != nullptr) - { - new_border.left.set_color(side::color_type::theme, color_node.attribute("theme").as_int()); - } - else - { - throw std::runtime_error("invalid color type"); - } - } - } - if(border_node.child("right") != nullptr) + {"start", new_border.start, new_border.start_assigned}, + {"end", new_border.end, new_border.end_assigned}, + {"left", new_border.left, new_border.left_assigned}, + {"right", new_border.right, new_border.right_assigned}, + {"top", new_border.top, new_border.top_assigned}, + {"bottom", new_border.bottom, new_border.bottom_assigned}, + {"diagonal", new_border.diagonal, new_border.diagonal_assigned}, + {"vertical", new_border.vertical, new_border.vertical_assigned}, + {"horizontal", new_border.horizontal, new_border.horizontal_assigned} + }; + + for(const auto &side : sides) { - new_border.right_assigned = true; - auto right_node = border_node.child("right"); - - if(right_node.attribute("style") != nullptr) - { - if(right_node.attribute("style").as_string() == std::string("thin")) - { - new_border.right.set_border_style(border_style::thin); - } - else - { - throw std::runtime_error("unknown border style"); - } - } - - auto color_node = right_node.child("color"); - - if(color_node != nullptr) - { - if(color_node.attribute("indexed") != nullptr) - { - new_border.right.set_color(side::color_type::indexed, color_node.attribute("indexed").as_int()); - } - else if(color_node.attribute("theme") != nullptr) - { - new_border.right.set_color(side::color_type::theme, color_node.attribute("theme").as_int()); - } - else - { - throw std::runtime_error("invalid color type"); - } - } - } - if(border_node.child("top") != nullptr) - { - new_border.top_assigned = true; - auto top_node = border_node.child("top"); - - if(top_node.attribute("style") != nullptr) - { - if(top_node.attribute("style").as_string() == std::string("thin")) - { - new_border.top.set_border_style(border_style::thin); - } - else - { - throw std::runtime_error("unknown border style"); - } - } - - auto color_node = top_node.child("color"); - - if(color_node != nullptr) - { - if(color_node.attribute("indexed") != nullptr) - { - new_border.top.set_color(side::color_type::indexed, color_node.attribute("indexed").as_int()); - } - else if(color_node.attribute("theme") != nullptr) - { - new_border.top.set_color(side::color_type::theme, color_node.attribute("theme").as_int()); - } - else - { - throw std::runtime_error("invalid color type"); - } - } - } - if(border_node.child("bottom") != nullptr) - { - new_border.bottom_assigned = true; - auto bottom_node = border_node.child("bottom"); - - if(bottom_node.attribute("style") != nullptr) - { - if(bottom_node.attribute("style").as_string() == std::string("thin")) - { - new_border.bottom.set_border_style(border_style::thin); - } - else - { - throw std::runtime_error("unknown border style"); - } - } - - auto color_node = bottom_node.child("color"); - - if(color_node != nullptr) - { - if(color_node.attribute("indexed") != nullptr) - { - new_border.bottom.set_color(side::color_type::indexed, color_node.attribute("indexed").as_int()); - } - else if(color_node.attribute("theme") != nullptr) - { - new_border.bottom.set_color(side::color_type::theme, color_node.attribute("theme").as_int()); - } - else - { - throw std::runtime_error("invalid color type"); - } - } - } - if(border_node.child("diagonal") != nullptr) - { - new_border.diagonal_assigned = true; - auto diagonal_node = border_node.child("diagonal"); - - if(diagonal_node.attribute("style") != nullptr) - { - if(diagonal_node.attribute("style").as_string() == std::string("thin")) - { - new_border.diagonal.set_border_style(border_style::thin); - } - else - { - throw std::runtime_error("unknown border style"); - } - } - - auto color_node = diagonal_node.child("color"); - - if(color_node != nullptr) - { - if(color_node.attribute("indexed") != nullptr) - { - new_border.diagonal.set_color(side::color_type::indexed, color_node.attribute("indexed").as_int()); - } - else if(color_node.attribute("theme") != nullptr) - { - new_border.diagonal.set_color(side::color_type::theme, color_node.attribute("theme").as_int()); - } - else - { - throw std::runtime_error("invalid color type"); - } - } + read_side(border_node.child(std::get<0>(side).c_str()), std::get<1>(side), std::get<2>(side)); } borders_.push_back(new_border); diff --git a/source/styles/style.cpp b/source/styles/style.cpp index bc35fc8a..6035e84f 100644 --- a/source/styles/style.cpp +++ b/source/styles/style.cpp @@ -39,22 +39,22 @@ style::style() : style::style(const style &other) : id_(other.id_), - alignment_(other.alignment_), alignment_apply_(other.alignment_apply_), - border_(other.border_), + alignment_(other.alignment_), border_apply_(other.border_apply_), border_id_(other.border_id_), - fill_(other.fill_), + border_(other.border_), fill_apply_(other.fill_apply_), fill_id_(other.fill_id_), - font_(other.font_), + fill_(other.fill_), font_apply_(other.font_apply_), font_id_(other.font_id_), - number_format_(other.number_format_), + font_(other.font_), number_format_apply_(other.number_format_apply_), number_format_id_(other.number_format_id_), - protection_(other.protection_), + number_format_(other.number_format_), protection_apply_(other.protection_apply_), + protection_(other.protection_), pivot_button_(other.pivot_button_), quote_prefix_(other.quote_prefix_) { diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp index b5d8b591..e3997df4 100644 --- a/source/workbook/workbook.cpp +++ b/source/workbook/workbook.cpp @@ -31,37 +31,6 @@ #include "detail/workbook_impl.hpp" #include "detail/worksheet_impl.hpp" -namespace { - -static std::string create_temporary_filename() -{ -#ifdef _WIN32 - std::array buffer; - DWORD result = GetTempPath(static_cast(buffer.size()), buffer.data()); - if(result > MAX_PATH) - { - throw std::runtime_error("buffer is too small"); - } - if(result == 0) - { - throw std::runtime_error("GetTempPath failed"); - } - std::string directory(buffer.begin(), buffer.begin() + result); - return directory + "xlnt.xlsx"; -#else - return "/tmp/xlsx.xlnt"; -#endif -} - -template -void hash_combine(std::size_t& seed, const T& v) -{ - std::hash hasher; - seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); -} - -} // namespace - namespace xlnt { namespace detail { diff --git a/source/writer/style_writer.cpp b/source/writer/style_writer.cpp index de2193b1..15e51671 100644 --- a/source/writer/style_writer.cpp +++ b/source/writer/style_writer.cpp @@ -129,6 +129,33 @@ std::string style_writer::write_table() const } } } + else if(fill_.get_type() == fill::type::solid) + { + auto solid_fill_node = fill_node.append_child("solidFill"); + solid_fill_node.append_child("color"); + } + else if(fill_.get_type() == fill::type::gradient) + { + auto gradient_fill_node = fill_node.append_child("gradientFill"); + + if(fill_.get_gradient_type_string() == "linear") + { + gradient_fill_node.append_attribute("degree").set_value(fill_.get_rotation()); + } + else if(fill_.get_gradient_type_string() == "path") + { + gradient_fill_node.append_attribute("left").set_value(fill_.get_gradient_left()); + gradient_fill_node.append_attribute("right").set_value(fill_.get_gradient_right()); + gradient_fill_node.append_attribute("top").set_value(fill_.get_gradient_top()); + gradient_fill_node.append_attribute("bottom").set_value(fill_.get_gradient_bottom()); + + auto start_node = gradient_fill_node.append_child("stop"); + start_node.append_attribute("position").set_value(0); + + auto end_node = gradient_fill_node.append_child("stop"); + end_node.append_attribute("position").set_value(1); + } + } } auto borders_node = style_sheet_node.append_child("borders"); @@ -139,176 +166,69 @@ std::string style_writer::write_table() const { auto border_node = borders_node.append_child("border"); - if(border_.left_assigned) + const std::vector> sides = { - auto left_node = border_node.append_child("left"); - - if(border_.left.is_style_assigned()) - { - auto style_attribute = left_node.append_attribute("style"); - - switch(border_.left.get_style()) - { - case border_style::none: style_attribute.set_value("none"); break; - case border_style::thin: style_attribute.set_value("thin"); break; - default: throw std::runtime_error("invalid style"); - } - } - - if(border_.left.is_color_assigned()) - { - auto color_node = left_node.append_child("color"); - - if(border_.left.get_color_type() == side::color_type::indexed) - { - color_node.append_attribute("indexed").set_value((int)border_.left.get_color()); - } - else if(border_.diagonal.get_color_type() == side::color_type::theme) - { - color_node.append_attribute("indexed").set_value((int)border_.left.get_color()); - } - else - { - throw std::runtime_error("invalid color type"); - } - } - } + {"start", border_.start, border_.start_assigned}, + {"end", border_.end, border_.end_assigned}, + {"left", border_.left, border_.left_assigned}, + {"right", border_.right, border_.right_assigned}, + {"top", border_.top, border_.top_assigned}, + {"bottom", border_.bottom, border_.bottom_assigned}, + {"diagonal", border_.diagonal, border_.diagonal_assigned}, + {"vertical", border_.vertical, border_.vertical_assigned}, + {"horizontal", border_.horizontal, border_.horizontal_assigned} + }; - if(border_.right_assigned) + for(const auto &side_tuple : sides) { - auto right_node = border_node.append_child("right"); + std::string name = std::get<0>(side_tuple); + const side &side_ = std::get<1>(side_tuple); + bool assigned = std::get<2>(side_tuple); - if(border_.right.is_style_assigned()) + if(assigned) { - auto style_attribute = right_node.append_attribute("style"); + auto side_node = border_node.append_child(name.c_str()); - switch(border_.right.get_style()) + if(side_.is_style_assigned()) { - case border_style::none: style_attribute.set_value("none"); break; - case border_style::thin: style_attribute.set_value("thin"); break; - default: throw std::runtime_error("invalid style"); + auto style_attribute = side_node.append_attribute("style"); + + switch(side_.get_style()) + { + case border_style::none: style_attribute.set_value("none"); break; + case border_style::dashdot : style_attribute.set_value("dashdot"); break; + case border_style::dashdotdot : style_attribute.set_value("dashdotdot"); break; + case border_style::dashed : style_attribute.set_value("dashed"); break; + case border_style::dotted : style_attribute.set_value("dotted"); break; + case border_style::double_ : style_attribute.set_value("double"); break; + case border_style::hair : style_attribute.set_value("hair"); break; + case border_style::medium : style_attribute.set_value("thin"); break; + case border_style::mediumdashdot: style_attribute.set_value("mediumdashdot"); break; + case border_style::mediumdashdotdot: style_attribute.set_value("mediumdashdotdot"); break; + case border_style::mediumdashed: style_attribute.set_value("mediumdashed"); break; + case border_style::slantdashdot: style_attribute.set_value("slantdashdot"); break; + case border_style::thick: style_attribute.set_value("thick"); break; + case border_style::thin: style_attribute.set_value("thin"); break; + default: throw std::runtime_error("invalid style"); + } } - } - - if(border_.right.is_color_assigned()) - { - auto color_node = right_node.append_child("color"); - if(border_.right.get_color_type() == side::color_type::indexed) + if(side_.is_color_assigned()) { - color_node.append_attribute("indexed").set_value((int)border_.right.get_color()); - } - else if(border_.diagonal.get_color_type() == side::color_type::theme) - { - color_node.append_attribute("indexed").set_value((int)border_.right.get_color()); - } - else - { - throw std::runtime_error("invalid color type"); - } - } - } - - if(border_.top_assigned) - { - auto top_node = border_node.append_child("top"); - - if(border_.top.is_style_assigned()) - { - auto style_attribute = top_node.append_attribute("style"); - - switch(border_.top.get_style()) - { - case border_style::none: style_attribute.set_value("none"); break; - case border_style::thin: style_attribute.set_value("thin"); break; - default: throw std::runtime_error("invalid style"); - } - } - - if(border_.top.is_color_assigned()) - { - auto color_node = top_node.append_child("color"); - if(border_.top.get_color_type() == side::color_type::indexed) - { - color_node.append_attribute("indexed").set_value((int)border_.top.get_color()); - } - else if(border_.diagonal.get_color_type() == side::color_type::theme) - { - color_node.append_attribute("indexed").set_value((int)border_.top.get_color()); - } - else - { - throw std::runtime_error("invalid color type"); - } - } - } - - if(border_.bottom_assigned) - { - auto bottom_node = border_node.append_child("bottom"); - - if(border_.bottom.is_style_assigned()) - { - auto style_attribute = bottom_node.append_attribute("style"); - - switch(border_.bottom.get_style()) - { - case border_style::none: style_attribute.set_value("none"); break; - case border_style::thin: style_attribute.set_value("thin"); break; - default: throw std::runtime_error("invalid style"); - } - } - - if(border_.bottom.is_color_assigned()) - { - auto color_node = bottom_node.append_child("color"); - - if(border_.bottom.get_color_type() == side::color_type::indexed) - { - color_node.append_attribute("indexed").set_value((int)border_.bottom.get_color()); - } - else if(border_.diagonal.get_color_type() == side::color_type::theme) - { - color_node.append_attribute("indexed").set_value((int)border_.bottom.get_color()); - } - else - { - throw std::runtime_error("invalid color type"); - } - } - } - - if(border_.diagonal_assigned) - { - auto diagonal_node = border_node.append_child("diagonal"); - - if(border_.diagonal.is_style_assigned()) - { - auto style_attribute = diagonal_node.append_attribute("style"); - - switch(border_.diagonal.get_style()) - { - case border_style::none: style_attribute.set_value("none"); break; - case border_style::thin: style_attribute.set_value("thin"); break; - default: throw std::runtime_error("invalid style"); - } - } - - if(border_.diagonal.is_color_assigned()) - { - auto color_node = diagonal_node.append_child("color"); - - if(border_.diagonal.get_color_type() == side::color_type::indexed) - { - color_node.append_attribute("indexed").set_value((int)border_.diagonal.get_color()); - } - else if(border_.diagonal.get_color_type() == side::color_type::theme) - { - color_node.append_attribute("indexed").set_value((int)border_.diagonal.get_color()); - } - else - { - throw std::runtime_error("invalid color type"); + auto color_node = side_node.append_child("color"); + + if(side_.get_color_type() == side::color_type::indexed) + { + color_node.append_attribute("indexed").set_value((int)side_.get_color()); + } + else if(side_.get_color_type() == side::color_type::theme) + { + color_node.append_attribute("indexed").set_value((int)side_.get_color()); + } + else + { + throw std::runtime_error("invalid color type"); + } } } }