refactor styles... again

This commit is contained in:
Thomas Fussell 2016-06-10 13:40:50 -04:00
parent 4e9c48eba9
commit 85e1b4a333
28 changed files with 912 additions and 954 deletions

View File

@ -38,7 +38,6 @@ enum class calendar;
class alignment;
class border;
class cell_reference;
class cell_style;
class comment;
class fill;
class font;
@ -46,6 +45,7 @@ class format;
class number_format;
class protection;
class relationship;
class style;
class workbook;
class worksheet;
@ -206,6 +206,26 @@ public:
void set_format(const format &new_format);
void clear_format();
// style
/// <summary>
/// Return true if this cell has had a format applied to it.
/// </summary>
bool has_style() const;
/// <summary>
/// Return a reference to the format applied to this cell.
/// </summary>
const style &get_style() const;
void set_style(const style &new_style);
void set_style(const std::string &style_name);
void clear_style();
/// <summary>
/// Return the number format of this cell.
/// </summary>

View File

@ -30,6 +30,7 @@
#include <xlnt/xlnt_config.hpp>
#include <xlnt/packaging/zip_file.hpp>
#include <detail/stylesheet.hpp>
namespace xlnt {
@ -94,6 +95,8 @@ public:
/// </summary>
bool save_stream_workbook(std::ostream &stream, bool as_template = false);
xlnt::detail::stylesheet &get_stylesheet();
private:
/// <summary>
/// Reads all files in archive and populates workbook with associated data

View File

@ -28,8 +28,6 @@
#include <vector>
#include <xlnt/xlnt_config.hpp>
#include <xlnt/styles/style.hpp>
#include <xlnt/workbook/workbook.hpp>
namespace xlnt {
@ -40,7 +38,7 @@ class conditional_format;
class fill;
class font;
class format;
class formattable;
class base_format;
class style;
class number_format;
class protection;
@ -49,8 +47,10 @@ class style;
class xml_document;
class xml_node;
namespace detail { struct stylesheet; }
/// <summary>
/// Reads and writes xl/styles.xml from/to an associated workbook.
/// Reads and writes xl/styles.xml from/to an associated stylesheet.
/// </summary>
class XLNT_CLASS style_serializer
{
@ -58,11 +58,7 @@ public:
/// <summary>
/// Construct a style_serializer which can write styles.xml based on wb or populate wb
/// with styles from an existing styles.xml.
style_serializer(workbook &wb);
//
// Primary methods
//
style_serializer(detail::stylesheet &s);
/// <summary>
/// Load all styles from xml_document into workbook given in constructor.
@ -73,204 +69,13 @@ public:
/// Populate parameter xml with an XML tree representing the styles contained in the workbook
/// given in the constructor.
/// </summary>
xml_document write_stylesheet();
// TODO: These need to be public for unit tests. Could also make test class a friend?
// private:
//
// Static element readers (i.e. readers that don't use internal state)
//
/// <summary>
/// Read and return an alignment from alignment_node.
/// </summary>
static alignment read_alignment(const xml_node &alignment_node);
/// <summary>
/// Read and return a border side from side_node.
/// </summary>
static side read_side(const xml_node &side_node);
/// <summary>
/// Read and return a border from border_node.
/// </summary>
static border read_border(const xml_node &border_node);
/// <summary>
/// Read and return a fill from fill_node.
/// </summary>
static fill read_fill(const xml_node &fill_node);
/// <summary>
/// Read and return a font from font_node.
/// </summary>
static font read_font(const xml_node &font_node);
/// <summary>
/// Read and return a number format from number_format_node.
/// </summary>
static number_format read_number_format(const xml_node &number_format_node);
/// <summary>
/// Read and return a protection from protection_node.
/// </summary>
static protection read_protection(const xml_node &protection_node);
/// <summary>
/// Read and return all indexed colors from indexed_colors_node.
/// </summary>
static std::vector<color> read_indexed_colors(const xml_node &indexed_colors_node);
/// <summary>
/// Read and return a color from color_node.
/// </summary>
static color read_color(const xml_node &color_node);
/// <summary>
/// Read and return a conditional format, dxf, from conditional_format_node.
/// </summary>
static conditional_format read_conditional_format(const xml_node &conditional_formats_node);
/// <summary>
/// Read a single format from the given node. In styles.xml, this is an "xf" element.
/// A format has an optional border id, fill id, font id, and number format id where
/// each id is an index in the corresponding list of borders, etc. A style also has
/// optional alignment and protection children. A style also defines whether each of
/// these is "applied". For example, a style with a defined font id, font=# but with
/// "applyFont=0" will not use the font in formatting.
/// </summary>
format read_format(const xml_node &format_node);
/// <summary>
/// Read a single named style from the given named_style_node. In styles.xml, this is a
/// (confusingly named) "cellStyle" element. This node defines the name, whether it is
/// built-in and an xfId which is the index of an element in cellStyleXfs. style_format_node
/// should be the XML node of the element at the index of xfId.
/// </summary>
style read_style(const xml_node &style_node, const xml_node &style_format_node);
//
// Non-static element readers (i.e. readers that modify internal state)
//
bool read_number_formats(const xml_node &number_formats_node);
/// <summary>
/// Read all borders from borders_node and add them to workbook.
/// Return true on success.
/// </summary>
bool read_borders(const xml_node &borders_node);
/// <summary>
/// Read all fills from fills_node and add them to workbook.
/// Return true on success.
/// </summary>
bool read_fills(const xml_node &fills_node);
/// <summary>
/// Read all fonts from fonts_node and add them to workbook.
/// Return true on success.
/// </summary>
bool read_fonts(const xml_node &fonts_node);
/// <summary>
/// Read all colors from colors_node and add them to workbook.
/// Return true on success.
/// </summary>
bool read_colors(const xml_node &colors_node);
/// <summary>
/// Read all cell styles from cell_styles_node and add them to workbook.
/// Return true on success.
/// </summary>
bool read_formats(const xml_node &formats_node);
/// <summary>
/// Read all named styles from named_style_node and cell_styles_node and add them to workbook.
/// Return true on success.
/// </summary>
bool read_styles(const xml_node &styles_node, const xml_node &style_formats_node);
/// <summary>
/// Read all borders from number_formats_node and add them to workbook.
/// Return true on success.
/// </summary>
bool read_stylesheet(const xml_node &number_formats_node);
//
// Non-static element writers (i.e. writers that modify internal workbook)
//
/// <summary>
/// Build an xml tree representing all borders in workbook into borders_node.
/// Returns true on success.
/// </summary>
bool write_borders(xml_node &borders_node) const;
/// <summary>
/// Build an xml tree representing all conditional formats in workbook into conditional_formats_node.
/// Returns true on success.
/// </summary>
bool write_conditional_formats(xml_node &conditional_formats_node) const;
/// <summary>
/// Build an xml tree representing all fills in workbook into fills_node.
/// Returns true on success.
/// </summary>
bool write_fills(xml_node &fills_node) const;
/// <summary>
/// Build an xml tree representing all fonts in workbook into fonts_node.
/// Returns true on success.
/// </summary>
bool write_fonts(xml_node &fonts_node) const;
/// <summary>
/// Build an xml tree representing all number formats in workbook into number_formats_node.
/// Returns true on success.
/// </summary>
bool write_number_formats(xml_node &number_formats_node) const;
bool write_formattable(const formattable &xf, xml_node xf_node) const;
/// <summary>
/// Build an xml tree representing the given style into style_node.
/// Returns true on success.
/// </summary>
bool write_formats(xml_node &styles_node) const;
bool write_styles(xml_node &cell_styles_node, xml_node &cell_style_formats_node) const;
bool write_colors(xml_node &colors_node) const;
bool write_ext_list(xml_node &ext_list_node) const;
const std::vector<border> &get_borders() const;
const std::vector<fill> &get_fills() const;
const std::vector<font> &get_fonts() const;
const std::vector<number_format> &get_number_formats() const;
const std::vector<color> &get_colors() const;
bool write_stylesheet(xml_document &xml);
private:
void initialize_vectors();
/// <summary>
/// Set in the constructor, this workbook is used as the source or target for all writing or reading, respectively.
/// Set in the constructor, this stylesheet is used as the source or target for all writing or reading, respectively.
/// </summary>
workbook &workbook_;
std::vector<color> colors_;
std::vector<border> borders_;
std::vector<fill> fills_;
std::vector<font> fonts_;
std::vector<number_format> number_formats_;
std::vector<format> formats_;
std::vector<style> styles_;
detail::stylesheet &stylesheet_;
};
} // namespace xlnt

View File

@ -36,6 +36,8 @@ class workbook;
class worksheet;
class xml_document;
namespace detail { struct stylesheet; }
/// <summary>
/// Manages converting a worksheet to and from XML.
/// </summary>
@ -44,7 +46,7 @@ class XLNT_CLASS worksheet_serializer
public:
worksheet_serializer(worksheet sheet);
bool read_worksheet(const xml_document &xml);
bool read_worksheet(const xml_document &xml, detail::stylesheet &stylesheet);
xml_document write_worksheet() const;
private:

View File

@ -38,12 +38,12 @@ class cell;
/// <summary>
/// Describes the formatting of a particular cell.
/// </summary>
class XLNT_CLASS formattable : public hashable
class XLNT_CLASS base_format : public hashable
{
public:
formattable();
formattable(const formattable &other);
formattable &operator=(const formattable &other);
base_format();
base_format(const base_format &other);
base_format &operator=(const base_format &other);
void reset();

View File

@ -72,6 +72,8 @@ public:
mediumgray,
};
fill();
type get_type() const;
void set_type(type t);
@ -122,21 +124,21 @@ protected:
std::string to_hash_string() const override;
private:
type type_ = type::pattern;
pattern_type pattern_type_ = pattern_type::none;
type type_;
pattern_type pattern_type_;
gradient_type gradient_type_;
double rotation_ = 0;
double rotation_;
std::experimental::optional<color> foreground_color_ = color::black();
std::experimental::optional<color> background_color_ = color::white();
std::experimental::optional<color> start_color_ = color::white();
std::experimental::optional<color> end_color_ = color::black();
std::experimental::optional<color> foreground_color_;
std::experimental::optional<color> background_color_;
std::experimental::optional<color> start_color_;
std::experimental::optional<color> end_color_;
double gradient_path_left_ = 0;
double gradient_path_right_ = 0;
double gradient_path_top_ = 0;
double gradient_path_bottom_ = 0;
double gradient_path_left_;
double gradient_path_right_;
double gradient_path_top_;
double gradient_path_bottom_;
};
} // namespace xlnt

