diff --git a/include/xlnt/styles/protection.hpp b/include/xlnt/styles/protection.hpp index d0b9b842..4f06822f 100644 --- a/include/xlnt/styles/protection.hpp +++ b/include/xlnt/styles/protection.hpp @@ -36,28 +36,21 @@ namespace xlnt { class XLNT_CLASS protection : public hashable { public: - enum class type - { - inherit, - protected_, - unprotected - }; - protection(); - protection(type locked); + protection(bool locked, bool hidden); - type get_locked() const; - void set_locked(type locked_type); + bool get_locked() const; + void set_locked(bool locked); - type get_hidden() const; - void set_hidden(type hidden_type); + bool get_hidden() const; + void set_hidden(bool hidden); protected: std::string to_hash_string() const override; private: - type locked_; - type hidden_; + bool locked_; + bool hidden_; }; } // namespace xlnt diff --git a/source/cell/tests/test_cell.hpp b/source/cell/tests/test_cell.hpp index 0dcae423..9f8e5af1 100644 --- a/source/cell/tests/test_cell.hpp +++ b/source/cell/tests/test_cell.hpp @@ -420,14 +420,11 @@ public: TS_ASSERT(!cell.has_format()); - xlnt::protection prot; - prot.set_locked(xlnt::protection::type::protected_); - - cell.set_protection(prot); + cell.set_protection(xlnt::protection(false, true)); TS_ASSERT(cell.has_format()); TS_ASSERT(cell.get_format().protection_applied()); - TS_ASSERT_EQUALS(cell.get_protection(), prot); + TS_ASSERT_EQUALS(cell.get_protection(), xlnt::protection(false, true)); TS_ASSERT(cell.has_format()); cell.clear_format(); diff --git a/source/detail/number_formatter.cpp b/source/detail/number_formatter.cpp index e995578e..3080cb83 100644 --- a/source/detail/number_formatter.cpp +++ b/source/detail/number_formatter.cpp @@ -465,10 +465,40 @@ void number_format_parser::finalize() bool leading_zero = false; std::size_t minutes_index = 0; + bool integer_part = false; + bool fractional_part = false; + std::size_t integer_part_index = 0; + + bool percentage = false; + + bool exponent = false; + std::size_t exponent_index = 0; + for (std::size_t i = 0; i < code.parts.size(); ++i) { const auto &part = code.parts[i]; + if (part.placeholders.type == format_placeholders::placeholders_type::integer_part) + { + integer_part = true; + integer_part_index = i; + } + else if (part.placeholders.type == format_placeholders::placeholders_type::fractional_part) + { + fractional_part = true; + } + else if (part.placeholders.type == format_placeholders::placeholders_type::scientific_exponent_plus + || part.placeholders.type == format_placeholders::placeholders_type::scientific_exponent_minus) + { + exponent = true; + exponent_index = i; + } + + if (part.placeholders.percentage) + { + percentage = true; + } + if (part.type == template_part::template_type::month_number || part.type == template_part::template_type::month_number_leading_zero) { @@ -514,6 +544,30 @@ void number_format_parser::finalize() template_part::template_type::minute_leading_zero : template_part::template_type::minute; } + + if (integer_part && !fractional_part) + { + code.parts[integer_part_index].placeholders.type = format_placeholders::placeholders_type::integer_only; + } + + if (integer_part && fractional_part && percentage) + { + code.parts[integer_part_index].placeholders.percentage = true; + } + + if (exponent) + { + const auto &next = code.parts[exponent_index + 1]; + auto temp = code.parts[exponent_index].placeholders.type; + code.parts[exponent_index].placeholders = next.placeholders; + code.parts[exponent_index].placeholders.type = temp; + code.parts.erase(code.parts.begin() + exponent_index + 1); + + for (std::size_t i = 0; i < code.parts.size(); ++i) + { + code.parts[i].placeholders.scientific = true; + } + } } validate(); @@ -608,15 +662,18 @@ number_format_token number_format_parser::parse_next_token() do { token.string.push_back(current_char); - current_char = format_string_[position_]; - - if (current_char != '.') - { - ++position_; - } + current_char = format_string_[position_++]; } while (current_char == '0' || current_char == '#' || current_char == '?' || current_char == ','); + --position_; + + if (current_char == '%') + { + token.string.push_back('%'); + ++position_; + } + break; case 'y': @@ -692,6 +749,17 @@ number_format_token number_format_parser::parse_next_token() token.type = number_format_token::token_type::number; token.string.push_back(current_char); break; + + case 'E': + token.type = number_format_token::token_type::number; + token.string.push_back(current_char); + current_char = format_string_[position_++]; + + if (current_char == '+' || current_char == '-') + { + token.string.push_back(current_char); + break; + } default: throw std::runtime_error("unexpected character"); @@ -736,6 +804,22 @@ format_placeholders number_format_parser::parse_placeholders(const std::string & { p.type = format_placeholders::placeholders_type::fractional_part; } + else if (placeholders_string.front() == 'E') + { + p.type = placeholders_string[1] == '+' + ? format_placeholders::placeholders_type::scientific_exponent_plus + : format_placeholders::placeholders_type::scientific_exponent_minus; + return p; + } + else + { + p.type = format_placeholders::placeholders_type::integer_part; + } + + if (placeholders_string.back() == '%') + { + p.percentage = true; + } std::vector comma_indices; @@ -983,10 +1067,28 @@ std::string number_formatter::fill_placeholders(const format_placeholders &p, lo return result; } + if (p.percentage) + { + number *= 100; + } + auto integer_part = static_cast(number); - if (p.type != format_placeholders::placeholders_type::fractional_part) + if (p.type == format_placeholders::placeholders_type::integer_only + || p.type == format_placeholders::placeholders_type::integer_part) { + if (p.scientific) + { + auto fractional_part = number; + + while (fractional_part > 10) + { + fractional_part /= 10; + } + + integer_part = static_cast(fractional_part); + } + auto result = std::to_string(integer_part); while (result.size() < p.num_zeros) @@ -1017,14 +1119,32 @@ std::string number_formatter::fill_placeholders(const format_placeholders &p, lo result = std::string(temp.rbegin(), temp.rend()); } + if (p.percentage && p.type == format_placeholders::placeholders_type::integer_only) + { + result.push_back('%'); + } + return result; } - else + else if (p.type == format_placeholders::placeholders_type::fractional_part) { auto fractional_part = number - integer_part; - auto result = std::to_string(fractional_part).substr(1); - while (result.back() == '0') + if (p.scientific) + { + fractional_part = number; + + while (fractional_part > 10) + { + fractional_part /= 10; + } + + fractional_part -= static_cast(fractional_part); + } + + auto result = fractional_part == 0 ? std::string(".") : std::to_string(fractional_part).substr(1); + + while (result.back() == '0' || result.size() > (p.num_zeros + p.num_optionals + 1)) { result.pop_back(); } @@ -1039,8 +1159,45 @@ std::string number_formatter::fill_placeholders(const format_placeholders &p, lo result.push_back(' '); } + if (p.percentage) + { + result.push_back('%'); + } + return result; } + else if (p.type == format_placeholders::placeholders_type::scientific_exponent_minus + || p.type == format_placeholders::placeholders_type::scientific_exponent_plus) + { + auto exponent = number != 0 ? static_cast(std::log10(integer_part)) : 0; + auto result = std::to_string(exponent); + + while (result.back() == '0' || result.size() > (p.num_zeros + p.num_optionals)) + { + result.pop_back(); + } + + while (result.size() < p.num_zeros) + { + result = "0" + result; + } + + while (result.size() < p.num_zeros + p.num_spaces) + { + result = " " + result; + } + + if (p.percentage) + { + result.push_back('%'); + } + + result = (p.type == format_placeholders::placeholders_type::scientific_exponent_plus ? "E+" : "E") + result; + + return result; + } + + return ""; } std::string number_formatter::format_number(const format_code &format, long double number) @@ -1188,6 +1345,7 @@ std::string number_formatter::format_number(const format_code &format, long doub std::string number_formatter::format_text(const format_code &format, const std::string &text) { std::string result; + bool any_text_part = false; for (const auto &part : format.parts) { @@ -1195,6 +1353,7 @@ std::string number_formatter::format_text(const format_code &format, const std:: { case template_part::template_type::text: result.append(part.string); + any_text_part = true; break; case template_part::template_type::general: @@ -1202,6 +1361,7 @@ std::string number_formatter::format_text(const format_code &format, const std:: || part.placeholders.type == format_placeholders::placeholders_type::text) { result.append(text); + any_text_part = true; } break; @@ -1211,6 +1371,11 @@ std::string number_formatter::format_text(const format_code &format, const std:: } } + if (!format.parts.empty() && !any_text_part) + { + return text; + } + return result; } diff --git a/source/detail/number_formatter.hpp b/source/detail/number_formatter.hpp index daba1170..baf12a80 100644 --- a/source/detail/number_formatter.hpp +++ b/source/detail/number_formatter.hpp @@ -236,16 +236,20 @@ struct format_placeholders bad, general, text, - fractional_part, + integer_only, integer_part, + fractional_part, fraction_integer, fraction_numerator, fraction_denominator, scientific_significand, - scientific_exponent + scientific_exponent_plus, + scientific_exponent_minus } type = placeholders_type::bad; bool use_comma_separator = false; + bool percentage = false; + bool scientific = false; std::size_t num_zeros = 0; // 0 std::size_t num_optionals = 0; // # diff --git a/source/detail/style_serializer.cpp b/source/detail/style_serializer.cpp index 80e933e5..d3d968d8 100644 --- a/source/detail/style_serializer.cpp +++ b/source/detail/style_serializer.cpp @@ -93,36 +93,6 @@ std::size_t string_to_size_t(const std::string &s) // enum serialization // -// protection::type serialization - -xlnt::protection::type protection_type_from_string(const std::string &type_string) -{ - auto lower = string_lower(type_string); - - if (lower == "inherit") return xlnt::protection::type::inherit; - if (is_true(lower)) return xlnt::protection::type::protected_; - - if (!is_false(lower)) - { - throw std::runtime_error("bad enum " + type_string); - } - - return xlnt::protection::type::unprotected; -}; - -std::string protection_type_to_string(xlnt::protection::type type) -{ - switch (type) - { - case xlnt::protection::type::inherit: return "inherit"; - case xlnt::protection::type::protected_: return "true"; - case xlnt::protection::type::unprotected: return "false"; - } - - throw std::runtime_error("bad enum " + std::to_string(static_cast(type))); -} - - // font::underline_style serialization const std::unordered_map &get_string_underline_style_map() @@ -398,10 +368,25 @@ xlnt::protection read_protection(const pugi::xml_node protection_node) { xlnt::protection prot; - prot.set_locked(protection_type_from_string(protection_node.attribute("locked").value())); - prot.set_hidden(protection_type_from_string(protection_node.attribute("hidden").value())); + if (is_true(protection_node.attribute("locked").value())) + { + prot.set_locked(true); + } + else if (!is_false(protection_node.attribute("locked").value())) + { + throw std::runtime_error("bad protection value"); + } - return std::move(prot); + if (is_true(protection_node.attribute("hidden").value())) + { + prot.set_hidden(true); + } + else if (!is_false(protection_node.attribute("hidden").value())) + { + throw std::runtime_error("bad protection value"); + } + + return prot; } xlnt::alignment read_alignment(const pugi::xml_node alignment_node) @@ -1030,12 +1015,14 @@ bool write_base_format(const xlnt::base_format &xf, const xlnt::detail::styleshe if (xf.get_alignment().has_vertical()) { - alignment_node.append_attribute("vertical").set_value(vertical_alignment_to_string(xf.get_alignment().get_vertical()).c_str()); + auto vertical = vertical_alignment_to_string(xf.get_alignment().get_vertical()); + alignment_node.append_attribute("vertical").set_value(vertical.c_str()); } if (xf.get_alignment().has_horizontal()) { - alignment_node.append_attribute("horizontal").set_value(horizontal_alignment_to_string(xf.get_alignment().get_horizontal()).c_str()); + auto horizontal = horizontal_alignment_to_string(xf.get_alignment().get_horizontal()); + alignment_node.append_attribute("horizontal").set_value(horizontal.c_str()); } if (xf.get_alignment().get_wrap_text()) @@ -1052,9 +1039,8 @@ bool write_base_format(const xlnt::base_format &xf, const xlnt::detail::styleshe if (xf.protection_applied()) { auto protection_node = xf_node.append_child("protection"); - - protection_node.append_attribute("locked").set_value(protection_type_to_string(xf.get_protection().get_locked()).c_str()); - protection_node.append_attribute("hidden").set_value(protection_type_to_string(xf.get_protection().get_hidden()).c_str()); + protection_node.append_attribute("locked").set_value(xf.get_protection().get_locked() ? "1" : "0"); + protection_node.append_attribute("hidden").set_value(xf.get_protection().get_hidden() ? "1" : "0"); } return true; @@ -1139,17 +1125,6 @@ bool write_colors(const std::vector &colors, pugi::xml_node &colors return true; } -bool write_ext_list(pugi::xml_node &ext_list_node) -{ - auto ext_node = ext_list_node.append_child("ext"); - - ext_node.append_attribute("uri").set_value("{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}"); - ext_node.append_attribute("xmlns:x14").set_value("http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"); - ext_node.append_child("x14:slicerStyles").append_attribute("defaultSlicerStyle").set_value("SlicerStyleLight1"); - - return true; -} - bool write_number_formats(const std::vector &number_formats, pugi::xml_node &number_formats_node) { number_formats_node.append_attribute("count").set_value(std::to_string(number_formats.size()).c_str()); @@ -1238,9 +1213,6 @@ bool style_serializer::write_stylesheet(pugi::xml_document &doc) auto colors_node = root_node.append_child("colors"); write_colors(stylesheet_.colors, colors_node); } - - auto ext_list_node = root_node.append_child("extLst"); - write_ext_list(ext_list_node); return true; } diff --git a/source/detail/stylesheet.hpp b/source/detail/stylesheet.hpp index c0e8f7f3..820f491c 100644 --- a/source/detail/stylesheet.hpp +++ b/source/detail/stylesheet.hpp @@ -95,7 +95,7 @@ struct stylesheet } formats.push_back(f); - format_styles.push_back(""); + format_styles.push_back("Normal"); try { diff --git a/source/styles/common_style.cpp b/source/styles/common_style.cpp index 07e39ded..bd0f16aa 100644 --- a/source/styles/common_style.cpp +++ b/source/styles/common_style.cpp @@ -162,8 +162,11 @@ const protection &base_format::get_protection() const void base_format::set_protection(const xlnt::protection &new_protection) { - protection_ = new_protection; - protection_applied(true); + if (!new_protection.get_locked() || new_protection.get_hidden()) + { + protection_ = new_protection; + protection_applied(true); + } } std::string base_format::to_hash_string() const diff --git a/source/styles/number_format.cpp b/source/styles/number_format.cpp index 01a5afa1..18cd474a 100644 --- a/source/styles/number_format.cpp +++ b/source/styles/number_format.cpp @@ -44,10 +44,10 @@ const std::unordered_map &builtin_formats() { 2, "0.00" }, { 3, "#,##0" }, { 4, "#,##0.00" }, - { 5, "\"$\"#,##0_);(\"$\"#,##0)" }, - { 6, "\"$\"#,##0_);[Red](\"$\"#,##0)" }, - { 7, "\"$\"#,##0.00_);(\"$\"#,##0.00)" }, - { 8, "\"$\"#,##0.00_);[Red](\"$\"#,##0.00)" }, + { 5, "#,##0;-#,##0" }, + { 6, "#,##0;[Red]-#,##0" }, + { 7, "#,##0.00;-#,##0.00" }, + { 8, "#,##0.00;[Red]-#,##0.00" }, { 9, "0%" }, { 10, "0.00%" }, { 11, "0.00E+00" }, diff --git a/source/styles/protection.cpp b/source/styles/protection.cpp index 73073fc6..13f543b2 100644 --- a/source/styles/protection.cpp +++ b/source/styles/protection.cpp @@ -26,41 +26,42 @@ namespace xlnt { -protection::protection() : protection(type::unprotected) +protection::protection() : protection(true, false) { } -protection::protection(type t) : locked_(t), hidden_(type::unprotected) +protection::protection(bool locked, bool hidden) + : locked_(locked), + hidden_(hidden) { } -protection::type protection::get_locked() const +bool protection::get_locked() const { return locked_; } -void protection::set_locked(type locked_type) +void protection::set_locked(bool locked) { - locked_ = locked_type; + locked_ = locked; } - -protection::type protection::get_hidden() const +bool protection::get_hidden() const { return hidden_; } -void protection::set_hidden(type hidden_type) +void protection::set_hidden(bool hidden) { - hidden_ = hidden_type; + hidden_ = hidden; } std::string protection::to_hash_string() const { std::string hash_string = "protection"; - hash_string.append(std::to_string(static_cast(locked_))); - hash_string.append(std::to_string(static_cast(hidden_))); + hash_string.append(locked_ ? "1" : "0"); + hash_string.append(hidden_ ? "1" : "0"); return hash_string; } diff --git a/source/styles/tests/test_number_format.hpp b/source/styles/tests/test_number_format.hpp index 42f08a1a..f9f3050b 100644 --- a/source/styles/tests/test_number_format.hpp +++ b/source/styles/tests/test_number_format.hpp @@ -363,46 +363,155 @@ public: nf.set_format_string("\"first\"General;\"second\"General;\"third\"General;\"fourth\"General;\"fifth\"General"); TS_ASSERT_THROWS(nf.format(1.2, xlnt::calendar::windows_1900), std::runtime_error); } - - void test_builtin_formats() + + void format_and_test(const xlnt::number_format &nf, const std::array &expect) { - TS_ASSERT_EQUALS(xlnt::number_format::text().format("a"), "a"); - TS_ASSERT_EQUALS(xlnt::number_format::number().format(1, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::number_comma_separated1().format(12345.67, xlnt::calendar::windows_1900), "12,345.67"); + long double positive = 42503.1234; + long double negative = -1 * positive; + long double zero = 0; + const std::string text = "text"; + xlnt::calendar calendar = xlnt::calendar::windows_1900; -/* - auto datetime = xlnt::datetime(2016, 6, 24, 0, 45, 58); - auto datetime_number = datetime.to_number(xlnt::calendar::windows_1900); + TS_ASSERT_EQUALS(nf.format(positive, calendar), expect[0]); + TS_ASSERT_EQUALS(nf.format(negative, calendar), expect[1]); + TS_ASSERT_EQUALS(nf.format(zero, calendar), expect[2]); + TS_ASSERT_EQUALS(nf.format(text), expect[3]); + } - TS_ASSERT_EQUALS(xlnt::number_format::percentage().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::percentage_00().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_yyyymmdd2().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_yyyymmdd().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_ddmmyyyy().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_dmyslash().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_dmyminus().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_dmminus().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_myminus().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_xlsx14().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_xlsx15().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_xlsx16().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_xlsx17().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_xlsx22().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_datetime().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_time1().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_time2().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_time3().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_time4().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_time5().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_time6().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_time7().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_time8().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_timedelta().format(datetime_number, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::date_yyyymmddslash().format(datetime_number, xlnt::calendar::windows_1900), "1"); + // General + void test_builtin_format_0() + { + format_and_test(xlnt::number_format::general(), {{"42503.1234", "-42503.1234", "0", "text"}}); + } - TS_ASSERT_EQUALS(xlnt::number_format::currency_usd_simple().format(1.23, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::currency_usd().format(1.23, xlnt::calendar::windows_1900), "1"); - TS_ASSERT_EQUALS(xlnt::number_format::currency_eur_simple().format(1.23, xlnt::calendar::windows_1900), "1"); -*/ + // 0 + void test_builtin_format_1() + { + format_and_test(xlnt::number_format::number(), {{"42503", "-42503", "0", "text"}}); + } + // 0.00 + void test_builtin_format_2() + { + format_and_test(xlnt::number_format::number_00(), {{"42503.12", "-42503.12", "0.00", "text"}}); + } + + // #,##0 + void test_builtin_format_3() + { + format_and_test(xlnt::number_format::from_builtin_id(3), {{"42,503", "-42,503", "0", "text"}}); + } + + // #,##0.00 + void test_builtin_format_4() + { + format_and_test(xlnt::number_format::from_builtin_id(4), {{"42,503.12", "-42,503.12", "0.00", "text"}}); + } + + // #,##0;-#,##0 + void test_builtin_format_5() + { + format_and_test(xlnt::number_format::from_builtin_id(5), {{"42,503", "-42,503", "0", "text"}}); + } + + // #,##0;[Red]-#,##0 + void test_builtin_format_6() + { + format_and_test(xlnt::number_format::from_builtin_id(6), {{"42,503", "-42,503", "0", "text"}}); + } + + // #,##0.00;-#,##0.00 + void test_builtin_format_7() + { + format_and_test(xlnt::number_format::from_builtin_id(7), {{"42,503.12", "-42,503.12", "0.00", "text"}}); + } + + // #,##0.00;[Red]-#,##0.00 + void test_builtin_format_8() + { + format_and_test(xlnt::number_format::from_builtin_id(8), {{"42,503.12", "-42,503.12", "0.00", "text"}}); + } + + // 0% + void test_builtin_format_9() + { + format_and_test(xlnt::number_format::percentage(), {{"4250312%", "-4250312%", "0%", "text"}}); + } + + // 0.00% + void test_builtin_format_10() + { + format_and_test(xlnt::number_format::percentage_00(), {{"4250312.34%", "-4250312.34%", "0.00%", "text"}}); + } + + // 0.00E+00 + void test_builtin_format_11() + { + format_and_test(xlnt::number_format::from_builtin_id(11), {{"4.25E+04", "-4.25E+04", "0.00E+00", "text"}}); + } + + // # ?/? + void _test_builtin_format_12() + { + format_and_test(xlnt::number_format::from_builtin_id(12), {{"42503 1/8", "-42503 1/8", "0", "text"}}); + } + + // # ??/?? + void _test_builtin_format_13() + { + format_and_test(xlnt::number_format::from_builtin_id(13), {{"42503 10/81", "-42503 10/81", "0", "text"}}); + } + + // mm-dd-yy + void _test_builtin_format_14() + { + format_and_test(xlnt::number_format::from_builtin_id(14), {{"05-13-16", "###########", "01-00-00", "text"}}); + } + + // d-mmm-yy + void _test_builtin_format_15() + { + format_and_test(xlnt::number_format::from_builtin_id(15), {{"13-May-16", "###########", "0-Jan-00", "text"}}); + } + + // d-mmm + void _test_builtin_format_16() + { + format_and_test(xlnt::number_format::from_builtin_id(16), {{"13-May", "###########", "0-Jan", "text"}}); + } + + // mmm-yy + void _test_builtin_format_17() + { + format_and_test(xlnt::number_format::from_builtin_id(17), {{"May-16", "###########", "Jan-00", "text"}}); + } + + // h:mm AM/PM + void _test_builtin_format_18() + { + format_and_test(xlnt::number_format::from_builtin_id(18), {{"2:57 AM", "###########", "12:00 AM", "text"}}); + } + + // h:mm:ss AM/PM + void _test_builtin_format_19() + { + format_and_test(xlnt::number_format::from_builtin_id(19), {{"2:57:42 AM", "###########", "12:00:00 AM", "text"}}); + } + + // h:mm + void _test_builtin_format_20() + { + format_and_test(xlnt::number_format::from_builtin_id(20), {{"2:57", "###########", "0:00", "text"}}); + } + + // h:mm:ss + void _test_builtin_format_21() + { + format_and_test(xlnt::number_format::from_builtin_id(21), {{"2:57:42", "###########", "0:00:00", "text"}}); + } + + // m/d/yy h:mm + void _test_builtin_format_22() + { + format_and_test(xlnt::number_format::from_builtin_id(22), {{"5/13/16 2:57", "###########", "1/0/00 0:00", "text"}}); } }; diff --git a/source/styles/tests/test_stylesheet.hpp b/source/styles/tests/test_stylesheet.hpp index a154de70..96717d93 100644 --- a/source/styles/tests/test_stylesheet.hpp +++ b/source/styles/tests/test_stylesheet.hpp @@ -14,65 +14,6 @@ class test_stylesheet : public CxxTest::TestSuite { public: - void test_ctor() - { - xlnt::workbook wb; - xlnt::excel_serializer excel_serializer(wb); - xlnt::style_serializer style_serializer(excel_serializer.get_stylesheet()); - xlnt::zip_file archive; - pugi::xml_document stylesheet_doc; - style_serializer.write_stylesheet(stylesheet_doc); - std::ostringstream ss; - stylesheet_doc.save(ss); - auto stylesheet_xml = ss.str(); - - const std::string expected = - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; - - TS_ASSERT(Helper::compare_xml(expected, stylesheet_xml)); - } - - void test_from_simple() { pugi::xml_document doc; diff --git a/source/workbook/tests/test_style_writer.hpp b/source/workbook/tests/test_style_writer.hpp index 0f52ada9..4e557069 100644 --- a/source/workbook/tests/test_style_writer.hpp +++ b/source/workbook/tests/test_style_writer.hpp @@ -6,6 +6,7 @@ #include #include #include +#include class test_style_writer : public CxxTest::TestSuite { @@ -27,262 +28,80 @@ public: auto diff = Helper::compare_xml(expected_doc.child("numFmts"), observed.child("styleSheet").child("numFmts")); TS_ASSERT(diff); } - /* - class TestStyleWriter(object): + + void test_simple_styles() + { + xlnt::workbook wb; + wb.set_guess_types(true); + auto ws = wb.get_active_sheet(); + ws.get_cell("A1").set_value("12.34%"); + auto now = xlnt::date::today(); + ws.get_cell("A2").set_value(now); + ws.get_cell("A3").set_value("This is a test"); + ws.get_cell("A4").set_value("31.31415"); + ws.get_cell("A5"); + + ws.get_cell("D9").set_number_format(xlnt::number_format::number_00()); + xlnt::protection locked(true, false); + ws.get_cell("D9").set_protection(locked); + xlnt::protection hidden(true, true); + ws.get_cell("E1").set_protection(hidden); + + xlnt::excel_serializer e(wb); + xlnt::style_serializer serializer(e.get_stylesheet()); + pugi::xml_document xml; + serializer.write_stylesheet(xml); + + TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory("/writer/expected/simple-styles.xml"), xml)); + } - void setup(self): - self.workbook = Workbook() - self.worksheet = self.workbook.create_sheet() - - void _test_no_style(self): - w = StyleWriter(self.workbook) - assert len(w.wb._cell_styles) == 1 # there is always the empty (defaul) style - - void _test_nb_style(self): - for i in range(1, 6): - cell = self.worksheet.cell(row=1, column=i) - cell.font = Font(size=i) - _ = cell.style_id - w = StyleWriter(self.workbook) - assert len(w.wb._cell_styles) == 6 # 5 + the default - - cell = self.worksheet.cell('A10') - cell.border=Border(top=Side(border_style=borders.BORDER_THIN)) - _ = cell.style_id - w = StyleWriter(self.workbook) - assert len(w.wb._cell_styles) == 7 - - - void _test_default_xfs(self): - w = StyleWriter(self.workbook) - fonts = nft = borders = fills = DummyElement() - w._write_cell_styles() - xml = tostring(w._root) - expected = """ - - - - - - """ - diff = compare_xml(xml, expected) - assert diff is None, diff - - - void _test_xfs_number_format(self): - for idx, nf in enumerate(["0.0%", "0.00%", "0.000%"], 1): - cell = self.worksheet.cell(row=idx, column=1) - cell.number_format = nf - _ = cell.style_id # add to workbook styles - w = StyleWriter(self.workbook) - w._write_cell_styles() - - expected = """ - - - - - - - - - """ - - xml = tostring(w._root) - diff = compare_xml(xml, expected) - assert diff is None, diff - - - void _test_xfs_fonts(self): - cell = self.worksheet.cell('A1') - cell.font = Font(size=12, bold=True) - _ = cell.style_id # update workbook styles - w = StyleWriter(self.workbook) - - w._write_cell_styles() - xml = tostring(w._root) - - expected = """ - - - - - - - """ - diff = compare_xml(xml, expected) - assert diff is None, diff - - - void _test_xfs_fills(self): - cell = self.worksheet.cell('A1') - cell.fill = fill=PatternFill(fill_type='solid', - start_color=Color(colors.DARKYELLOW)) - _ = cell.style_id # update workbook styles - w = StyleWriter(self.workbook) - w._write_cell_styles() - - xml = tostring(w._root) - expected = """ - - - - - - - """ - diff = compare_xml(xml, expected) - assert diff is None, diff - - - void _test_xfs_borders(self): - cell = self.worksheet.cell('A1') - cell.border=Border(top=Side(border_style=borders.BORDER_THIN, - color=Color(colors.DARKYELLOW))) - _ = cell.style_id # update workbook styles - - w = StyleWriter(self.workbook) - w._write_cell_styles() - - xml = tostring(w._root) - expected = """ - - - - - - - """ - diff = compare_xml(xml, expected) - assert diff is None, diff - - - void _test_protection(self): - cell = self.worksheet.cell('A1') - cell.protection = Protection(locked=True, hidden=True) - _ = cell.style_id - - w = StyleWriter(self.workbook) - w._write_cell_styles() - xml = tostring(w._root) - expected = """ - - - - - - - - """ - diff = compare_xml(xml, expected) - assert diff is None, diff - - - void _test_named_styles(self): - writer = StyleWriter(self.workbook) - writer._write_named_styles() - xml = tostring(writer._root) - expected = """ - - - - - - """ - diff = compare_xml(xml, expected) - assert diff is None, diff - - - void _test_style_names(self): - writer = StyleWriter(self.workbook) - writer._write_style_names() - xml = tostring(writer._root) - expected = """ - - - - - """ - diff = compare_xml(xml, expected) - assert diff is None, diff - - - - void _test_simple_styles(datadir): - wb = Workbook(guess_types=True) - ws = wb.active - now = datetime.datetime.now() - for idx, v in enumerate(['12.34%', now, 'This is a test', '31.31415', None], 1): - ws.append([v]) - _ = ws.cell(column=1, row=idx).style_id - -# set explicit formats - ws['D9'].number_format = numbers.FORMAT_NUMBER_00 - ws['D9'].protection = Protection(locked=True) - ws['D9'].style_id - ws['E1'].protection = Protection(hidden=True) - ws['E1'].style_id - - assert len(wb._cell_styles) == 5 - writer = StyleWriter(wb) - - datadir.chdir() - with open('simple-styles.xml') as reference_file: - expected = reference_file.read() - xml = writer.write_table() - diff = compare_xml(xml, expected) - assert diff is None, diff - - - void _test_empty_workbook(): - wb = Workbook() - writer = StyleWriter(wb) - expected = """ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - """ - xml = writer.write_table() - diff = compare_xml(xml, expected) - assert diff is None, diff - */ + void test_empty_workbook() + { + xlnt::workbook wb; + xlnt::excel_serializer e(wb); + xlnt::style_serializer serializer(e.get_stylesheet()); + auto expected = + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + pugi::xml_document xml; + serializer.write_stylesheet(xml); + TS_ASSERT(Helper::compare_xml(expected, xml)); + } }; diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp index 5f09a534..14ee51a1 100644 --- a/source/workbook/workbook.cpp +++ b/source/workbook/workbook.cpp @@ -91,6 +91,11 @@ workbook::workbook() : d_(new detail::workbook_impl()) add_format(format()); create_style("Normal"); d_->stylesheet_.format_styles.front() = "Normal"; + + xlnt::fill gray125; + gray125.set_type(xlnt::fill::type::pattern); + gray125.set_pattern_type(xlnt::fill::pattern_type::gray125); + d_->stylesheet_.fills.push_back(gray125); } workbook::workbook(encoding e) : workbook() diff --git a/tests/data/writer/expected/simple-styles.xml b/tests/data/writer/expected/simple-styles.xml index 3dd9108e..16566e9c 100644 --- a/tests/data/writer/expected/simple-styles.xml +++ b/tests/data/writer/expected/simple-styles.xml @@ -1,51 +1,49 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file