diff --git a/include/xlnt/cell/cell.hpp b/include/xlnt/cell/cell.hpp index 941217b8..0b3d40e3 100644 --- a/include/xlnt/cell/cell.hpp +++ b/include/xlnt/cell/cell.hpp @@ -426,7 +426,12 @@ public: /// /// Returns a wrapper pointing to the named style applied to this cell. /// - const class style style() const; + class style style(); + + /// + /// Returns a wrapper pointing to the named style applied to this cell. + /// + const class style style() const; /// /// Sets the named style applied to this cell to a style named style_name. diff --git a/include/xlnt/styles/format.hpp b/include/xlnt/styles/format.hpp index 60b36ddc..0117aabb 100755 --- a/include/xlnt/styles/format.hpp +++ b/include/xlnt/styles/format.hpp @@ -43,6 +43,7 @@ namespace detail { struct format_impl; struct stylesheet; +class xlsx_producer; } // namespace detail @@ -52,11 +53,6 @@ struct stylesheet; class XLNT_API format { public: - /// - /// - /// - std::size_t id() const; - // Alignment /// @@ -234,10 +230,16 @@ public: /// /// /// - const class style style() const; + class style style(); + + /// + /// + /// + const class style style() const; private: friend struct detail::stylesheet; + friend class detail::xlsx_producer; friend class cell; /// @@ -245,6 +247,11 @@ private: /// format(detail::format_impl *d); + /// + /// + /// + std::size_t id() const; + /// /// /// diff --git a/include/xlnt/styles/style.hpp b/include/xlnt/styles/style.hpp index 4fa07d83..c76432b4 100755 --- a/include/xlnt/styles/style.hpp +++ b/include/xlnt/styles/style.hpp @@ -61,81 +61,79 @@ public: style() = delete; /// - /// Default copy constructor + /// Default copy constructor. Constructs a style using the same PIMPL as other. /// style(const style &other) = default; /// - /// Return the name of this style. + /// Returns the name of this style. /// std::string name() const; /// - /// + /// Sets the name of this style to name. /// style name(const std::string &name); /// - /// + /// Returns true if this style is hidden. /// bool hidden() const; /// - /// + /// Sets the hidden state of this style to value. A hidden style will not + /// be shown in the list of selectable styles in the UI, but will still + /// apply its formatting to cells using it. /// style hidden(bool value); /// - /// + /// Returns true if this is a builtin style that has been customized and + /// should therefore be persisted in the workbook. /// - optional custom() const; + bool custom_builtin() const; /// - /// + /// Returns the index of the builtin style that this style is an instance + /// of or is a customized version thereof. If style::builtin() is false, + /// this will throw an invalid_attribute exception. /// - style custom(bool value); + std::size_t builtin_id() const; + + /// + /// Returns true if this is a builtin style. + /// + bool builtin() const; + + // Formatting (xf) components /// - /// + /// Returns the alignment of this style. /// - optional builtin_id() const; + class alignment alignment() const; + + /// + /// Returns true if the alignment of this style should be applied to cells + /// using it. + /// + bool alignment_applied() const; /// - /// - /// - style builtin_id(std::size_t builtin_id); - - // Formatting components - - /// - /// - /// - class alignment &alignment(); - - /// - /// - /// - const class alignment &alignment() const; - - /// - /// + /// Sets the alignment of this style to new_alignment. Applied, which defaults + /// to true, determines whether the alignment should be enabled for cells using + /// this style. /// style alignment(const xlnt::alignment &new_alignment, bool applied = true); /// /// /// - bool alignment_applied() const; + class border border() const; - /// - /// - /// - class border &border(); - - /// - /// - /// - const class border &border() const; + /// + /// + /// + bool border_applied() const; /// /// @@ -145,17 +143,12 @@ public: /// /// /// - bool border_applied() const; + class fill fill() const; - /// - /// - /// - class fill &fill(); - - /// - /// - /// - const class fill &fill() const; + /// + /// + /// + bool fill_applied() const; /// /// @@ -165,17 +158,12 @@ public: /// /// /// - bool fill_applied() const; + class font font() const; - /// - /// - /// - class font &font(); - - /// - /// - /// - const class font &font() const; + /// + /// + /// + bool font_applied() const; /// /// @@ -185,17 +173,12 @@ public: /// /// /// - bool font_applied() const; + class number_format number_format() const; - /// - /// - /// - class number_format &number_format(); - - /// - /// - /// - const class number_format &number_format() const; + /// + /// + /// + bool number_format_applied() const; /// /// @@ -205,53 +188,51 @@ public: /// /// /// - bool number_format_applied() const; + class protection protection() const; + + /// + /// + /// + bool protection_applied() const; /// - /// - /// - class protection &protection(); - - /// - /// - /// - const class protection &protection() const; - - /// - /// + /// /// style protection(const xlnt::protection &new_protection, bool applied = true); /// - /// - /// - bool protection_applied() const; - - /// - /// + /// Returns true if the pivot table interface is enabled for this style. /// bool pivot_button() const; /// - /// + /// If show is true, a pivot table interface will be displayed for cells using + /// this style. /// void pivot_button(bool show); /// - /// + /// Returns true if this style should add a single-quote prefix for all text values. /// bool quote_prefix() const; /// - /// + /// If quote is true, enables a single-quote prefix for all text values in cells + /// using this style (e.g. "abc" will appear as "'abc"). The text will also not + /// be stored in sharedStrings when this is enabled. /// void quote_prefix(bool quote); /// - /// + /// Returns true if this style is equivalent to other. /// bool operator==(const style &other) const; + /// + /// Returns true if this style is not equivalent to other. + /// + bool operator!=(const style &other) const; + private: friend struct detail::stylesheet; friend class detail::xlsx_consumer; diff --git a/include/xlnt/workbook/workbook.hpp b/include/xlnt/workbook/workbook.hpp index 86715b71..01826e88 100644 --- a/include/xlnt/workbook/workbook.hpp +++ b/include/xlnt/workbook/workbook.hpp @@ -669,6 +669,11 @@ public: /// class style create_style(const std::string &name); + /// + /// Creates a new style and returns it. + /// + class style create_builtin_style(std::size_t builtin_id); + /// /// Clear all named styles from cells and remove the styles from /// from the styelsheet. This leaves all other styling in place diff --git a/source/cell/cell.cpp b/source/cell/cell.cpp index 559b2cc7..aa5addd3 100644 --- a/source/cell/cell.cpp +++ b/source/cell/cell.cpp @@ -792,14 +792,26 @@ void cell::style(const std::string &style_name) style(workbook().style(style_name)); } -const style cell::style() const +style cell::style() { if (!has_format() || !format().has_style()) { throw invalid_attribute(); } - return format().style(); + auto f = format(); + + return f.style(); +} + +const style cell::style() const +{ + if (!has_format() || !format().has_style()) + { + throw invalid_attribute(); + } + + return format().style(); } bool cell::has_style() const diff --git a/source/detail/style_impl.hpp b/source/detail/style_impl.hpp index ccffa092..49153ae1 100755 --- a/source/detail/style_impl.hpp +++ b/source/detail/style_impl.hpp @@ -25,7 +25,7 @@ struct style_impl std::string name; std::size_t formatting_record_id; - optional custom_builtin; + bool custom_builtin; bool hidden_style; optional builtin_id; diff --git a/source/detail/stylesheet.hpp b/source/detail/stylesheet.hpp index f02e4eb9..1e6f6d36 100644 --- a/source/detail/stylesheet.hpp +++ b/source/detail/stylesheet.hpp @@ -83,6 +83,71 @@ struct stylesheet return xlnt::style(&impl); } + class style create_builtin_style(const std::size_t builtin_id) + { + // From Annex G.2 + static const auto *names = new std::unordered_map + { + { 0, "Normal" }, + { 1, "RowLevel_1" }, + { 2, "ColLevel_1" }, + { 3, "Comma" }, + { 4, "Currency" }, + { 5, "Percent" }, + { 6, "Comma [0]" }, + { 7, "Currency [0]" }, + { 8, "Hyperlink" }, + { 9, "Followed Hyperlink" }, + { 10, "Note" }, + { 11, "Warning Text" }, + { 15, "Title" }, + { 16, "Heading 1" }, + { 17, "Heading 2" }, + { 18, "Heading 3" }, + { 19, "Heading 4" }, + { 20, "Input" }, + { 21, "Output"}, + { 22, "Calculation"}, + { 22, "Calculation" }, + { 23, "Check Cell" }, + { 24, "Linked Cell" }, + { 25, "Total" }, + { 26, "Good" }, + { 27, "Bad" }, + { 28, "Neutral" }, + { 29, "Accent1" }, + { 30, "20% - Accent1" }, + { 31, "40% - Accent1" }, + { 32, "60% - Accent1" }, + { 33, "Accent2" }, + { 34, "20% - Accent2" }, + { 35, "40% - Accent2" }, + { 36, "60% - Accent2" }, + { 37, "Accent3" }, + { 38, "20% - Accent3" }, + { 39, "40% - Accent3" }, + { 40, "60% - Accent3" }, + { 41, "Accent4" }, + { 42, "20% - Accent4" }, + { 43, "40% - Accent4" }, + { 44, "60% - Accent4" }, + { 45, "Accent5" }, + { 46, "20% - Accent5" }, + { 47, "40% - Accent5" }, + { 48, "60% - Accent5" }, + { 49, "Accent6" }, + { 50, "20% - Accent6" }, + { 51, "40% - Accent6" }, + { 52, "60% - Accent6" }, + { 53, "Explanatory Text" } + }; + + auto new_style = create_style(names->at(builtin_id)); + new_style.d_->builtin_id = builtin_id; + + return new_style; + } + class style style(const std::string &name) { if (!has_style(name)) throw key_not_found(); diff --git a/source/detail/xlsx_producer.cpp b/source/detail/xlsx_producer.cpp index f4c243ac..c28cf6bd 100755 --- a/source/detail/xlsx_producer.cpp +++ b/source/detail/xlsx_producer.cpp @@ -1422,10 +1422,10 @@ void xlsx_producer::write_styles(const relationship & /*rel*/) write_attribute("hidden", write_bool(true)); } - if (current_style.custom_builtin.is_set()) - { - write_attribute("customBuiltin", write_bool(current_style.custom_builtin.get())); - } + if (current_style.builtin_id.is_set() && current_style.custom_builtin) + { + write_attribute("customBuiltin", write_bool(current_style.custom_builtin)); + } write_end_element(xmlns, "cellStyle"); } diff --git a/source/styles/format.cpp b/source/styles/format.cpp index 42a5e581..4f1dab3f 100755 --- a/source/styles/format.cpp +++ b/source/styles/format.cpp @@ -61,7 +61,7 @@ bool format::has_style() const return d_->style.is_set(); } -const style format::style() const +style format::style() { if (!has_style()) { @@ -71,6 +71,16 @@ const style format::style() const return d_->parent->style(d_->style.get()); } +const style format::style() const +{ + if (!has_style()) + { + throw invalid_attribute(); + } + + return d_->parent->style(d_->style.get()); +} + xlnt::alignment &format::alignment() { return d_->parent->alignments.at(d_->alignment_id.get()); diff --git a/source/styles/style.cpp b/source/styles/style.cpp index d2632f6a..694989e1 100755 --- a/source/styles/style.cpp +++ b/source/styles/style.cpp @@ -31,6 +31,17 @@ #include #include +namespace { + +std::vector::iterator find_number_format( + std::vector &number_formats, std::size_t id) +{ + return std::find_if(number_formats.begin(), number_formats.end(), + [=](const xlnt::number_format &nf) { return nf.id() == id; }); +} + +} + namespace xlnt { style::style(detail::style_impl *d) @@ -49,15 +60,9 @@ style style::hidden(bool value) return style(d_); } -optional style::builtin_id() const +std::size_t style::builtin_id() const { - return d_->builtin_id; -} - -style style::builtin_id(std::size_t builtin_id) -{ - d_->builtin_id = builtin_id; - return *this; + return d_->builtin_id.get(); } std::string style::name() const @@ -71,15 +76,9 @@ style style::name(const std::string &name) return *this; } -optional style::custom() const +bool style::custom_builtin() const { - return d_->custom_builtin; -} - -style style::custom(bool value) -{ - d_->custom_builtin = value; - return *this; + return d_->builtin_id.is_set() && d_->custom_builtin; } bool style::operator==(const style &other) const @@ -87,86 +86,94 @@ bool style::operator==(const style &other) const return name() == other.name(); } -xlnt::alignment &style::alignment() +xlnt::alignment style::alignment() const { return d_->parent->alignments.at(d_->alignment_id.get()); } -const xlnt::alignment &style::alignment() const +bool style::alignment_applied() const { - return d_->parent->alignments.at(d_->alignment_id.get()); + return d_->alignment_applied; } style style::alignment(const xlnt::alignment &new_alignment, bool applied) { d_->alignment_id = d_->parent->find_or_add(d_->parent->alignments, new_alignment); d_->alignment_applied = applied; - return style(d_); + + return *this; } -xlnt::border &style::border() +xlnt::border style::border() const { return d_->parent->borders.at(d_->border_id.get()); } -const xlnt::border &style::border() const +bool style::border_applied() const { - return d_->parent->borders.at(d_->border_id.get()); + return d_->border_applied; } style style::border(const xlnt::border &new_border, bool applied) { d_->border_id = d_->parent->find_or_add(d_->parent->borders, new_border); d_->border_applied = applied; - return style(d_); + + return *this; } -xlnt::fill &style::fill() +xlnt::fill style::fill() const { return d_->parent->fills.at(d_->fill_id.get()); } -const xlnt::fill &style::fill() const +bool style::fill_applied() const { - return d_->parent->fills.at(d_->fill_id.get()); + return d_->fill_applied; } style style::fill(const xlnt::fill &new_fill, bool applied) { d_->fill_id = d_->parent->find_or_add(d_->parent->fills, new_fill); d_->fill_applied = applied; - return style(d_); + + return *this; } -xlnt::font &style::font() +xlnt::font style::font() const { return d_->parent->fonts.at(d_->font_id.get()); } -const xlnt::font &style::font() const +bool style::font_applied() const { - return d_->parent->fonts.at(d_->font_id.get()); + return d_->font_applied; } style style::font(const xlnt::font &new_font, bool applied) { d_->font_id = d_->parent->find_or_add(d_->parent->fonts, new_font); d_->font_applied = applied; - return style(d_); + + return *this; } -xlnt::number_format &style::number_format() +xlnt::number_format style::number_format() const { - auto tarid = d_->number_format_id.get(); - return *std::find_if(d_->parent->number_formats.begin(), d_->parent->number_formats.end(), - [=](const class number_format &nf) { return nf.id() == tarid; }); + auto match = find_number_format(d_->parent->number_formats, + d_->number_format_id.get()); + + if (match == d_->parent->number_formats.end()) + { + throw invalid_attribute(); + } + + return *match; } -const xlnt::number_format &style::number_format() const +bool style::number_format_applied() const { - auto tarid = d_->number_format_id.get(); - return *std::find_if(d_->parent->number_formats.begin(), d_->parent->number_formats.end(), - [=](const class number_format &nf) { return nf.id() == tarid; }); + return d_->number_format_applied; } style style::number_format(const xlnt::number_format &new_number_format, bool applied) @@ -178,64 +185,34 @@ style style::number_format(const xlnt::number_format &new_number_format, bool ap copy.id(d_->parent->next_custom_number_format_id()); d_->parent->number_formats.push_back(copy); } - else if (std::find_if(d_->parent->number_formats.begin(), d_->parent->number_formats.end(), - [©](const class number_format &nf) { return nf.id() == copy.id(); }) - == d_->parent->number_formats.end()) - { + else if (find_number_format(d_->parent->number_formats, copy.id()) + == d_->parent->number_formats.end()) + { d_->parent->number_formats.push_back(copy); } d_->number_format_id = copy.id(); d_->number_format_applied = applied; - return style(d_); + return *this; } -xlnt::protection &style::protection() +xlnt::protection style::protection() const { return d_->parent->protections.at(d_->protection_id.get()); } -const xlnt::protection &style::protection() const +bool style::protection_applied() const { - return d_->parent->protections.at(d_->protection_id.get()); + return d_->protection_applied; } style style::protection(const xlnt::protection &new_protection, bool applied) { d_->protection_id = d_->parent->find_or_add(d_->parent->protections, new_protection); d_->protection_applied = applied; - return style(d_); -} -bool style::alignment_applied() const -{ - return d_->alignment_applied; -} - -bool style::border_applied() const -{ - return d_->border_applied; -} - -bool style::fill_applied() const -{ - return d_->fill_applied; -} - -bool style::font_applied() const -{ - return d_->font_applied; -} - -bool style::number_format_applied() const -{ - return d_->number_format_applied; -} - -bool style::protection_applied() const -{ - return d_->protection_applied; + return *this; } bool style::pivot_button() const diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp index 7a3dfcab..59449471 100644 --- a/source/workbook/workbook.cpp +++ b/source/workbook/workbook.cpp @@ -497,12 +497,7 @@ workbook workbook::empty() .color(theme_color(1)); stylesheet.fonts.push_back(default_font); - wb.create_style("Normal") - .builtin_id(0) - .border(default_border, false) - .fill(default_fill, false) - .font(default_font, false) - .number_format(xlnt::number_format::general(), false); + wb.create_builtin_style(0); wb.create_format(true) .border(default_border, false) @@ -1351,6 +1346,11 @@ style workbook::create_style(const std::string &name) return d_->stylesheet_.get().create_style(name); } +style workbook::create_builtin_style(const std::size_t builtin_id) +{ + return d_->stylesheet_.get().create_builtin_style(builtin_id); +} + style workbook::style(const std::string &name) { return d_->stylesheet_.get().style(name);