View File

@ -48,6 +48,8 @@ public:
single_accounting
};
font();
void set_bold(bool bold);
bool is_bold() const;

View File

@ -23,7 +23,7 @@
// @author: see AUTHORS file
#pragma once
#include <xlnt/styles/formattable.hpp>
#include <xlnt/styles/base_format.hpp>
namespace xlnt {
@ -33,28 +33,15 @@ namespace detail { struct workbook_impl; }
/// <summary>
/// Describes the formatting of a particular cell.
/// </summary>
class XLNT_CLASS format : public formattable
class XLNT_CLASS format : public base_format
{
public:
format();
format(const format &other);
format &operator=(const format &other);
// Named Style
bool has_style() const;
std::string get_style_name() const;
style &get_style();
const style &get_style() const;
void set_style(const std::string &name);
void set_style(const style &new_style);
void remove_style();
protected:
std::string to_hash_string() const override;
private:
detail::workbook_impl *parent_;
std::string named_style_name_;
};
} // namespace xlnt

View File

@ -26,7 +26,7 @@
#include <cstdint>
#include <string>
#include <xlnt/styles/formattable.hpp>
#include <xlnt/styles/base_format.hpp>
namespace xlnt {
@ -36,7 +36,7 @@ class workbook;
/// Describes a style which has a name and can be applied to multiple individual
/// formats. In Excel this is a "Cell Style".
/// </summary>
class XLNT_CLASS style : public formattable
class XLNT_CLASS style : public base_format
{
public:
style();

View File

@ -23,6 +23,7 @@
// @author: see AUTHORS file
#pragma once
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
@ -32,11 +33,14 @@
#include <xlnt/xlnt_config.hpp>
#include <xlnt/packaging/relationship.hpp>
namespace CxxTest { class TestSuite; }
namespace xlnt {
class alignment;
class app_properties;
class border;
class cell;
class cell_style;
class color;
class const_worksheet_iterator;
@ -193,10 +197,12 @@ public:
const std::vector<format> &get_formats() const;
// Named Styles
bool has_style(const std::string &name);
bool has_style(const std::string &name) const;
style &get_style(const std::string &name);
const style &get_style(const std::string &name) const;
std::size_t get_style_id(const std::string &name) const;
style &create_style(const std::string &name);
std::size_t add_style(const style &new_style);
void clear_styles();
const std::vector<style> &get_styles() const;
@ -214,10 +220,11 @@ public:
const std::vector<std::uint8_t> &get_thumbnail() const;
private:
friend class excel_serializer;
friend class worksheet;
friend class style_serializer;
std::string next_relationship_id() const;
void apply_to_cells(std::function<void(cell)> f);
std::unique_ptr<detail::workbook_impl> d_;
};

View File

@ -238,6 +238,8 @@ private:
friend class range_iterator;
friend class const_range_iterator;
std::size_t next_custom_number_format_id();
worksheet(detail::worksheet_impl *d);
detail::worksheet_impl *d_;
};

View File

@ -31,8 +31,9 @@
#include <xlnt/packaging/document_properties.hpp>
#include <xlnt/packaging/relationship.hpp>
#include <xlnt/serialization/encoding.hpp>
#include <xlnt/styles/format.hpp>
#include <xlnt/styles/color.hpp>
#include <xlnt/styles/format.hpp>
#include <xlnt/styles/style.hpp>
#include <xlnt/utils/date.hpp>
#include <xlnt/utils/datetime.hpp>
#include <xlnt/utils/time.hpp>
@ -906,10 +907,24 @@ void cell::set_font(const font &font_)
void cell::set_number_format(const number_format &number_format_)
{
format new_format;
if (d_->has_format_)
{
new_format = get_workbook().get_format(d_->format_id_);
}
auto number_format_with_id = number_format_;
if (!number_format_with_id.has_id())
{
number_format_with_id.set_id(get_worksheet().next_custom_number_format_id());
}
new_format.set_number_format(number_format_with_id);
d_->has_format_ = true;
auto format_copy = get_workbook().get_format(d_->format_id_);
format_copy.set_number_format(number_format_);
d_->format_id_ = get_workbook().add_format(format_copy);
d_->format_id_ = get_workbook().add_format(new_format);
}
void cell::set_alignment(const xlnt::alignment &alignment_)
@ -1030,4 +1045,42 @@ void cell::guess_type_and_set_value(const std::string &value)
}
}
void cell::clear_format()
{
d_->format_id_ = 0;
d_->has_format_ = false;
}
void cell::clear_style()
{
d_->style_id_ = 0;
d_->has_style_ = false;
}
void cell::set_style(const style &new_style)
{
d_->has_style_ = true;
if (get_workbook().has_style(new_style.get_name()))
{
d_->style_id_ = get_workbook().get_style_id(new_style.get_name());
}
else
{
d_->style_id_ = get_workbook().add_style(new_style);
}
}
void cell::set_style(const std::string &style_name)
{
d_->has_style_ = true;
if (!get_workbook().has_style(style_name))
{
throw std::runtime_error("style " + style_name + " doesn't exist in workbook");
}
d_->style_id_ = get_workbook().get_style_id(style_name);
}
} // namespace xlnt

