From 4e51e9e0e5079d707cf0a1ecf4684f6883400cb3 Mon Sep 17 00:00:00 2001 From: Thomas Fussell Date: Wed, 2 Nov 2016 18:16:34 -0400 Subject: [PATCH] working on styles, don't use yet --- include/xlnt/cell/cell.hpp | 48 ++--- include/xlnt/styles/base_format.hpp | 94 --------- include/xlnt/styles/format.hpp | 209 ++++++++++++++++--- include/xlnt/styles/style.hpp | 151 +++++++++++++- include/xlnt/workbook/workbook.hpp | 5 +- source/cell/cell.cpp | 248 +++++++++++++--------- source/cell/tests/test_cell.hpp | 13 ++ source/detail/format_impl.hpp | 28 +++ source/detail/style_impl.hpp | 18 +- source/detail/stylesheet.hpp | 86 ++++++-- source/detail/xlsx_consumer.cpp | 8 +- source/detail/xlsx_producer.cpp | 8 +- source/styles/base_format.cpp | 154 -------------- source/styles/format.cpp | 312 +++++++++++++++++++++++----- source/styles/style.cpp | 169 ++++++++++++++- source/workbook/workbook.cpp | 30 ++- third-party/botan | 2 +- 17 files changed, 1070 insertions(+), 513 deletions(-) diff --git a/include/xlnt/cell/cell.hpp b/include/xlnt/cell/cell.hpp index 803893ac..740cb29a 100644 --- a/include/xlnt/cell/cell.hpp +++ b/include/xlnt/cell/cell.hpp @@ -36,7 +36,6 @@ namespace xlnt { enum class calendar; class alignment; -class base_format; class border; class cell_reference; class comment; @@ -177,41 +176,32 @@ public: // computed format /// - /// For each of alignment, border, fill, font, number format, and protection, - /// returns a format using the value from the cell format if that value is - /// applied, or else the value from the named style if that value is applied, - /// or else the default value. This is used to retreive the formatting of the cell - /// as it will be displayed in an editing application. - /// - base_format get_computed_format() const; - - /// - /// Returns the result of get_computed_format().get_alignment(). + /// /// alignment get_computed_alignment() const; /// - /// Returns the result of get_computed_format().get_border(). + /// /// border get_computed_border() const; /// - /// Returns the result of get_computed_format().get_fill(). + /// /// fill get_computed_fill() const; /// - /// Returns the result of get_computed_format().get_font(). + /// /// font get_computed_font() const; /// - /// Returns the result of get_computed_format().get_number_format(). + /// /// number_format get_computed_number_format() const; /// - /// Returns the result of get_computed_format().get_protection(). + /// /// protection get_computed_protection() const; @@ -492,27 +482,21 @@ private: // make these friends so they can use the private constructor friend class style; friend class worksheet; - friend class detail::xlsx_consumer; - friend class detail::xlsx_producer; + friend class detail::xlsx_consumer; + friend class detail::xlsx_producer; friend struct detail::cell_impl; - /// - /// Helper function to guess the type of a string, convert it, - /// and then use the correct cell::get_value according to the type. - /// - void guess_type_and_set_value(const std::string &value); - - /// - /// Returns a non-const reference to the format of this cell. - /// This is for internal use only. - /// - format &get_format_internal(); + /// + /// Helper function to guess the type of a string, convert it, + /// and then use the correct cell::get_value according to the type. + /// + void guess_type_and_set_value(const std::string &value); /// - /// Use workbook::create_format() to create a new format then copy - /// this cell's formatting to that new format and return it. + /// Returns a non-const reference to the format of this cell. + /// This is for internal use only. /// - format &duplicate_format(); + format &get_format_internal(); /// /// Private constructor to create a cell from its implementation. diff --git a/include/xlnt/styles/base_format.hpp b/include/xlnt/styles/base_format.hpp index af00c55a..e69de29b 100644 --- a/include/xlnt/styles/base_format.hpp +++ b/include/xlnt/styles/base_format.hpp @@ -1,94 +0,0 @@ -// Copyright (c) 2014-2016 Thomas Fussell -// Copyright (c) 2010-2015 openpyxl -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE -// -// @license: http://www.opensource.org/licenses/mit-license.php -// @author: see AUTHORS file -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace xlnt { - -/// -/// Describes the formatting of a particular cell. -/// -class XLNT_API base_format -{ -public: - // Alignment - class alignment &alignment(); - const class alignment &alignment() const; - void alignment(const xlnt::alignment &new_alignment, bool applied); - bool alignment_applied() const; - - // Border - virtual class border &border(); - virtual const class border &border() const; - virtual void border(const xlnt::border &new_border, bool applied); - bool border_applied() const; - - // Fill - virtual class fill &fill(); - virtual const class fill &fill() const; - virtual void fill(const xlnt::fill &new_fill, bool applied); - bool fill_applied() const; - - // Font - virtual class font &font(); - virtual const class font &font() const; - virtual void font(const xlnt::font &new_font, bool applied); - bool font_applied() const; - - // Number Format - virtual class number_format &number_format(); - virtual const class number_format &number_format() const; - virtual void number_format(const xlnt::number_format &new_number_format, bool applied); - bool number_format_applied() const; - - // Protection - class protection &protection(); - const class protection &protection() const; - void protection(const xlnt::protection &new_protection, bool applied); - bool protection_applied() const; - -protected: - class alignment alignment_; - class border border_; - class fill fill_; - class font font_; - class number_format number_format_; - class protection protection_; - - bool apply_alignment_ = false; - bool apply_border_ = false; - bool apply_fill_ = false; - bool apply_font_ = false; - bool apply_number_format_ = false; - bool apply_protection_ = false; -}; - -} // namespace xlnt diff --git a/include/xlnt/styles/format.hpp b/include/xlnt/styles/format.hpp index f609c235..2fbe8302 100644 --- a/include/xlnt/styles/format.hpp +++ b/include/xlnt/styles/format.hpp @@ -36,53 +36,200 @@ class fill; class font; class number_format; class protection; +class workbook; namespace detail { struct format_impl; struct stylesheet; +class xlsx_consumer; +class xlsx_producer; } // namespace detail /// /// Describes the formatting of a particular cell. /// -class XLNT_API format : public base_format +class XLNT_API format { public: - std::size_t id() const; - - bool has_style() const; - void clear_style(); - void style(const std::string &name); - void style(const xlnt::style &new_style); - const class style &style() const; - - class border &border() override; - const class border &border() const override; - void border(const xlnt::border &new_border, bool applied) override; - - class fill &fill() override; - const class fill &fill() const override; - void fill(const xlnt::fill &new_fill, bool applied) override; + /// + /// Returns the index of this format. + /// + std::size_t id() const; - class font &font() override; - const class font &font() const override; - void font(const xlnt::font &new_font, bool applied) override; + // Alignment - class number_format &number_format() override; - const class number_format &number_format() const override; - void number_format(const xlnt::number_format &new_number_format, bool applied) override; + /// + /// Returns the alignment to be applied to contents of cells using this format. + /// + class alignment &alignment(); - format &alignment_id(std::size_t id); - format &border_id(std::size_t id); - format &fill_id(std::size_t id); - format &font_id(std::size_t id); - format &number_format_id(std::size_t id); - format &protection_id(std::size_t id); + /// + /// Returns the alignment to be applied to contents of cells using this format. + /// + const class alignment &alignment() const; + + /// + /// Sets the alignment of this format to new_alignment. If applied is true, + /// the alignment will be used when displaying the cell. Updates all cells + /// currently using this format if update is true, otherwise creates new + /// format with the new protection. + /// + void alignment(const xlnt::alignment &new_alignment, + bool applied = true, bool update = true); + + /// + /// Returns true if the alignment is being applied. + /// + bool alignment_applied() const; + + // Border + + /// + /// Returns the border properties to be applied to the outline of cells using this format. + /// + class border &border(); + + /// + /// Returns the border properties to be applied to the outline of cells using this format. + /// + const class border &border() const; + + /// + /// Sets the border of this format to new_border. If applied is true, + /// the border will be used when displaying the cell. Updates all cells + /// currently using this format if update is true, otherwise creates + /// new format with the new protection. + /// + void border(const xlnt::border &new_border, + bool applied = true, bool update = true); + + /// + /// Returns true if the border is being applied. + /// + bool border_applied() const; + + // Fill + + /// + /// Returns the fill to be applied to the background of cells using this format. + /// + class fill &fill(); + + /// + /// Returns the fill to be applied to the background of cells using this format. + /// + const class fill &fill() const; + + /// + /// Sets the fill of this format to new_fill and applies it if applied is true. + /// Updates all cells currently using this format if update is true, + /// otherwise creates new format with the new protection. + /// + void fill(const xlnt::fill &new_fill, + bool applied = true, bool update = true); + + /// + /// Returns true if the fill is being applied. + /// + bool fill_applied() const; + + // Font + + /// + /// Returns the font to be applied to contents of cells using this format. + /// + class font &font(); + + /// + /// Returns the font to be applied to contents of cells using this format. + /// + const class font &font() const; + + /// + /// Sets the font of this format to new_font and applies it if applied is true. + /// Updates all cells currently using this format if update is true, + /// otherwise creates new format with the new protection. + /// + void font(const xlnt::font &new_font, + bool applied = true, bool update = true); + + /// + /// Returns true if the font is being applied. + /// + bool font_applied() const; + + // Number Format + + /// + /// Returns the number format to be applied to text/numbers in cells using this format. + /// + class number_format &number_format(); + + /// + /// Returns the number format to be applied to text/numbers in cells using this format. + /// + const class number_format &number_format() const; + + /// + /// Sets the number format applied to text/numbers in cells using this format + /// and applies it if applied is true. Updates all cells currently using this + /// format if update is true, otherwise creates new format with the new number + /// format. + /// + void number_format(const xlnt::number_format &new_number_format, + bool applied = true, bool update = true); + + /// + /// Returns true if the number format is being applied. + /// + bool number_format_applied() const; + + // Protection + + /// + /// Returns the protection to be applied to the contents of cells using this format. + /// + class protection &protection(); + + /// + /// Returns the protection to be applied to the contents of cells using this format. + /// + const class protection &protection() const; + + /// + /// Sets the protection of the contents of the cell using this format. Applies it if + /// applied is true. Updates all cells currently using this format if update is true, + /// otherwise creates new format with the new protection. + /// + void protection(const xlnt::protection &new_protection, + bool applied = true, bool update = true); + + /// + /// Returns true if the protection is being applied. + /// + bool protection_applied() const; + + /// + /// Returns true if the formats are identical. + /// + XLNT_API friend bool operator==(const format &left, const format &right); private: - friend struct detail::stylesheet; - format(detail::format_impl *d); - detail::format_impl *d_; + friend struct detail::stylesheet; + friend class detail::xlsx_consumer; + friend class detail::xlsx_producer; + friend class cell; + friend class workbook; + + /// + /// Private constructor used by stylesheet. + /// + format(detail::format_impl *d); + + /// + /// Pointer to implementation. This memory is held in a vector in stylesheet. + /// + detail::format_impl *d_; }; } // namespace xlnt diff --git a/include/xlnt/styles/style.hpp b/include/xlnt/styles/style.hpp index de64f099..aca8e21e 100644 --- a/include/xlnt/styles/style.hpp +++ b/include/xlnt/styles/style.hpp @@ -27,7 +27,6 @@ #include #include -#include namespace xlnt { @@ -40,7 +39,7 @@ struct stylesheet; /// Describes a style which has a name and can be applied to multiple individual /// formats. In Excel this is a "Cell Style". /// -class XLNT_API style : public base_format +class XLNT_API style { public: std::string name() const; @@ -55,18 +54,152 @@ public: optional builtin_id() const; style &builtin_id(std::size_t builtin_id); - style &alignment_id(std::size_t id); - style &border_id(std::size_t id); - style &fill_id(std::size_t id); - style &font_id(std::size_t id); - style &number_format_id(std::size_t id); - style &protection_id(std::size_t id); + // Alignment - bool operator==(const style &other); + /// + /// Returns the alignment to be applied to contents of cells using this format. + /// + class alignment &alignment(); + + /// + /// Returns the alignment to be applied to contents of cells using this format. + /// + const class alignment &alignment() const; + + /// + /// Sets the alignment of this format to new_alignment. If applied is true, + /// the alignment will be used when displaying the cell. + /// + void alignment(const xlnt::alignment &new_alignment, bool applied = true, bool update = true); + + /// + /// Returns true if the alignment is being applied. + /// + bool alignment_applied() const; + + // Border + + /// + /// Returns the border properties to be applied to the outline of cells using this format. + /// + class border &border(); + + /// + /// Returns the border properties to be applied to the outline of cells using this format. + /// + const class border &border() const; + + /// + /// Sets the border of this format to new_border. If applied is true, + /// the border will be used when displaying the cell. + /// + void border(const xlnt::border &new_border, bool applied = true, bool update = true); + + /// + /// Returns true if the border is being applied. + /// + bool border_applied() const; + + // Fill + + /// + /// Returns the fill to be applied to the background of cells using this format. + /// + class fill &fill(); + + /// + /// Returns the fill to be applied to the background of cells using this format. + /// + const class fill &fill() const; + + /// + /// Sets the fill of this format to new_fill and applies it if applied is true. + /// + void fill(const xlnt::fill &new_fill, bool applied = true, bool update = true); + + /// + /// Returns true if the fill is being applied. + /// + bool fill_applied() const; + + // Font + + /// + /// Returns the font to be applied to contents of cells using this format. + /// + class font &font(); + + /// + /// Returns the font to be applied to contents of cells using this format. + /// + const class font &font() const; + + /// + /// Sets the font of this format to new_font and applies it if applied is true. + /// + void font(const xlnt::font &new_font, bool applied = true, bool update = true); + + /// + /// Returns true if the font is being applied. + /// + bool font_applied() const; + + // Number Format + + /// + /// Returns the number format to be applied to text/numbers in cells using this format. + /// + class number_format &number_format(); + + /// + /// Returns the number format to be applied to text/numbers in cells using this format. + /// + const class number_format &number_format() const; + + /// + /// Sets the number format applied to text/numbers in cells using this format + /// and applies it if applied is true. + /// + void number_format(const xlnt::number_format &new_number_format, bool applied = true, bool update = true); + + /// + /// Returns true if the number format is being applied. + /// + bool number_format_applied() const; + + // Protection + + /// + /// Returns the protection to be applied to the contents of cells using this format. + /// + class protection &protection(); + + /// + /// Returns the protection to be applied to the contents of cells using this format. + /// + const class protection &protection() const; + + /// + /// Sets the protection of the contents of the cell using this format. Applies it if + /// applied is true. + /// + void protection(const xlnt::protection &new_protection, bool applied = true, bool update = true); + + /// + /// Returns true if the protection is being applied. + /// + bool protection_applied() const; + + /// + /// Returns true if the formats are identical. + /// + XLNT_API friend bool operator==(const style &left, const style &right); private: friend struct detail::stylesheet; + style(detail::style_impl *d); + detail::style_impl *d_; }; diff --git a/include/xlnt/workbook/workbook.hpp b/include/xlnt/workbook/workbook.hpp index 72736d7e..fb1ebb55 100644 --- a/include/xlnt/workbook/workbook.hpp +++ b/include/xlnt/workbook/workbook.hpp @@ -36,6 +36,7 @@ namespace xlnt { class alignment; +class base_format; class border; class cell; class cell_style; @@ -419,7 +420,9 @@ public: format &get_format(std::size_t format_index); const format &get_format(std::size_t format_index) const; - format &create_format(); + format &create_format(); + format &create_format(format pattern); + format &create_format(base_format pattern); void clear_formats(); // styles diff --git a/source/cell/cell.cpp b/source/cell/cell.cpp index 0bcd539b..a43da945 100644 --- a/source/cell/cell.cpp +++ b/source/cell/cell.cpp @@ -30,8 +30,14 @@ #include #include #include +#include +#include #include +#include +#include #include +#include +#include #include #include #include @@ -44,6 +50,7 @@ #include #include +#include namespace { @@ -610,32 +617,104 @@ void cell::set_data_type(type t) number_format cell::get_computed_number_format() const { - return get_computed_format().number_format(); + number_format computed; + + if (has_format() && get_format().number_format_applied()) + { + computed = get_format().number_format(); + } +/* + if (has_style() && get_style().number_format_applied()) + { + computed = get_style().number_format(); + } +*/ + return computed; } font cell::get_computed_font() const { - return get_computed_format().font(); + font computed; + + if (has_format() && get_format().number_format_applied()) + { + computed = get_format().font(); + } +/* + if (has_style() && get_style().number_format_applied()) + { + computed = get_style().number_format(); + } +*/ + return computed; } fill cell::get_computed_fill() const { - return get_computed_format().fill(); + fill computed; + + if (has_format() && get_format().number_format_applied()) + { + computed = get_format().fill(); + } +/* + if (has_style() && get_style().number_format_applied()) + { + computed = get_style().number_format(); + } +*/ + return computed; } border cell::get_computed_border() const { - return get_computed_format().border(); + border computed; + + if (has_format() && get_format().number_format_applied()) + { + computed = get_format().border(); + } +/* + if (has_style() && get_style().number_format_applied()) + { + computed = get_style().number_format(); + } +*/ + return computed; } alignment cell::get_computed_alignment() const { - return get_computed_format().alignment(); + alignment computed; + + if (has_format() && get_format().number_format_applied()) + { + computed = get_format().alignment(); + } +/* + if (has_style() && get_style().number_format_applied()) + { + computed = get_style().number_format(); + } +*/ + return computed; } protection cell::get_computed_protection() const { - return get_computed_format().protection(); + protection computed; + + if (has_format() && get_format().number_format_applied()) + { + computed = get_format().protection(); + } +/* + if (has_style() && get_style().number_format_applied()) + { + computed = get_style().number_format(); + } +*/ + return computed; } void cell::clear_value() @@ -758,44 +837,80 @@ XLNT_API timedelta cell::get_value() const void cell::set_alignment(const xlnt::alignment &alignment_) { - auto &format = duplicate_format(); - format.alignment(alignment_, true); - d_->format_id_ = format.id(); + if (!has_format()) + { + set_format(get_workbook().create_format()); + get_format().alignment(alignment_, true, true); + } + else + { + get_format().alignment(alignment_, true, false); + } } void cell::set_border(const xlnt::border &border_) { - auto &format = duplicate_format(); - format.border(border_, true); - d_->format_id_ = format.id(); + if (!has_format()) + { + set_format(get_workbook().create_format()); + get_format().border(border_, true, true); + } + else + { + get_format().border(border_, true, false); + } } void cell::set_fill(const xlnt::fill &fill_) { - auto &format = duplicate_format(); - format.fill(fill_, true); - d_->format_id_ = format.id(); + if (!has_format()) + { + set_format(get_workbook().create_format()); + get_format().fill(fill_, true, true); + } + else + { + get_format().fill(fill_, true, false); + } } void cell::set_font(const font &font_) { - auto &format = duplicate_format(); - format.font(font_, true); - d_->format_id_ = format.id(); + if (!has_format()) + { + set_format(get_workbook().create_format()); + get_format().font(font_, true, true); + } + else + { + get_format().font(font_, true, false); + } } void cell::set_number_format(const number_format &number_format_) { - auto &format = duplicate_format(); - format.number_format(number_format_, true); - d_->format_id_ = format.id(); + if (!has_format()) + { + set_format(get_workbook().create_format()); + get_format().number_format(number_format_, true, true); + } + else + { + get_format().number_format(number_format_, true, false); + } } void cell::set_protection(const xlnt::protection &protection_) { - auto &format = duplicate_format(); - format.protection(protection_, true); - d_->format_id_ = format.id(); + if (!has_format()) + { + set_format(get_workbook().create_format()); + get_format().protection(protection_, true, true); + } + else + { + get_format().protection(protection_, true, false); + } } template <> @@ -898,81 +1013,39 @@ void cell::clear_style() { if (has_format()) { - get_format_internal().clear_style(); + get_format().d_->style.clear(); } } void cell::set_style(const style &new_style) { - auto &new_format = duplicate_format(); - new_format.style(new_style); - d_->format_id_ = new_format.id(); + if (!has_format()) + { + set_format(get_workbook().create_format()); + } + + auto current_format = get_format(); + current_format.d_->style = new_style.name(); } void cell::set_style(const std::string &style_name) { - auto &new_format = duplicate_format(); - new_format.style(get_workbook().get_style(style_name).name()); - d_->format_id_ = new_format.id(); + set_style(get_workbook().get_style(style_name)); } style cell::get_style() const { - if (!has_format() || !get_format().has_style()) + if (!has_format() || !get_format().d_->style.is_set()) { throw invalid_attribute(); } - return get_format().style(); + return get_workbook().get_style(get_format().d_->style.get()); } bool cell::has_style() const { - return has_format() && get_format().has_style(); -} - -base_format cell::get_computed_format() const -{ - base_format result; - - // Check style first - - if (has_style()) - { - style cell_style = get_style(); - - if (cell_style.alignment_applied()) result.alignment(cell_style.alignment(), true); - if (cell_style.border_applied()) result.border(cell_style.border(), true); - if (cell_style.fill_applied()) result.fill(cell_style.fill(), true); - if (cell_style.font_applied()) result.font(cell_style.font(), true); - if (cell_style.number_format_applied()) result.number_format(cell_style.number_format(), true); - if (cell_style.protection_applied()) result.protection(cell_style.protection(), true); - } - - // Cell format overrides style - - if (has_format()) - { - format cell_format = get_format(); - - if (cell_format.alignment_applied()) result.alignment(cell_format.alignment(), true); - if (cell_format.border_applied()) result.border(cell_format.border(), true); - if (cell_format.fill_applied()) result.fill(cell_format.fill(), true); - if (cell_format.font_applied()) result.font(cell_format.font(), true); - if (cell_format.number_format_applied()) result.number_format(cell_format.number_format(), true); - if (cell_format.protection_applied()) result.protection(cell_format.protection(), true); - } - - // Use defaults for any remaining non-applied components - - if (!result.alignment_applied()) result.alignment(alignment(), true); - if (!result.border_applied()) result.border(border(), true); - if (!result.fill_applied()) result.fill(fill(), true); - if (!result.font_applied()) result.font(font(), true); - if (!result.number_format_applied()) result.number_format(number_format(), true); - if (!result.protection_applied()) result.protection(protection(), true); - - return result; + return has_format() && get_format().d_->style.is_set(); } format &cell::get_format_internal() @@ -985,25 +1058,6 @@ format &cell::get_format_internal() return get_workbook().get_format(*d_->format_id_); } -format &cell::duplicate_format() -{ - auto &new_format = get_workbook().create_format(); - - if (has_format()) - { - auto ¤t_format = get_format_internal(); - - new_format.alignment(current_format.alignment(), current_format.alignment_applied()); - new_format.border(current_format.border(), current_format.border_applied()); - new_format.fill(current_format.fill(), current_format.fill_applied()); - new_format.font(current_format.font(), current_format.font_applied()); - new_format.number_format(current_format.number_format(), current_format.number_format_applied()); - new_format.protection(current_format.protection(), current_format.protection_applied()); - } - - return new_format; -} - format cell::get_format() const { if (!d_->format_id_) diff --git a/source/cell/tests/test_cell.hpp b/source/cell/tests/test_cell.hpp index c3f1c4a4..51cb7ab5 100644 --- a/source/cell/tests/test_cell.hpp +++ b/source/cell/tests/test_cell.hpp @@ -18,6 +18,19 @@ public: wb_guess_types.set_guess_types(true); } + void test_temp() + { + xlnt::workbook wb; + auto cell = wb[0].get_cell("A1"); + cell.set_value("right"); + cell.set_alignment(xlnt::alignment().horizontal(xlnt::horizontal_alignment::right)); + cell.set_font(xlnt::font().size(20).color(xlnt::color::white())); + cell.set_fill(xlnt::fill::solid(xlnt::color::black())); + wb.create_style("yellow-fill").fill(xlnt::fill::solid(xlnt::color::yellow()), true); + cell.set_style("yellow-fill"); + wb.save("temp.xlsx"); + } + void test_infer_numeric() { auto ws = wb_guess_types.create_sheet(); diff --git a/source/detail/format_impl.hpp b/source/detail/format_impl.hpp index bc1e6561..b9972d63 100644 --- a/source/detail/format_impl.hpp +++ b/source/detail/format_impl.hpp @@ -29,14 +29,42 @@ struct format_impl std::size_t id; + bool alignment_applied = false; optional alignment_id; + bool border_applied = false; optional border_id; + bool fill_applied = false; optional fill_id; + bool font_applied = false; optional font_id; + bool number_format_applied = false; optional number_format_id; + bool protection_applied = false; optional protection_id; optional style; + + bool operator==(const format_impl &other) const + { + return alignment_applied == other.alignment_applied + && alignment_id.is_set() == other.alignment_id.is_set() + && (!alignment_id.is_set() || alignment_id.get() == other.alignment_id.get()) + && border_applied == other.border_applied + && border_id.is_set() == other.border_id.is_set() + && (!border_id.is_set() || border_id.get() == other.border_id.get()) + && fill_applied == other.fill_applied + && fill_id.is_set() == other.fill_id.is_set() + && (!fill_id.is_set() || fill_id.get() == other.fill_id.get()) + && font_applied == other.font_applied + && font_id.is_set() == other.font_id.is_set() + && (!font_id.is_set() || font_id.get() == other.font_id.get()) + && number_format_applied == other.number_format_applied + && number_format_id.is_set() == other.number_format_id.is_set() + && (!number_format_id.is_set() || number_format_id.get() == other.number_format_id.get()) + && protection_applied == other.protection_applied + && protection_id.is_set() == other.protection_id.is_set() + && (!protection_id.is_set() || protection_id.get() == other.protection_id.get()); + } }; } // namespace detail diff --git a/source/detail/style_impl.hpp b/source/detail/style_impl.hpp index d1c71ff7..86cefd49 100644 --- a/source/detail/style_impl.hpp +++ b/source/detail/style_impl.hpp @@ -31,12 +31,18 @@ struct style_impl optional builtin_id; optional outline_style; - optional alignment; - optional border; - optional fill; - optional font; - optional number_format; - optional protection; + bool alignment_applied = false; + optional alignment_id; + bool border_applied = false; + optional border_id; + bool fill_applied = false; + optional fill_id; + bool font_applied = false; + optional font_id; + bool number_format_applied = false; + optional number_format_id; + bool protection_applied = false; + optional protection_id; }; } // namespace detail diff --git a/source/detail/stylesheet.hpp b/source/detail/stylesheet.hpp index b9bb9bc6..6c58c14b 100644 --- a/source/detail/stylesheet.hpp +++ b/source/detail/stylesheet.hpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -38,23 +39,23 @@ namespace detail { struct stylesheet { - ~stylesheet() - { - } - format &create_format() { - format_impls.push_back(format_impl()); - auto &impl = format_impls.back(); - impl.parent = this; - impl.id = format_impls.size() - 1; - formats.push_back(format(&impl)); + format_impls.push_back(format_impl()); + auto &impl = format_impls.back(); + impl.parent = this; + impl.id = format_impls.size() - 1; + formats.push_back(format(&impl)); auto &format = formats.back(); - + if (!alignments.empty()) { format.alignment(alignments.front(), false); } + else + { + format.alignment(alignment(), false); + } if (!borders.empty()) { @@ -73,7 +74,7 @@ struct stylesheet if (!number_formats.empty()) { - format.number_format(number_formats.front(), false); + format.number_format(number_formats.begin()->second, false); } if (!protections.empty()) @@ -84,10 +85,27 @@ struct stylesheet return format; } - format &get_format(std::size_t index) - { - return formats.at(index); - } + format &get_format(std::size_t index) + { + return formats.at(index); + } + + std::pair find_format(format pattern) + { + std::size_t index = 0; + + for (const format &f : formats) + { + if (f == pattern) + { + return {true, index}; + } + + ++index; + } + + return {false, 0}; + } style &create_style() { @@ -130,14 +148,26 @@ struct stylesheet for (const auto &nf : number_formats) { - if (nf.get_id() >= id) + if (nf.second.get_id() >= id) { - id = nf.get_id() + 1; + id = nf.second.get_id() + 1; } } return id; } + + std::size_t add_alignment(const alignment &new_alignment) + { + auto match = std::find(alignments.begin(), alignments.end(), new_alignment); + + if (match == alignments.end()) + { + match = alignments.insert(alignments.end(), new_alignment); + } + + return std::distance(alignments.begin(), match); + } std::size_t add_border(const border &new_border) { @@ -196,6 +226,26 @@ struct stylesheet return index; } + std::size_t add_protection(const protection &new_protection) + { + std::size_t index = 0; + + for (const auto &p : protections) + { + if (p == new_protection) + { + return index; + } + + ++index; + } + + protections.push_back(new_protection); + + return index; + } + + void clear() { format_impls.clear(); @@ -224,7 +274,7 @@ struct stylesheet std::vector borders; std::vector fills; std::vector fonts; - std::vector number_formats; + std::unordered_map number_formats; std::vector protections; std::vector colors; diff --git a/source/detail/xlsx_consumer.cpp b/source/detail/xlsx_consumer.cpp index 8b84cbc1..9700266e 100644 --- a/source/detail/xlsx_consumer.cpp +++ b/source/detail/xlsx_consumer.cpp @@ -1265,7 +1265,7 @@ void xlsx_consumer::read_stylesheet() nf.set_format_string(format_string); nf.set_id(string_to_size_t(parser().attribute("numFmtId"))); - stylesheet.number_formats.push_back(nf); + stylesheet.number_formats[nf.get_id()] = nf; parser().next_expect(xml::parser::event_type::end_element); // numFmt } @@ -1510,9 +1510,9 @@ void xlsx_consumer::read_stylesheet() for (const auto &nf : stylesheet.number_formats) { - if (nf.get_id() == number_format_id) + if (nf.first == number_format_id) { - result = nf; + result = nf.second; is_custom_number_format = true; break; } @@ -1552,7 +1552,7 @@ void xlsx_consumer::read_stylesheet() { auto &new_format = stylesheet.create_format(); - new_format.style(stylesheet.styles.at(record.style_id.first).name()); + new_format.d_->style = stylesheet.styles.at(record.style_id.first).name(); new_format.alignment(record.alignment.first, record.alignment.second); new_format.border(stylesheet.borders.at(record.border_id.first), record.border_id.second); diff --git a/source/detail/xlsx_producer.cpp b/source/detail/xlsx_producer.cpp index bbd5b453..523060e0 100644 --- a/source/detail/xlsx_producer.cpp +++ b/source/detail/xlsx_producer.cpp @@ -776,8 +776,8 @@ void xlsx_producer::write_styles(const relationship &rel) for (const auto &num_fmt : number_formats) { serializer().start_element(xmlns, "numFmt"); - serializer().attribute("numFmtId", num_fmt.get_id()); - serializer().attribute("formatCode", num_fmt.get_format_string()); + serializer().attribute("numFmtId", num_fmt.first); + serializer().attribute("formatCode", num_fmt.second.get_format_string()); serializer().end_element(xmlns, "numFmt"); } @@ -1117,11 +1117,11 @@ 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()) + if (current_format.d_->style.is_set()) { 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(); }))); + [&](const xlnt::style &s) { return s.name() == current_format.d_->style.get(); }))); } if (current_format.alignment_applied()) diff --git a/source/styles/base_format.cpp b/source/styles/base_format.cpp index 1d42898c..e69de29b 100644 --- a/source/styles/base_format.cpp +++ b/source/styles/base_format.cpp @@ -1,154 +0,0 @@ -// Copyright (c) 2014-2016 Thomas Fussell -// Copyright (c) 2010-2015 openpyxl -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE -// -// @license: http://www.opensource.org/licenses/mit-license.php -// @author: see AUTHORS file -#include - -namespace xlnt { - -alignment &base_format::alignment() -{ - return alignment_; -} - -const alignment &base_format::alignment() const -{ - return alignment_; -} - -void base_format::alignment(const xlnt::alignment &new_alignment, bool apply) -{ - alignment_ = new_alignment; - apply_alignment_ = apply; -} - -number_format &base_format::number_format() -{ - return number_format_; -} - -const number_format &base_format::number_format() const -{ - return number_format_; -} - -void base_format::number_format(const xlnt::number_format &new_number_format, bool apply) -{ - number_format_ = new_number_format; - apply_number_format_ = apply; -} - -border &base_format::border() -{ - return border_; -} - -const border &base_format::border() const -{ - return border_; -} - -void base_format::border(const xlnt::border &new_border, bool apply) -{ - border_ = new_border; - apply_border_ = apply; -} - -fill &base_format::fill() -{ - return fill_; -} - -const fill &base_format::fill() const -{ - return fill_; -} - -void base_format::fill(const xlnt::fill &new_fill, bool apply) -{ - fill_ = new_fill; - apply_fill_ = apply; -} - -font &base_format::font() -{ - return font_; -} - -const font &base_format::font() const -{ - return font_; -} - -void base_format::font(const xlnt::font &new_font, bool apply) -{ - font_ = new_font; - apply_font_ = apply; -} - -protection &base_format::protection() -{ - return protection_; -} - -const protection &base_format::protection() const -{ - return protection_; -} - -void base_format::protection(const xlnt::protection &new_protection, bool apply) -{ - protection_ = new_protection; - apply_protection_ = apply; -} - -bool base_format::alignment_applied() const -{ - return apply_alignment_; -} - -bool base_format::border_applied() const -{ - return apply_border_; -} - -bool base_format::fill_applied() const -{ - return apply_fill_; -} - -bool base_format::font_applied() const -{ - return apply_font_; -} - -bool base_format::number_format_applied() const -{ - return apply_number_format_; -} - -bool base_format::protection_applied() const -{ - return apply_protection_; -} - -} // namespace xlnt diff --git a/source/styles/format.cpp b/source/styles/format.cpp index 1bfb5cb7..88f76870 100644 --- a/source/styles/format.cpp +++ b/source/styles/format.cpp @@ -38,132 +38,334 @@ std::size_t format::id() const return d_->id; } -void format::clear_style() +alignment &format::alignment() { - d_->style.clear(); + return d_->parent->alignments.at(d_->alignment_id); } -void format::style(const xlnt::style &new_style) +const alignment &format::alignment() const { - d_->style = new_style.name(); + return d_->parent->alignments.at(d_->alignment_id); } -void format::style(const std::string &new_style) +void format::alignment(const xlnt::alignment &new_alignment, bool applied, bool update) { - for (auto &style : d_->parent->styles) - { - if (style.name() == new_style) - { - d_->style = new_style; - return; - } - } + auto alignment_id = d_->parent->add_alignment(new_alignment); - throw key_not_found(); -} + if (update) + { + d_->alignment_id = alignment_id; + d_->alignment_applied = applied; + } + else + { + auto impl_copy = *d_; -bool format::has_style() const -{ - return d_->style; -} + impl_copy.alignment_id = alignment_id; + impl_copy.alignment_applied = applied; -const style &format::style() const -{ - if (!has_style()) - { - throw invalid_attribute(); - } + auto match = std::find(d_->parent->format_impls.begin(), d_->parent->format_impls.end(), impl_copy); - return d_->parent->get_style(*d_->style); + if (match != d_->parent->format_impls.end()) + { + d_ = &*match; + } + else + { + d_->parent->format_impls.push_back(impl_copy); + d_ = &d_->parent->format_impls.back(); + } + } } xlnt::border &format::border() { - return base_format::border(); + const auto &self = *this; + return const_cast(self.border()); } const xlnt::border &format::border() const { - return base_format::border(); + if (!d_->border_id) + { + throw xlnt::exception("no border"); + } + + return d_->parent->borders.at(d_->border_id.get()); } -void format::border(const xlnt::border &new_border, bool applied) +void format::border(const xlnt::border &new_border, bool applied, bool update) { - border_id(d_->parent->add_border(new_border)); - base_format::border(new_border, applied); + auto border_id = d_->parent->add_border(new_border); + + if (update) + { + d_->border_id = border_id; + d_->border_applied = applied; + } + else + { + auto impl_copy = *d_; + + impl_copy.border_id = border_id; + impl_copy.border_applied = applied; + + auto match = std::find(d_->parent->format_impls.begin(), d_->parent->format_impls.end(), impl_copy); + + if (match != d_->parent->format_impls.end()) + { + d_ = &*match; + } + else + { + d_->parent->format_impls.push_back(impl_copy); + d_ = &d_->parent->format_impls.back(); + } + } } xlnt::fill &format::fill() { - return base_format::fill(); + const auto &self = *this; + return const_cast(self.fill()); } const xlnt::fill &format::fill() const { - return base_format::fill(); + if (!d_->fill_id) + { + throw xlnt::exception("no border"); + } + + return d_->parent->fills.at(d_->fill_id.get()); } -void format::fill(const xlnt::fill &new_fill, bool applied) +void format::fill(const xlnt::fill &new_fill, bool applied, bool update) { - fill_id(d_->parent->add_fill(new_fill)); - base_format::fill(new_fill, applied); + auto fill_id = d_->parent->add_fill(new_fill); + + if (update) + { + d_->fill_id = fill_id; + d_->fill_applied = applied; + } + else + { + auto impl_copy = *d_; + + impl_copy.fill_id = fill_id; + impl_copy.fill_applied = applied; + + auto match = std::find(d_->parent->format_impls.begin(), d_->parent->format_impls.end(), impl_copy); + + if (match != d_->parent->format_impls.end()) + { + d_ = &*match; + } + else + { + d_->parent->format_impls.push_back(impl_copy); + d_ = &d_->parent->format_impls.back(); + } + } } xlnt::font &format::font() { - return base_format::font(); + const auto &self = *this; + return const_cast(self.font()); } const xlnt::font &format::font() const { - return base_format::font(); + if (!d_->font_id) + { + throw xlnt::exception("no border"); + } + + return d_->parent->fonts.at(d_->font_id.get()); } -void format::font(const xlnt::font &new_font, bool applied) +void format::font(const xlnt::font &new_font, bool applied, bool update) { - font_id(d_->parent->add_font(new_font)); - base_format::font(new_font, applied); + auto font_id = d_->parent->add_font(new_font); + + if (update) + { + d_->font_id = font_id; + d_->font_applied = applied; + } + else + { + auto impl_copy = *d_; + + impl_copy.font_id = font_id; + impl_copy.font_applied = applied; + + auto match = std::find(d_->parent->format_impls.begin(), d_->parent->format_impls.end(), impl_copy); + + if (match != d_->parent->format_impls.end()) + { + d_ = &*match; + } + else + { + d_->parent->format_impls.push_back(impl_copy); + d_ = &d_->parent->format_impls.back(); + } + } } xlnt::number_format &format::number_format() { - return base_format::number_format(); + const auto &self = *this; + return const_cast(self.number_format()); } const xlnt::number_format &format::number_format() const { - return base_format::number_format(); + if (!d_->number_format_id) + { + throw xlnt::exception("no number format"); + } + + return d_->parent->number_formats.at(d_->number_format_id.get()); } -void format::number_format(const xlnt::number_format &new_number_format, bool applied) +void format::number_format(const xlnt::number_format &new_number_format, bool applied, bool update) { auto copy = new_number_format; if (!copy.has_id()) { copy.set_id(d_->parent->next_custom_number_format_id()); - d_->parent->number_formats.push_back(copy); + d_->parent->number_formats[copy.get_id()] = copy; } - base_format::number_format(copy, applied); + auto number_format_id = copy.get_id(); + + if (update) + { + d_->number_format_id = number_format_id; + d_->number_format_applied = applied; + } + else + { + auto impl_copy = *d_; + + impl_copy.number_format_id = number_format_id; + impl_copy.number_format_applied = applied; + + auto match = std::find(d_->parent->format_impls.begin(), d_->parent->format_impls.end(), impl_copy); + + if (match != d_->parent->format_impls.end()) + { + d_ = &*match; + } + else + { + d_->parent->format_impls.push_back(impl_copy); + d_ = &d_->parent->format_impls.back(); + } + } } -format &format::border_id(std::size_t id) +protection &format::protection() { - d_->border_id = id; - return *this; + return d_->parent->protections.at(d_->protection_id); } -format &format::fill_id(std::size_t id) +const protection &format::protection() const { - d_->fill_id = id; - return *this; + return d_->parent->protections.at(d_->protection_id); } -format &format::font_id(std::size_t id) +void format::protection(const xlnt::protection &new_protection, bool applied, bool update) { - d_->font_id = id; - return *this; + auto protection_id = d_->parent->add_protection(new_protection); + + if (update) + { + d_->protection_id = protection_id; + d_->protection_applied = applied; + } + else + { + auto impl_copy = *d_; + + impl_copy.protection_id = protection_id; + impl_copy.protection_applied = applied; + + auto match = std::find(d_->parent->format_impls.begin(), d_->parent->format_impls.end(), impl_copy); + + if (match != d_->parent->format_impls.end()) + { + d_ = &*match; + } + else + { + d_->parent->format_impls.push_back(impl_copy); + d_ = &d_->parent->format_impls.back(); + } + } +} + +bool format::alignment_applied() const +{ + return d_->alignment_applied; +} + +bool format::border_applied() const +{ + return d_->border_applied; +} + +bool format::fill_applied() const +{ + return d_->fill_applied; +} + +bool format::font_applied() const +{ + return d_->font_applied; +} + +bool format::number_format_applied() const +{ + return d_->number_format_applied; +} + +bool format::protection_applied() const +{ + return d_->protection_applied; +} + + + +XLNT_API bool operator==(const format &left, const format &right) +{ + if (left.alignment_applied() != right.alignment_applied()) return false; + if (left.alignment_applied() && left.alignment() != right.alignment()) return false; + + if (left.border_applied() != right.border_applied()) return false; + if (left.border_applied() && left.border() != right.border()) return false; + + if (left.fill_applied() != right.fill_applied()) return false; + if (left.fill_applied() && left.fill() != right.fill()) return false; + + if (left.font_applied() != right.font_applied()) return false; + if (left.font_applied() && left.font() != right.font()) return false; + + if (left.number_format_applied() != right.number_format_applied()) return false; + if (left.number_format_applied() && left.number_format() != right.number_format()) return false; + + if (left.protection_applied() != right.protection_applied()) return false; + if (left.protection_applied() && left.protection() != right.protection()) return false; + + if (left.d_->style.is_set() != right.d_->style.is_set()) return false; + if (left.d_->style.is_set() && left.d_->style.get() != right.d_->style.get()) return false; + + return true; } } // namespace xlnt diff --git a/source/styles/style.cpp b/source/styles/style.cpp index ef3f0e71..a6848203 100644 --- a/source/styles/style.cpp +++ b/source/styles/style.cpp @@ -22,13 +22,14 @@ // @license: http://www.opensource.org/licenses/mit-license.php // @author: see AUTHORS file +#include // include order is important here +#include #include #include #include #include #include #include -#include // include order is important here #include namespace xlnt { @@ -81,9 +82,171 @@ style &style::custom(bool value) return *this; } -bool style::operator==(const style &other) +alignment &style::alignment() { - return d_ == other.d_; + return d_->parent->alignments.at(d_->alignment_id); +} + +const alignment &style::alignment() const +{ + return d_->parent->alignments.at(d_->alignment_id); +} + +void style::alignment(const xlnt::alignment &new_alignment, bool applied, bool update) +{ + if (update) + { + d_->alignment_id = 0; + } +} + +xlnt::border &style::border() +{ + const auto &self = *this; + return const_cast(self.border()); +} + +const xlnt::border &style::border() const +{ + if (!d_->border_id) + { + throw xlnt::exception("no border"); + } + + return d_->parent->borders.at(d_->border_id.get()); +} + +void style::border(const xlnt::border &new_border, bool applied, bool update) +{ + d_->border_id = d_->parent->add_border(new_border); +} + +xlnt::fill &style::fill() +{ + const auto &self = *this; + return const_cast(self.fill()); +} + +const xlnt::fill &style::fill() const +{ + if (!d_->fill_id) + { + throw xlnt::exception("no border"); + } + + return d_->parent->fills.at(d_->fill_id.get()); +} + +void style::fill(const xlnt::fill &new_fill, bool applied, bool update) +{ + d_->fill_id = d_->parent->add_fill(new_fill); + d_->fill_applied = applied; +} + +xlnt::font &style::font() +{ + const auto &self = *this; + return const_cast(self.font()); +} + +const xlnt::font &style::font() const +{ + if (!d_->font_id) + { + throw xlnt::exception("no border"); + } + + return d_->parent->fonts.at(d_->font_id.get()); +} + +void style::font(const xlnt::font &new_font, bool applied, bool update) +{ + d_->font_id = d_->parent->add_font(new_font); + d_->font_applied = applied; +} + +xlnt::number_format &style::number_format() +{ + const auto &self = *this; + return const_cast(self.number_format()); +} + +const xlnt::number_format &style::number_format() const +{ + if (!d_->number_format_id) + { + throw xlnt::exception("no number format"); + } + + return d_->parent->number_formats.at(d_->number_format_id.get()); +} + +void style::number_format(const xlnt::number_format &new_number_format, bool applied, bool update) +{ + auto copy = new_number_format; + + if (!copy.has_id()) + { + copy.set_id(d_->parent->next_custom_number_format_id()); + d_->parent->number_formats[copy.get_id()] = copy; + } + + d_->number_format_id = copy.get_id(); + d_->number_format_applied = applied; +} + +protection &style::protection() +{ + return d_->parent->protections.at(d_->protection_id); +} + +const protection &style::protection() const +{ + return d_->parent->protections.at(d_->protection_id); +} + +void style::protection(const xlnt::protection &new_protection, bool applied, bool update) +{ + if (update) + { + d_->protection_id = 0; + } +} + + +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; +} + +XLNT_API bool operator==(const style &left, const style &right) +{ + return left.d_ == right.d_; } } // namespace xlnt diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp index de13debf..53185d57 100644 --- a/source/workbook/workbook.cpp +++ b/source/workbook/workbook.cpp @@ -165,7 +165,7 @@ workbook workbook::empty_excel() auto &default_format = wb.create_format(); default_format.font(default_font, false); default_format.border(default_border, false); - default_format.style("Normal"); + default_format.d_->style.set("Normal"); wb.set_theme(theme()); @@ -255,7 +255,7 @@ workbook workbook::empty_libre_office() auto default_number_format = xlnt::number_format(); default_number_format.set_format_string("General"); default_number_format.set_id(164); - wb.d_->stylesheet_.number_formats.push_back(default_number_format); + wb.d_->stylesheet_.number_formats[default_number_format.get_id()] = default_number_format; auto default_protection = xlnt::protection() .locked(true) @@ -314,7 +314,7 @@ workbook workbook::empty_libre_office() format.number_format(default_number_format, true); format.alignment(default_alignment, true); format.protection(default_protection, true); - format.style("Normal"); + format.d_->style.set("Normal"); wb.d_->has_file_version_ = true; wb.d_->file_version_.app_name = "Calc"; @@ -993,10 +993,32 @@ std::vector workbook::get_named_ranges() const format &workbook::create_format() { - register_stylesheet_in_manifest(); + register_stylesheet_in_manifest(); return d_->stylesheet_.create_format(); } +format &workbook::create_format(format pattern) +{ + register_stylesheet_in_manifest(); + + auto existing = d_->stylesheet_.find_format(pattern); + + if (existing.first) + { + return d_->stylesheet_.get_format(existing.second); + } + + auto &new_format = create_format(); + new_format.alignment(pattern.alignment(), pattern.alignment_applied()); + new_format.border(pattern.border(), pattern.border_applied()); + new_format.fill(pattern.fill(), pattern.fill_applied()); + new_format.font(pattern.font(), pattern.font_applied()); + new_format.number_format(pattern.number_format(), pattern.number_format_applied()); + new_format.protection(pattern.protection(), pattern.protection_applied());; + new_format.d_->style.set(pattern.d_->style.get()); + return new_format; +} + bool workbook::has_style(const std::string &name) const { return d_->stylesheet_.has_style(name); diff --git a/third-party/botan b/third-party/botan index dad94a55..73c2605f 160000 --- a/third-party/botan +++ b/third-party/botan @@ -1 +1 @@ -Subproject commit dad94a550613733d8c75b2fbd8db47048dfdaf13 +Subproject commit 73c2605f50e6192bf6cb560c51d32bc53b4c5597