diff --git a/include/xlnt/styles/alignment.hpp b/include/xlnt/styles/alignment.hpp index 99a9a2c6..ec0d3ae8 100644 --- a/include/xlnt/styles/alignment.hpp +++ b/include/xlnt/styles/alignment.hpp @@ -52,7 +52,7 @@ public: optional rotation() const; - alignment &rotation(bool text_rotation); + alignment &rotation(int text_rotation); optional horizontal() const; diff --git a/include/xlnt/styles/font.hpp b/include/xlnt/styles/font.hpp index a3af7f55..ba6a4ff2 100644 --- a/include/xlnt/styles/font.hpp +++ b/include/xlnt/styles/font.hpp @@ -54,6 +54,10 @@ public: bool bold() const; + font &superscript(bool superscript); + + bool superscript() const; + font &italic(bool italic); bool italic() const; diff --git a/source/detail/xlsx_consumer.cpp b/source/detail/xlsx_consumer.cpp index 690cc1a3..a2733555 100644 --- a/source/detail/xlsx_consumer.cpp +++ b/source/detail/xlsx_consumer.cpp @@ -673,9 +673,11 @@ void xlsx_consumer::read_pivot_table() void xlsx_consumer::read_shared_string_table() { - static const auto xmlns = constants::get_namespace("shared-strings"); + static const auto xmlns = constants::get_namespace("worksheet"); parser().next_expect(xml::parser::event_type::start_element, xmlns, "sst"); + parser().content(xml::content::complex); + std::size_t unique_count = 0; if (parser().attribute_present("uniqueCount")) @@ -690,12 +692,14 @@ void xlsx_consumer::read_shared_string_table() if (parser().peek() == xml::parser::event_type::end_element) break; parser().next_expect(xml::parser::event_type::start_element, xmlns, "si"); + parser().content(xml::content::complex); parser().next_expect(xml::parser::event_type::start_element); text t; if (parser().name() == "t") { + parser().next_expect(xml::parser::event_type::characters); t.set_plain_string(parser().value()); } else if (parser().name() == "r") // possible multiple text entities. @@ -705,8 +709,8 @@ void xlsx_consumer::read_shared_string_table() if (parser().peek() == xml::parser::event_type::end_element) break; parser().next_expect(xml::parser::event_type::start_element, xmlns, "t"); - - text_run run; + parser().next_expect(xml::parser::event_type::characters); + text_run run; run.set_string(parser().value()); if (parser().peek() == xml::parser::event_type::start_element) @@ -740,14 +744,16 @@ void xlsx_consumer::read_shared_string_table() run.set_scheme(parser().attribute("val")); } - parser().next_expect(xml::parser::event_type::end_element, parser().qname()); + parser().next_expect(xml::parser::event_type::end_element); } } t.add_run(run); } } - + + parser().next_expect(xml::parser::event_type::end_element); + parser().next_expect(xml::parser::event_type::end_element); strings.push_back(t); } @@ -1022,6 +1028,10 @@ void xlsx_consumer::read_stylesheet() new_font.bold(true); } } + else if (parser().name() == "vertAlign") + { + new_font.superscript(parser().attribute("val") == "superscript"); + } else if (parser().name() == "strike") { if (parser().attribute_present("val")) @@ -1127,6 +1137,7 @@ void xlsx_consumer::read_stylesheet() if (parser().peek() == xml::parser::event_type::end_element) break; parser().next_expect(xml::parser::event_type::start_element, xmlns, "xf"); + parser().content(xml::content::complex); auto &record = *(!in_style_records ? format_records.emplace(format_records.end()) @@ -1179,8 +1190,25 @@ void xlsx_consumer::read_stylesheet() if (parser().qname() == xml::qname(xmlns, "alignment")) { - record.alignment.first.wrap(is_true(parser().attribute("wrapText"))); - record.alignment.first.shrink(is_true(parser().attribute("shrinkToFit"))); + if (parser().attribute_present("wrapText")) + { + record.alignment.first.wrap(is_true(parser().attribute("wrapText"))); + } + + if (parser().attribute_present("shrinkToFit")) + { + record.alignment.first.shrink(is_true(parser().attribute("shrinkToFit"))); + } + + if (parser().attribute_present("indent")) + { + record.alignment.first.indent(parser().attribute("indent")); + } + + if (parser().attribute_present("textRotation")) + { + record.alignment.first.rotation(parser().attribute("textRotation")); + } if (parser().attribute_present("vertical")) { @@ -1462,6 +1490,7 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id) if (parser().peek() == xml::parser::event_type::end_element) break; parser().next_expect(xml::parser::event_type::start_element, xmlns, "row"); + parser().content(xml::content::complex); auto row_index = static_cast(std::stoull(parser().attribute("r"))); @@ -1470,6 +1499,16 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id) ws.get_row_properties(row_index).height = std::stold(parser().attribute("ht")); } + if (parser().attribute_present("customHeight")) + { + ws.get_row_properties(row_index).height = std::stold(parser().attribute("customHeight")); + } + + if (parser().attribute_present(xml::qname(xmlns_x14ac, "dyDescent"))) + { + parser().attribute(xml::qname(xmlns_x14ac, "dyDescent")); + } + std::string span_string = parser().attribute("spans"); auto colon_index = span_string.find(':'); @@ -1492,6 +1531,7 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id) if (parser().peek() == xml::parser::event_type::end_element) break; parser().next_expect(xml::parser::event_type::start_element, xmlns, "c"); + parser().content(xml::content::complex); auto cell = ws.get_cell(cell_reference(parser().attribute("r"))); auto has_type = parser().attribute_present("t"); @@ -1516,22 +1556,26 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id) if (parser().qname() == xml::qname(xmlns, "v")) { has_value = true; + parser().next_expect(xml::parser::event_type::characters); value_string = parser().value(); } else if (parser().qname() == xml::qname(xmlns, "f")) { has_formula = true; - has_shared_formula = parser().attribute_present("t") && parser().attribute("t") == "shared"; + has_shared_formula = parser().attribute_present("t") + && parser().attribute("t") == "shared"; + parser().next_expect(xml::parser::event_type::characters); formula_value_string = parser().value(); } else if (parser().qname() == xml::qname(xmlns, "is")) { parser().next_expect(xml::parser::event_type::start_element, xmlns, "t"); + parser().next_expect(xml::parser::event_type::characters); value_string = parser().value(); parser().next_expect(xml::parser::event_type::end_element, xmlns, "t"); } - parser().next_expect(xml::parser::event_type::end_element, parser().qname()); + parser().next_expect(xml::parser::event_type::end_element); } if (has_formula && !has_shared_formula && !ws.get_workbook().get_data_only()) @@ -1572,6 +1616,8 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id) parser().next_expect(xml::parser::event_type::end_element, xmlns, "c"); } + + parser().next_expect(xml::parser::event_type::end_element, xmlns, "row"); } parser().next_expect(xml::parser::event_type::end_element, xmlns, "sheetData"); @@ -1601,6 +1647,11 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id) ws.get_column_properties(min).style = column_style; ws.get_column_properties(min).custom = custom; } + + if (parser().attribute_present("bestFit")) + { + parser().attribute("bestFit"); + } parser().next_expect(xml::parser::event_type::end_element, xmlns, "col"); } diff --git a/source/detail/xlsx_producer.cpp b/source/detail/xlsx_producer.cpp index 78fdf7a2..6ab55498 100644 --- a/source/detail/xlsx_producer.cpp +++ b/source/detail/xlsx_producer.cpp @@ -758,9 +758,19 @@ void xlsx_producer::write_styles(const relationship &rel) serializer().start_element(xmlns, "fonts"); serializer().attribute("count", fonts.size()); + auto num_known_fonts = std::count_if(fonts.begin(), fonts.end(), [](const xlnt::font &f) + { + static const auto known_fonts = std::vector + { + xlnt::font().color(xlnt::theme_color(1)).scheme("minor").family(2) + }; + + return std::find(known_fonts.begin(), known_fonts.end(), f) != known_fonts.end(); + }); + if (source_.x15_enabled()) { - serializer().attribute(xmlns_x14ac, "knownFonts", fonts.size()); + serializer().attribute(xmlns_x14ac, "knownFonts", num_known_fonts); } for (const auto ¤t_font : fonts) @@ -999,7 +1009,7 @@ void xlsx_producer::write_styles(const relationship &rel) { const auto current_alignment = current_style.alignment(); - serializer().start_element("alignment"); + serializer().start_element(xmlns, "alignment"); if (current_alignment.vertical()) { @@ -1031,17 +1041,17 @@ void xlsx_producer::write_styles(const relationship &rel) serializer().attribute("shrinkToFit", write_bool(*current_alignment.shrink())); } - serializer().end_element("alignment"); + serializer().end_element(xmlns, "alignment"); } if (current_style.protection_applied()) { const auto current_protection = current_style.protection(); - serializer().start_element("protection"); + serializer().start_element(xmlns, "protection"); serializer().attribute("locked", write_bool(current_protection.locked())); serializer().attribute("hidden", write_bool(current_protection.hidden())); - serializer().end_element("protection"); + serializer().end_element(xmlns, "protection"); } serializer().end_element(xmlns, "xf"); @@ -1072,11 +1082,18 @@ void xlsx_producer::write_styles(const relationship &rel) if (current_format.alignment_applied()) serializer().attribute("applyAlignment", write_bool(true)); if (current_format.protection_applied()) serializer().attribute("applyProtection", write_bool(true)); + if (current_format.has_style()) + { + serializer().attribute("xfId", std::distance(stylesheet.styles.begin(), + std::find_if(stylesheet.styles.begin(), stylesheet.styles.end(), + [&](const xlnt::style &s) { return s.name() == current_format.style().name(); }))); + } + if (current_format.alignment_applied()) { const auto current_alignment = current_format.alignment(); - serializer().start_element("alignment"); + serializer().start_element(xmlns, "alignment"); if (current_alignment.vertical()) { @@ -1108,24 +1125,17 @@ void xlsx_producer::write_styles(const relationship &rel) serializer().attribute("shrinkToFit", write_bool(*current_alignment.shrink())); } - serializer().end_element("alignment"); + serializer().end_element(xmlns, "alignment"); } if (current_format.protection_applied()) { const auto current_protection = current_format.protection(); - serializer().start_element("protection"); + serializer().start_element(xmlns, "protection"); serializer().attribute("locked", write_bool(current_protection.locked())); serializer().attribute("hidden", write_bool(current_protection.hidden())); - serializer().end_element("protection"); - } - - if (current_format.has_style()) - { - serializer().attribute("xfId", std::distance(stylesheet.styles.begin(), - std::find_if(stylesheet.styles.begin(), stylesheet.styles.end(), - [&](const xlnt::style &s) { return s.name() == current_format.style().name(); }))); + serializer().end_element(xmlns, "protection"); } serializer().end_element(xmlns, "xf"); @@ -1845,13 +1855,13 @@ void xlsx_producer::write_worksheet(const relationship &rel) const auto &props = ws.get_column_properties(column); - serializer().end_element(xmlns, "col"); + serializer().start_element(xmlns, "col"); serializer().attribute("min", column.index); serializer().attribute("max", column.index); serializer().attribute("width", props.width); serializer().attribute("style", props.style); serializer().attribute("customWidth", write_bool(props.custom)); - serializer().end_element(xmlns, "cols"); + serializer().end_element(xmlns, "col"); } serializer().end_element(xmlns, "cols"); diff --git a/source/styles/alignment.cpp b/source/styles/alignment.cpp index ef552330..61e16fe4 100644 --- a/source/styles/alignment.cpp +++ b/source/styles/alignment.cpp @@ -81,9 +81,9 @@ optional alignment::indent() const return indent_; } -alignment &alignment::rotation(bool value) +alignment &alignment::rotation(int value) { - text_rotation_ = 0; + text_rotation_ = value; return *this; } diff --git a/source/styles/font.cpp b/source/styles/font.cpp index 0b480a19..f94dfb59 100644 --- a/source/styles/font.cpp +++ b/source/styles/font.cpp @@ -50,6 +50,17 @@ bool font::bold() const return bold_; } +font &font::superscript(bool superscript) +{ + superscript_ = superscript; + return *this; +} + +bool font::superscript() const +{ + return superscript_; +} + font &font::italic(bool italic) { italic_ = italic; diff --git a/source/workbook/tests/test_round_trip.hpp b/source/workbook/tests/test_round_trip.hpp index fe401808..11610a6e 100644 --- a/source/workbook/tests/test_round_trip.hpp +++ b/source/workbook/tests/test_round_trip.hpp @@ -93,7 +93,6 @@ public: void test_round_trip_empty_excel_rw() { - TS_SKIP(""); auto path = path_helper::get_data_directory("9_default-excel.xlsx"); TS_ASSERT(round_trip_matches_rw(path)); } @@ -107,13 +106,12 @@ public: void test_round_trip_all_styles_rw() { - TS_SKIP(""); auto path = path_helper::get_data_directory("13_all_styles.xlsx"); xlnt::workbook original_workbook; original_workbook.load(path); std::vector buffer; original_workbook.save(buffer); -// TS_ASSERT(round_trip_matches_rw(path)); + //TS_ASSERT(round_trip_matches_rw(path)); } };