View File

@ -73,6 +73,9 @@ struct cell_impl
bool has_format_;
std::size_t format_id_;
bool has_style_;
std::size_t style_id_;
std::unique_ptr<comment_impl> comment_;
};

View File

@ -0,0 +1,172 @@
// 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 <string>
#include <unordered_map>
#include <vector>
#include <xlnt/styles/border.hpp>
#include <xlnt/styles/fill.hpp>
#include <xlnt/styles/font.hpp>
#include <xlnt/styles/format.hpp>
#include <xlnt/styles/number_format.hpp>
#include <xlnt/styles/style.hpp>
namespace {
template<typename T>
std::size_t search_vector(const std::vector<T> &items, const T &to_find)
{
auto match = std::find(items.begin(), items.end(), to_find);
if (match == items.end())
{
throw std::out_of_range("xlnt::stylesheet index lookup");
}
return std::distance(items.begin(), match);
}
} // namespace
namespace xlnt {
namespace detail {
struct stylesheet
{
~stylesheet() {}
std::size_t index(const format &f) { return search_vector(formats, f); }
std::size_t index(const std::string &style_name)
{
auto match = std::find_if(styles.begin(), styles.end(),
[&](const style &s) { return s.get_name() == style_name; });
if (match == styles.end())
{
throw std::out_of_range("xlnt::stylesheet style index lookup");
}
return std::distance(styles.begin(), match);
}
std::size_t index(const border &b) { return search_vector(borders, b); }
std::size_t index(const fill &f) { return search_vector(fills, f); }
std::size_t index(const font &f) { return search_vector(fonts, f); }
std::size_t index(const number_format &f) { return search_vector(number_formats, f); }
std::size_t add_format(const format &f)
{
auto match = std::find(formats.begin(), formats.end(), f);
if (match != formats.end())
{
return std::distance(formats.begin(), match);
}
auto number_format_match = std::find_if(number_formats.begin(), number_formats.end(), [&](const number_format &nf) { return nf.get_format_string() == f.get_number_format().get_format_string(); });
if (number_format_match == number_formats.end() && f.get_number_format().get_id() >= 164)
{
number_formats.push_back(f.get_number_format());
}
formats.push_back(f);
format_styles.push_back("");
try
{
search_vector(borders, f.get_border());
}
catch(std::out_of_range)
{
borders.push_back(f.get_border());
}
try
{
search_vector(fills, f.get_fill());
}
catch(std::out_of_range)
{
fills.push_back(f.get_fill());
}
try
{
search_vector(fonts, f.get_font());
}
catch(std::out_of_range)
{
fonts.push_back(f.get_font());
}
if (f.get_number_format().get_id() >= 164)
{
try
{
search_vector(number_formats, f.get_number_format());
}
catch(std::out_of_range)
{
number_formats.push_back(f.get_number_format());
}
}
return formats.size() - 1;
}
std::size_t add_style(const style &s)
{
auto match = std::find(styles.begin(), styles.end(), s);
if (match != styles.end())
{
return std::distance(styles.begin(), match);
}
styles.push_back(s);
return styles.size() - 1;
}
std::vector<format> formats;
std::vector<std::string> format_styles;
std::vector<style> styles;
std::vector<border> borders;
std::vector<fill> fills;
std::vector<font> fonts;
std::vector<number_format> number_formats;
std::vector<color> colors;
std::unordered_map<std::size_t, std::string> style_name_map;
std::size_t next_custom_format_id = 164;
};
} // namespace detail
} // namespace xlnt

View File

@ -25,7 +25,9 @@
#include <iterator>
#include <vector>
#include <detail/stylesheet.hpp>
#include <detail/worksheet_impl.hpp>
#include <xlnt/serialization/encoding.hpp>
#include <xlnt/packaging/app_properties.hpp>
#include <xlnt/packaging/document_properties.hpp>
#include <xlnt/packaging/manifest.hpp>
@ -54,8 +56,7 @@ struct workbook_impl
guess_types_(other.guess_types_),
data_only_(other.data_only_),
read_only_(other.read_only_),
formats_(other.formats_),
styles_(other.styles_),
stylesheet_(other.stylesheet_),
manifest_(other.manifest_)
{
}
@ -95,9 +96,7 @@ struct workbook_impl
bool data_only_;
bool read_only_;
std::vector<format> formats_;
std::vector<style> styles_;
std::size_t next_custom_format_id_;
stylesheet stylesheet_;
manifest manifest_;
theme theme_;

View File

@ -47,6 +47,8 @@
#include <xlnt/worksheet/worksheet.hpp>
#include <detail/constants.hpp>
#include <detail/stylesheet.hpp>
#include <detail/workbook_impl.hpp>
namespace {
@ -144,10 +146,11 @@ bool load_workbook(xlnt::zip_file &archive, bool guess_types, bool data_only, xl
}
}
xlnt::style_serializer style_reader_(wb);
xlnt::detail::stylesheet stylesheet;
xlnt::style_serializer style_serializer(stylesheet);
xlnt::xml_document style_xml;
style_xml.from_string(archive.read(xlnt::constants::ArcStyles()));
style_reader_.read_stylesheet(style_xml);
style_serializer.read_stylesheet(style_xml);
auto sheets_node = root_node.get_child("sheets");
@ -169,7 +172,7 @@ bool load_workbook(xlnt::zip_file &archive, bool guess_types, bool data_only, xl
xlnt::worksheet_serializer worksheet_serializer(ws);
xlnt::xml_document worksheet_xml;
worksheet_xml.from_string(archive.read(ws_filename));
worksheet_serializer.read_worksheet(worksheet_xml);
worksheet_serializer.read_worksheet(worksheet_xml, stylesheet);
}
if (archive.has_file("docProps/thumbnail.jpeg"))
@ -264,8 +267,10 @@ void excel_serializer::write_data(bool /*as_template*/)
archive_.writestr(constants::ArcWorkbook(), xml_serializer::serialize(workbook_serializer_.write_workbook()));
style_serializer style_serializer_(workbook_);
archive_.writestr(constants::ArcStyles(), style_serializer_.write_stylesheet().to_string());
style_serializer style_serializer(workbook_.d_->stylesheet_);
xlnt::xml_document style_xml;
style_serializer.write_stylesheet(style_xml);
archive_.writestr(constants::ArcStyles(), style_xml.to_string());
manifest_serializer manifest_serializer_(workbook_.get_manifest());
archive_.writestr(constants::ArcContentTypes(), manifest_serializer_.write_manifest().to_string());
@ -329,4 +334,9 @@ bool excel_serializer::save_virtual_workbook(std::vector<std::uint8_t> &bytes, b
return true;
}
detail::stylesheet &excel_serializer::get_stylesheet()
{
return workbook_.d_->stylesheet_;
}
} // namespace xlnt

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,8 @@
#include <cxxtest/TestSuite.h>
#include <xlnt/serialization/style_serializer.hpp>
#include <detail/stylesheet.hpp>
#include <detail/workbook_impl.hpp>
class test_style_writer : public CxxTest::TestSuite
{
@ -12,15 +14,17 @@ public:
{
xlnt::workbook wb;
wb.get_active_sheet().get_cell("A1").set_number_format(xlnt::number_format("YYYY"));
xlnt::style_serializer writer(wb);
xlnt::excel_serializer excel_serializer(wb);
xlnt::style_serializer style_serializer(excel_serializer.get_stylesheet());
xlnt::xml_document observed;
auto num_fmts_node = observed.add_child("numFmts");
writer.write_number_formats(num_fmts_node);
style_serializer.write_stylesheet(observed);
xlnt::xml_document expected_doc;
std::string expected =
" <numFmts count=\"1\">"
" <numFmt formatCode=\"YYYY\" numFmtId=\"164\"></numFmt>"
" </numFmts>";
auto diff = Helper::compare_xml(expected, observed);
expected_doc.from_string(expected);
auto diff = Helper::compare_xml(expected_doc.get_child("numFmts"), observed.get_child("styleSheet").get_child("numFmts"));
TS_ASSERT(diff);
}
/*

View File

@ -40,6 +40,7 @@
#include <xlnt/worksheet/row_properties.hpp>
#include <detail/constants.hpp>
#include <detail/stylesheet.hpp>
namespace {
@ -56,7 +57,7 @@ worksheet_serializer::worksheet_serializer(worksheet sheet) : sheet_(sheet)
{
}
bool worksheet_serializer::read_worksheet(const xml_document &xml)
bool worksheet_serializer::read_worksheet(const xml_document &xml, detail::stylesheet &stylesheet)
{
auto &root_node = xml.get_child("worksheet");
@ -198,7 +199,7 @@ bool worksheet_serializer::read_worksheet(const xml_document &xml)
if (has_format)
{
cell.set_format(sheet_.get_workbook().get_format(format_id));
cell.set_format(stylesheet.formats.at(format_id));
}
}
}

View File

@ -21,11 +21,11 @@
//
// @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file
#include <xlnt/styles/formattable.hpp>
#include <xlnt/styles/base_format.hpp>
namespace xlnt {
formattable::formattable()
base_format::base_format()
: apply_alignment_(false),
apply_border_(false),
apply_fill_(false),
@ -35,7 +35,7 @@ formattable::formattable()
{
}
formattable::formattable(const formattable &other)
base_format::base_format(const base_format &other)
: alignment_(other.alignment_),
border_(other.border_),
fill_(other.fill_),
@ -51,7 +51,7 @@ formattable::formattable(const formattable &other)
{
}
formattable &formattable::operator=(const xlnt::formattable &other)
base_format &base_format::operator=(const xlnt::base_format &other)
{
alignment_ = other.alignment_;
border_ = other.border_;
@ -70,105 +70,105 @@ formattable &formattable::operator=(const xlnt::formattable &other)
return *this;
}
alignment &formattable::get_alignment()
alignment &base_format::get_alignment()
{
return alignment_;
}
const alignment &formattable::get_alignment() const
const alignment &base_format::get_alignment() const
{
return alignment_;
}
void formattable::set_alignment(const xlnt::alignment &new_alignment)
void base_format::set_alignment(const xlnt::alignment &new_alignment)
{
alignment_ = new_alignment;
alignment_applied(true);
}
number_format &formattable::get_number_format()
number_format &base_format::get_number_format()
{
return number_format_;
}
const number_format &formattable::get_number_format() const
const number_format &base_format::get_number_format() const
{
return number_format_;
}
void formattable::set_number_format(const xlnt::number_format &new_number_format)
void base_format::set_number_format(const xlnt::number_format &new_number_format)
{
number_format_ = new_number_format;
number_format_applied(true);
}
border &formattable::get_border()
border &base_format::get_border()
{
return border_;
}
const border &formattable::get_border() const
const border &base_format::get_border() const
{
return border_;
}
void formattable::set_border(const xlnt::border &new_border)
void base_format::set_border(const xlnt::border &new_border)
{
border_ = new_border;
border_applied(true);
}
fill &formattable::get_fill()
fill &base_format::get_fill()
{
return fill_;
}
const fill &formattable::get_fill() const
const fill &base_format::get_fill() const
{
return fill_;
}
void formattable::set_fill(const xlnt::fill &new_fill)
void base_format::set_fill(const xlnt::fill &new_fill)
{
fill_ = new_fill;
fill_applied(true);
}
font &formattable::get_font()
font &base_format::get_font()
{
return font_;
}
const font &formattable::get_font() const
const font &base_format::get_font() const
{
return font_;
}
void formattable::set_font(const xlnt::font &new_font)
void base_format::set_font(const xlnt::font &new_font)
{
font_ = new_font;
font_applied(true);
}
protection &formattable::get_protection()
protection &base_format::get_protection()
{
return protection_;
}
const protection &formattable::get_protection() const
const protection &base_format::get_protection() const
{
return protection_;
}
void formattable::set_protection(const xlnt::protection &new_protection)
void base_format::set_protection(const xlnt::protection &new_protection)
{
protection_ = new_protection;
protection_applied(true);
}
std::string formattable::to_hash_string() const
std::string base_format::to_hash_string() const
{
std::string hash_string("formattable:");
std::string hash_string("base_format:");
hash_string.append(std::to_string(alignment_applied()));
hash_string.append(alignment_applied() ? std::to_string(alignment_.hash()) : ":");
@ -191,62 +191,62 @@ std::string formattable::to_hash_string() const
return hash_string;
}
void formattable::alignment_applied(bool applied)
void base_format::alignment_applied(bool applied)
{
apply_alignment_ = applied;
}
void formattable::border_applied(bool applied)
void base_format::border_applied(bool applied)
{
apply_border_ = applied;
}
void formattable::fill_applied(bool applied)
void base_format::fill_applied(bool applied)
{
apply_fill_ = applied;
}
void formattable::font_applied(bool applied)
void base_format::font_applied(bool applied)
{
apply_font_ = applied;
}
void formattable::number_format_applied(bool applied)
void base_format::number_format_applied(bool applied)
{
apply_number_format_ = applied;
}
void formattable::protection_applied(bool applied)
void base_format::protection_applied(bool applied)
{
apply_protection_ = applied;
}
bool formattable::alignment_applied() const
bool base_format::alignment_applied() const
{
return apply_alignment_;
}
bool formattable::border_applied() const
bool base_format::border_applied() const
{
return apply_border_;
}
bool formattable::fill_applied() const
bool base_format::fill_applied() const
{
return apply_fill_;
}
bool formattable::font_applied() const
bool base_format::font_applied() const
{
return apply_font_;
}
bool formattable::number_format_applied() const
bool base_format::number_format_applied() const
{
return apply_number_format_;
}
bool formattable::protection_applied() const
bool base_format::protection_applied() const
{
return apply_protection_;
}

View File

@ -26,6 +26,18 @@
namespace xlnt {
fill::fill()
: type_(type::pattern),
pattern_type_(pattern_type::none),
gradient_type_(gradient_type::linear),
rotation_(0),
gradient_path_left_(0),
gradient_path_right_(0),
gradient_path_top_(0),
gradient_path_bottom_(0)
{
}
fill::type fill::get_type() const
{
return type_;

View File

@ -26,6 +26,24 @@
namespace xlnt {
font::font()
: name_("Calibri"),
size_(12),
bold_(false),
italic_(false),
superscript_(false),
subscript_(false),
underline_(underline_style::none),
strikethrough_(false),
color_(xlnt::color::type::theme, 1),
has_family_(true),
family_(2),
has_scheme_(true),
scheme_("minor")
{
}
void font::set_bold(bool bold)
{
bold_ = bold;

View File

@ -31,60 +31,27 @@
namespace xlnt {
format::format()
: formattable(),
parent_(nullptr),
named_style_name_("Normal")
format::format() : base_format()
{
}
format::format(const format &other)
: formattable(other),
parent_(other.parent_),
named_style_name_(other.named_style_name_)
format::format(const format &other) : base_format(other)
{
}
format &format::operator=(const format &other)
{
formattable::operator=(other);
parent_ = other.parent_;
named_style_name_ = other.named_style_name_;
base_format::operator=(other);
return *this;
}
std::string format::to_hash_string() const
{
auto hash_string = formattable::to_hash_string();
auto hash_string = base_format::to_hash_string();
hash_string.append(":format:");
if (!named_style_name_.empty())
{
hash_string.append(named_style_name_);
}
else
{
hash_string.append(":");
}
return hash_string;
}
void format::set_style(const std::string &style_name)
{
named_style_name_ = style_name;
}
bool format::has_style() const
{
return !named_style_name_.empty();
}
std::string format::get_style_name() const
{
return named_style_name_;
}
} // namespace xlnt

View File

@ -70,7 +70,7 @@ const std::unordered_map<std::size_t, std::string> &builtin_formats()
{ 42, "_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"_);_(@_)" },
{ 43, "_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)" },
{ 44, "_(\"$\"* #,##0.00_)_(\"$\"* \\(#,##0.00\\)_(\"$\"* \"-\"??_)_(@_)" },
{ 44, "_-\"$\"* #,##0.00_-;\\-\"$\"* #,##0.00_-;_-\"$\"* \"-\"??_-;_-@_-" },
{ 45, "mm:ss" },
{ 46, "[h]:mm:ss" },
{ 47, "mmss.0" },

View File

@ -27,14 +27,14 @@
namespace xlnt {
style::style()
: formattable(),
: base_format(),
hidden_(false),
builtin_id_(0)
{
}
style::style(const style &other)
: formattable(other),
: base_format(other),
name_(other.name_),
hidden_(other.hidden_),
builtin_id_(other.builtin_id_)
@ -43,7 +43,7 @@ style::style(const style &other)
style &style::operator=(const style &other)
{
formattable::operator=(other);
base_format::operator=(other);
name_ = other.name_;
hidden_ = other.hidden_;
@ -84,7 +84,7 @@ void style::set_name(const std::string &name)
std::string style::to_hash_string() const
{
return formattable::to_hash_string() + name_;
return base_format::to_hash_string() + name_;
}
} // namespace xlnt

View File

@ -15,9 +15,12 @@ public:
void test_ctor()
{
xlnt::workbook wb;
xlnt::style_serializer style_serializer(wb);
xlnt::excel_serializer excel_serializer(wb);
xlnt::style_serializer style_serializer(excel_serializer.get_stylesheet());
xlnt::zip_file archive;
auto stylesheet_xml = style_serializer.write_stylesheet().to_string();
xlnt::xml_document stylesheet_doc;
style_serializer.write_stylesheet(stylesheet_doc);
auto stylesheet_xml = stylesheet_doc.to_string();
const std::string expected =
"<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" xmlns:x14ac=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac\" mc:Ignorable=\"x14ac\">"
@ -72,9 +75,10 @@ public:
auto xml = PathHelper::read_file(PathHelper::GetDataDirectory("/reader/styles/simple-styles.xml"));
doc.from_string(xml);
xlnt::workbook wb;
xlnt::style_serializer s(wb);
xlnt::excel_serializer e(wb);
xlnt::style_serializer s(e.get_stylesheet());
TS_ASSERT(s.read_stylesheet(doc));
TS_ASSERT_EQUALS(s.get_number_formats().size(), 1);
TS_ASSERT_EQUALS(e.get_stylesheet().number_formats.size(), 1);
}
void test_from_complex()
@ -83,12 +87,13 @@ public:
auto xml = PathHelper::read_file(PathHelper::GetDataDirectory("/reader/styles/complex-styles.xml"));
doc.from_string(xml);
xlnt::workbook wb;
xlnt::style_serializer s(wb);
xlnt::excel_serializer e(wb);
xlnt::style_serializer s(e.get_stylesheet());
TS_ASSERT(s.read_stylesheet(doc));
TS_ASSERT_EQUALS(s.get_borders().size(), 7);
TS_ASSERT_EQUALS(s.get_fills().size(), 6);
TS_ASSERT_EQUALS(s.get_fonts().size(), 8);
TS_ASSERT_EQUALS(s.get_number_formats().size(), 1);
TS_ASSERT_EQUALS(e.get_stylesheet().borders.size(), 7);
TS_ASSERT_EQUALS(e.get_stylesheet().fills.size(), 6);
TS_ASSERT_EQUALS(e.get_stylesheet().fonts.size(), 8);
TS_ASSERT_EQUALS(e.get_stylesheet().number_formats.size(), 0);
}
/*

View File

@ -24,6 +24,7 @@
#include <algorithm>
#include <array>
#include <fstream>
#include <functional>
#include <set>
#include <sstream>
@ -60,7 +61,10 @@ namespace xlnt {
namespace detail {
workbook_impl::workbook_impl()
: active_sheet_index_(0), guess_types_(false), data_only_(false), read_only_(false), next_custom_format_id_(164)
: active_sheet_index_(0),
guess_types_(false),
data_only_(false),
read_only_(false)
{
}
@ -86,6 +90,7 @@ workbook::workbook() : d_(new detail::workbook_impl())
add_format(format());
create_style("Normal");
d_->stylesheet_.format_styles.front() = "Normal";
}
workbook::workbook(encoding e) : workbook()
@ -555,11 +560,6 @@ workbook::~workbook()
{
}
const std::vector<style> &workbook::get_styles() const
{
return d_->styles_;
}
bool workbook::get_data_only() const
{
return d_->data_only_;
@ -609,65 +609,63 @@ std::vector<named_range> workbook::get_named_ranges() const
return named_ranges;
}
std::size_t workbook::add_format(const format &style)
std::size_t workbook::add_format(const format &to_add)
{
auto format_copy = style;
return d_->stylesheet_.add_format(to_add);
}
//TODO this is ugly
if (!style.get_number_format().has_id())
{
bool match = false;
std::size_t workbook::add_style(const style &to_add)
{
return d_->stylesheet_.add_style(to_add);
}
for (std::size_t i = 0; i < d_->formats_.size(); i++)
{
const auto &current_number_format = d_->formats_.at(i).get_number_format();
bool workbook::has_style(const std::string &name) const
{
return std::find_if(d_->stylesheet_.styles.begin(), d_->stylesheet_.styles.end(),
[&](const style &s) { return s.get_name() == name; }) != d_->stylesheet_.styles.end();
}
if (current_number_format.get_format_string() == format_copy.get_number_format().get_format_string())
{
format_copy.set_number_format(current_number_format);
match = true;
break;
}
}
if (!match)
{
format_copy.get_number_format().set_id(d_->next_custom_format_id_++);
}
}
// TODO hashmap?
for (std::size_t i = 0; i < d_->formats_.size(); i++)
{
if (d_->formats_[i] == format_copy)
{
return i;
}
}
d_->formats_.push_back(format_copy);
return d_->formats_.size() - 1;
std::size_t workbook::get_style_id(const std::string &name) const
{
return std::distance(d_->stylesheet_.styles.begin(),
std::find_if(d_->stylesheet_.styles.begin(), d_->stylesheet_.styles.end(),
[&](const style &s) { return s.get_name() == name; }));
}
void workbook::clear_styles()
{
d_->styles_.clear();
d_->stylesheet_.styles.clear();
apply_to_cells([](cell c) { c.clear_style(); });
}
void workbook::clear_formats()
{
d_->formats_.clear();
d_->stylesheet_.formats.clear();
apply_to_cells([](cell c) { c.clear_format(); });
}
void workbook::apply_to_cells(std::function<void(cell)> f)
{
for (auto ws : *this)
{
for (auto r : ws.iter_cells(true))
{
for (auto c : r)
{
f.operator()(c);
}
}
}
}
format &workbook::get_format(std::size_t format_index)
{
return d_->formats_.at(format_index);
return d_->stylesheet_.formats.at(format_index);
}
const format &workbook::get_format(std::size_t format_index) const
{
return d_->formats_.at(format_index);
return d_->stylesheet_.formats.at(format_index);
}
manifest &workbook::get_manifest()
@ -749,30 +747,30 @@ style &workbook::create_style(const std::string &name)
style style;
style.set_name(name);
d_->styles_.push_back(style);
d_->stylesheet_.styles.push_back(style);
return d_->styles_.back();
return d_->stylesheet_.styles.back();
}
std::vector<format> &workbook::get_formats()
{
return d_->formats_;
return d_->stylesheet_.formats;
}
const std::vector<format> &workbook::get_formats() const
{
return d_->formats_;
return d_->stylesheet_.formats;
}
style &workbook::get_style(const std::string &name)
{
return *std::find_if(d_->styles_.begin(), d_->styles_.end(),
return *std::find_if(d_->stylesheet_.styles.begin(), d_->stylesheet_.styles.end(),
[&name](const style &s) { return s.get_name() == name; });
}
const style &workbook::get_style(const std::string &name) const
{
return *std::find_if(d_->styles_.begin(), d_->styles_.end(),
return *std::find_if(d_->stylesheet_.styles.begin(), d_->stylesheet_.styles.end(),
[&name](const style &s) { return s.get_name() == name; });
}

View File

@ -43,6 +43,7 @@
#include <detail/cell_impl.hpp>
#include <detail/constants.hpp>
#include <detail/workbook_impl.hpp>
#include <detail/worksheet_impl.hpp>
namespace xlnt {
@ -995,4 +996,9 @@ sheet_view worksheet::get_sheet_view() const
return d_->view_;
}
std::size_t worksheet::next_custom_number_format_id()
{
return get_workbook().d_->stylesheet_.next_custom_format_id++;
}
} // namespace xlnt