work on round-tripping of a workbook with complex formatting

This commit is contained in:
Thomas Fussell 2016-03-10 17:12:51 +08:00
parent 1c6c36d1a0
commit 5a9c18834d
15 changed files with 830 additions and 381 deletions

View File

@ -38,6 +38,7 @@ class color;
class conditional_format;
class fill;
class font;
class format;
class named_style;
class number_format;
class protection;
@ -219,6 +220,16 @@ public:
/// </summary>
bool read_number_formats(const xml_node &number_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 style from the given node. In styles.xml, this is an "xf" element.
/// A style has an optional border id, fill id, font id, and number format id where

View File

@ -32,7 +32,7 @@
namespace xlnt {
/// <summary>
/// Alignment options for use in styles.
/// Alignment options for use in cell formats.
/// </summary>
class XLNT_CLASS alignment : public hashable
{
@ -53,6 +53,10 @@ public:
void set_vertical(vertical_alignment vertical);
void set_shrink_to_fit(bool shrink_to_fit);
bool get_shrink_to_fit() const;
protected:
std::string to_hash_string() const override;

View File

@ -0,0 +1,107 @@
// 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 <xlnt/xlnt_config.hpp>
#include <xlnt/styles/alignment.hpp>
#include <xlnt/styles/border.hpp>
#include <xlnt/styles/fill.hpp>
#include <xlnt/styles/font.hpp>
#include <xlnt/styles/number_format.hpp>
#include <xlnt/styles/protection.hpp>
namespace xlnt {
class workbook;
/// <summary>
/// Describes the entirety of the formatting of a particular cell.
/// </summary>
class XLNT_CLASS format : public hashable
{
public:
format();
format(const format &other);
format &operator=(const format &other);
std::size_t hash() const;
const alignment get_alignment() const;
const border get_border() const;
const fill get_fill() const;
const font get_font() const;
const number_format get_number_format() const;
const protection get_protection() const;
bool pivot_button() const;
bool quote_prefix() const;
std::size_t get_id() const;
std::size_t get_fill_id() const;
std::size_t get_font_id() const;
std::size_t get_border_id() const;
std::size_t get_number_format_id() const;
void apply_alignment(bool apply);
void apply_border(bool apply);
void apply_fill(bool apply);
void apply_font(bool apply);
void apply_number_format(bool apply);
void apply_protection(bool apply);
protected:
std::string to_hash_string() const override;
private:
friend class style_serializer;
friend class workbook;
std::size_t id_;
bool alignment_apply_;
alignment alignment_;
bool border_apply_;
std::size_t border_id_;
border border_;
bool fill_apply_;
std::size_t fill_id_;
fill fill_;
bool font_apply_;
std::size_t font_id_;
font font_;
bool number_format_apply_;
std::size_t number_format_id_;
number_format number_format_;
bool protection_apply_;
protection protection_;
bool pivot_button_;
bool quote_prefix_;
};
} // namespace xlnt

View File

@ -24,12 +24,7 @@
#pragma once
#include <xlnt/xlnt_config.hpp>
#include <xlnt/styles/alignment.hpp>
#include <xlnt/styles/border.hpp>
#include <xlnt/styles/fill.hpp>
#include <xlnt/styles/font.hpp>
#include <xlnt/styles/number_format.hpp>
#include <xlnt/styles/protection.hpp>
#include <xlnt/utils/hashable.hpp>
namespace xlnt {
@ -47,61 +42,28 @@ public:
std::size_t hash() const;
const alignment get_alignment() const;
const border get_border() const;
const fill get_fill() const;
const font get_font() const;
const number_format get_number_format() const;
const protection get_protection() const;
bool pivot_button() const;
bool quote_prefix() const;
std::string get_name() const;
void set_name(const std::string &name);
std::size_t get_id() const;
std::size_t get_fill_id() const;
std::size_t get_font_id() const;
std::size_t get_border_id() const;
std::size_t get_number_format_id() const;
std::size_t get_format_id() const;
void set_format_id(std::size_t format_id);
void apply_alignment(bool apply);
void apply_border(bool apply);
void apply_fill(bool apply);
void apply_font(bool apply);
void apply_number_format(bool apply);
void apply_protection(bool apply);
std::size_t get_builtin_id() const;
void set_builtin_id(std::size_t builtin_id);
void set_hidden(bool hidden);
bool get_hidden() const;
protected:
std::string to_hash_string() const override;
private:
friend class style_serializer;
friend class workbook;
std::size_t id_;
bool alignment_apply_;
alignment alignment_;
bool border_apply_;
std::size_t border_id_;
border border_;
bool fill_apply_;
std::size_t fill_id_;
fill fill_;
bool font_apply_;
std::size_t font_id_;
font font_;
bool number_format_apply_;
std::size_t number_format_id_;
number_format number_format_;
bool protection_apply_;
protection protection_;
bool pivot_button_;
bool quote_prefix_;
std::string name_;
std::size_t format_id_;
std::size_t builtin_id_;
bool hidden_;
};
} // namespace xlnt

View File

@ -43,6 +43,7 @@ class document_properties;
class drawing;
class fill;
class font;
class format;
class manifest;
class named_range;
class number_format;
@ -182,6 +183,8 @@ public:
void add_number_format(const number_format &format);
void add_protection(const protection &p);
const std::vector<format> &get_cell_style_formats() const;
const std::vector<format> &get_cell_formats() const;
const std::vector<style> &get_styles() const;
const std::vector<color> &get_colors() const;
@ -213,6 +216,12 @@ public:
bool has_loaded_theme() const;
const theme &get_loaded_theme() const;
const format &get_cell_style_format(std::size_t format_id) const;
std::size_t add_cell_style_format(const format &format_);
const format &get_cell_format(std::size_t format_id) const;
std::size_t add_cell_format(const format &format_);
const style &get_style(std::size_t style_id) const;
std::size_t add_style(const style &style_);
@ -225,6 +234,9 @@ public:
std::vector<std::string> &get_shared_strings();
const std::vector<std::string> &get_shared_strings() const;
void set_thumbnail(const std::vector<std::uint8_t> &thumbnail);
const std::vector<std::uint8_t> &get_thumbnail() const;
private:
friend class worksheet;
std::shared_ptr<detail::workbook_impl> d_;

View File

@ -31,7 +31,7 @@
#include <xlnt/packaging/relationship.hpp>
#include <xlnt/serialization/encoding.hpp>
#include <xlnt/styles/color.hpp>
#include <xlnt/styles/style.hpp>
#include <xlnt/styles/format.hpp>
#include <xlnt/utils/date.hpp>
#include <xlnt/utils/datetime.hpp>
#include <xlnt/utils/time.hpp>
@ -596,7 +596,7 @@ const font &cell::get_font() const
{
if (d_->has_style_)
{
auto font_id = get_parent().get_parent().get_styles()[d_->style_id_].get_font_id();
auto font_id = get_parent().get_parent().get_cell_formats()[d_->style_id_].get_font_id();
return get_parent().get_parent().get_font(font_id);
}
else

View File

@ -98,6 +98,8 @@ struct workbook_impl
bool data_only_;
bool read_only_;
std::vector<format> cell_style_formats_;
std::vector<format> cell_formats_;
std::vector<style> styles_;
std::size_t next_custom_format_id_;
@ -113,6 +115,8 @@ struct workbook_impl
theme theme_;
encoding encoding_;
std::vector<std::uint8_t> thumbnail_;
};
} // namespace detail

View File

@ -162,6 +162,12 @@ bool load_workbook(xlnt::zip_file &archive, bool guess_types, bool data_only, xl
worksheet_serializer.read_worksheet(worksheet_xml);
}
if (archive.has_file("docProps/thumbnail.jpeg"))
{
auto thumbnail_data = archive.read("docProps/thumbnail.jpeg");
wb.set_thumbnail(std::vector<std::uint8_t>(thumbnail_data.begin(), thumbnail_data.end()));
}
return true;
}
@ -251,6 +257,12 @@ void excel_serializer::write_data(bool /*as_template*/)
archive_.writestr(constants::ArcContentTypes(), manifest_serializer_.write_manifest().to_string());
write_worksheets();
if(!workbook_.get_thumbnail().empty())
{
const auto &thumbnail = workbook_.get_thumbnail();
archive_.writestr("docProps/thumbnail.jpeg", std::string(thumbnail.begin(), thumbnail.end()));
}
}
void excel_serializer::write_worksheets()

View File

@ -21,7 +21,7 @@
//
// @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file
#include <cctype>
#include <cctype> // for std::tolower
#include <xlnt/serialization/style_serializer.hpp>
#include <xlnt/serialization/xml_document.hpp>
@ -30,6 +30,7 @@
#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/protection.hpp>
#include <xlnt/styles/style.hpp>
@ -196,6 +197,7 @@ alignment style_serializer::read_alignment(const xml_node &alignment_node)
alignment align;
align.set_wrap_text(is_true(alignment_node.get_attribute("wrapText")));
align.set_shrink_to_fit(is_true(alignment_node.get_attribute("shrinkToFit")));
bool has_vertical = alignment_node.has_attribute("vertical");
@ -264,20 +266,20 @@ alignment style_serializer::read_alignment(const xml_node &alignment_node)
return align;
}
style style_serializer::read_style(const xml_node &style_node)
format style_serializer::read_format(const xml_node &format_node)
{
style s;
format f;
s.apply_number_format(is_true(style_node.get_attribute("applyNumberFormat")));
s.number_format_id_ = std::stoull(style_node.get_attribute("numFmtId"));
f.apply_number_format(is_true(format_node.get_attribute("applyNumberFormat")));
f.number_format_id_ = std::stoull(format_node.get_attribute("numFmtId"));
bool builtin_format = true;
for (auto num_fmt : workbook_.get_number_formats())
{
if (static_cast<std::size_t>(num_fmt.get_id()) == s.get_number_format_id())
if (static_cast<std::size_t>(num_fmt.get_id()) == f.get_number_format_id())
{
s.number_format_ = num_fmt;
f.number_format_ = num_fmt;
builtin_format = false;
break;
}
@ -285,37 +287,49 @@ style style_serializer::read_style(const xml_node &style_node)
if (builtin_format)
{
s.number_format_ = number_format::from_builtin_id(s.get_number_format_id());
f.number_format_ = number_format::from_builtin_id(f.get_number_format_id());
}
s.apply_font(is_true(style_node.get_attribute("applyFont")));
s.font_id_ = style_node.has_attribute("fontId") ? std::stoull(style_node.get_attribute("fontId")) : 0;
s.font_ = workbook_.get_font(s.font_id_);
f.apply_font(is_true(format_node.get_attribute("applyFont")));
f.font_id_ = format_node.has_attribute("fontId") ? std::stoull(format_node.get_attribute("fontId")) : 0;
f.font_ = workbook_.get_font(f.font_id_);
s.apply_fill(is_true(style_node.get_attribute("applyFill")));
s.fill_id_ = style_node.has_attribute("fillId") ? std::stoull(style_node.get_attribute("fillId")) : 0;
s.fill_ = workbook_.get_fill(s.fill_id_);
f.apply_fill(is_true(format_node.get_attribute("applyFill")));
f.fill_id_ = format_node.has_attribute("fillId") ? std::stoull(format_node.get_attribute("fillId")) : 0;
f.fill_ = workbook_.get_fill(f.fill_id_);
s.apply_border(is_true(style_node.get_attribute("applyBorder")));
s.border_id_ = style_node.has_attribute("borderId") ? std::stoull(style_node.get_attribute("borderId")) : 0;
s.border_ = workbook_.get_border(s.border_id_);
f.apply_border(is_true(format_node.get_attribute("applyBorder")));
f.border_id_ = format_node.has_attribute("borderId") ? std::stoull(format_node.get_attribute("borderId")) : 0;
f.border_ = workbook_.get_border(f.border_id_);
s.apply_protection(style_node.has_attribute("protection"));
f.apply_protection(format_node.has_attribute("protection"));
if (s.protection_apply_)
if (f.protection_apply_)
{
auto inline_protection = read_protection(style_node.get_child("protection"));
s.protection_ = inline_protection;
auto inline_protection = read_protection(format_node.get_child("protection"));
f.protection_ = inline_protection;
}
s.apply_alignment(style_node.has_child("alignment"));
f.apply_alignment(format_node.has_child("alignment"));
if (s.alignment_apply_)
if (f.alignment_apply_)
{
auto inline_alignment = read_alignment(style_node.get_child("alignment"));
s.alignment_ = inline_alignment;
auto inline_alignment = read_alignment(format_node.get_child("alignment"));
f.alignment_ = inline_alignment;
}
return f;
}
style style_serializer::read_style(const xml_node &style_node)
{
style s;
s.set_name(style_node.get_attribute("name"));
s.set_format_id(std::stoull(style_node.get_attribute("xfId")));
s.set_hidden(style_node.has_attribute("hidden") && is_true(style_node.get_attribute("hidden")));
s.set_builtin_id(std::stoull(style_node.get_attribute("builtinId")));
return s;
}
@ -329,16 +343,40 @@ bool style_serializer::read_stylesheet(const xml_document &xml)
read_number_formats(stylesheet_node.get_child("numFmts"));
read_colors(stylesheet_node.get_child("colors"));
auto cell_xfs_node = stylesheet_node.get_child("cellXfs");
auto cell_style_formats_node = stylesheet_node.get_child("cellStyleXfs");
for (auto xf_node : cell_xfs_node.get_children())
for (auto format_node : cell_style_formats_node.get_children())
{
if (xf_node.get_name() != "xf")
if (format_node.get_name() != "xf")
{
continue;
}
workbook_.add_style(read_style(xf_node));
workbook_.add_cell_style_format(read_format(format_node));
}
auto cell_formats_node = stylesheet_node.get_child("cellXfs");
for (auto format_node : cell_formats_node.get_children())
{
if (format_node.get_name() != "xf")
{
continue;
}
workbook_.add_cell_format(read_format(format_node));
}
auto cell_styles_node = stylesheet_node.get_child("cellStyles");
for (auto cell_style_node : cell_styles_node.get_children())
{
if (cell_style_node.get_name() != "cellStyle")
{
continue;
}
workbook_.add_style(read_style(cell_style_node));
}
return true;
@ -404,25 +442,53 @@ font style_serializer::read_font(const xlnt::xml_node &font_node)
}
if (font_node.has_child("b"))
{
if(font_node.get_child("b").has_attribute("val"))
{
new_font.set_bold(is_true(font_node.get_child("b").get_attribute("val")));
}
else
{
new_font.set_bold(true);
}
}
if (font_node.has_child("strike"))
{
if(font_node.get_child("strike").has_attribute("val"))
{
new_font.set_strikethrough(is_true(font_node.get_child("strike").get_attribute("val")));
}
else
{
new_font.set_strikethrough(true);
}
}
if (font_node.has_child("i"))
{
if(font_node.get_child("i").has_attribute("val"))
{
new_font.set_italic(is_true(font_node.get_child("i").get_attribute("val")));
}
else
{
new_font.set_italic(true);
}
}
if (font_node.has_child("u"))
{
if (font_node.get_child("u").has_attribute("val"))
{
std::string underline_string = font_node.get_child("u").get_attribute("val");
new_font.set_underline(underline_style_from_string(underline_string));
}
else
{
new_font.set_underline(xlnt::font::underline_style::single);
}
}
return new_font;
}
@ -635,18 +701,18 @@ xml_document style_serializer::write_stylesheet() const
if (f.is_italic())
{
auto bold_node = font_node.add_child("i");
bold_node.add_attribute("val", "1");
auto italic_node = font_node.add_child("i");
italic_node.add_attribute("val", "1");
}
if (f.is_underline())
{
auto bold_node = font_node.add_child("u");
auto underline_node = font_node.add_child("u");
switch (f.get_underline())
{
case font::underline_style::single:
bold_node.add_attribute("val", "single");
underline_node.add_attribute("val", "single");
break;
default:
break;
@ -655,8 +721,8 @@ xml_document style_serializer::write_stylesheet() const
if (f.is_strikethrough())
{
auto bold_node = font_node.add_child("strike");
bold_node.add_attribute("val", "1");
auto strike_node = font_node.add_child("strike");
strike_node.add_attribute("val", "1");
}
auto size_node = font_node.add_child("sz");
@ -672,6 +738,14 @@ xml_document style_serializer::write_stylesheet() const
{
color_node.add_attribute("theme", std::to_string(f.get_color().get_theme()));
}
else if (f.get_color().get_type() == color::type::auto_)
{
color_node.add_attribute("auto", std::to_string(f.get_color().get_auto()));
}
else if (f.get_color().get_type() == color::type::rgb)
{
color_node.add_attribute("rgb", f.get_color().get_rgb_string());
}
auto name_node = font_node.add_child("name");
name_node.add_attribute("val", f.get_name());
@ -703,6 +777,8 @@ xml_document style_serializer::write_stylesheet() const
auto type_string = fill_.get_pattern_type_string();
pattern_fill_node.add_attribute("patternType", type_string);
if (fill_.get_pattern_type() != xlnt::fill::pattern_type::solid) continue;
if (fill_.get_foreground_color())
{
auto fg_color_node = pattern_fill_node.add_child("fgColor");
@ -817,10 +893,10 @@ xml_document style_serializer::write_stylesheet() const
style_string = "none";
break;
case border_style::dashdot:
style_string = "dashdot";
style_string = "dashDot";
break;
case border_style::dashdotdot:
style_string = "dashdotdot";
style_string = "dashDotDot";
break;
case border_style::dashed:
style_string = "dashed";
@ -838,16 +914,16 @@ xml_document style_serializer::write_stylesheet() const
style_string = "thin";
break;
case border_style::mediumdashdot:
style_string = "mediumdashdot";
style_string = "mediumDashDot";
break;
case border_style::mediumdashdotdot:
style_string = "mediumdashdotdot";
style_string = "mediumDashDotDot";
break;
case border_style::mediumdashed:
style_string = "mediumdashed";
style_string = "mediumDashed";
break;
case border_style::slantdashdot:
style_string = "slantdashdot";
style_string = "slantDashDot";
break;
case border_style::thick:
style_string = "thick";
@ -888,48 +964,32 @@ xml_document style_serializer::write_stylesheet() const
}
auto cell_style_xfs_node = style_sheet_node.add_child("cellStyleXfs");
cell_style_xfs_node.add_attribute("count", "1");
auto &cell_style_formats = workbook_.get_cell_style_formats();
cell_style_xfs_node.add_attribute("count", std::to_string(cell_style_formats.size()));
auto style_xf_node = cell_style_xfs_node.add_child("xf");
style_xf_node.add_attribute("numFmtId", "0");
style_xf_node.add_attribute("fontId", "0");
style_xf_node.add_attribute("fillId", "0");
style_xf_node.add_attribute("borderId", "0");
auto cell_xfs_node = style_sheet_node.add_child("cellXfs");
const auto &styles = workbook_.get_styles();
cell_xfs_node.add_attribute("count", std::to_string(styles.size()));
for (auto &style : styles)
for(auto &format : cell_style_formats)
{
auto xf_node = cell_xfs_node.add_child("xf");
xf_node.add_attribute("numFmtId", std::to_string(style.get_number_format().get_id()));
xf_node.add_attribute("fontId", std::to_string(style.get_font_id()));
auto xf_node = cell_style_xfs_node.add_child("xf");
if (style.fill_apply_)
{
xf_node.add_attribute("fillId", std::to_string(style.get_fill_id()));
}
xf_node.add_attribute("numFmtId", std::to_string(format.get_number_format().get_id()));
xf_node.add_attribute("fontId", std::to_string(format.get_font_id()));
xf_node.add_attribute("fillId", std::to_string(format.get_fill_id()));
xf_node.add_attribute("borderId", std::to_string(format.get_border_id()));
if (style.border_apply_)
{
xf_node.add_attribute("borderId", std::to_string(style.get_border_id()));
}
xf_node.add_attribute("applyNumberFormat", format.number_format_apply_ ? "1" : "0");
xf_node.add_attribute("applyFill", format.fill_apply_ ? "1" : "0");
xf_node.add_attribute("applyFont", format.font_apply_ ? "1" : "0");
xf_node.add_attribute("applyBorder", format.border_apply_ ? "1" : "0");
xf_node.add_attribute("applyAlignment", format.alignment_apply_ ? "1" : "0");
xf_node.add_attribute("applyProtection", format.protection_apply_ ? "1" : "0");
xf_node.add_attribute("applyNumberFormat", style.number_format_apply_ ? "1" : "0");
xf_node.add_attribute("applyFont", style.font_apply_ ? "1" : "0");
xf_node.add_attribute("applyFill", style.fill_apply_ ? "1" : "0");
xf_node.add_attribute("applyBorder", style.border_apply_ ? "1" : "0");
xf_node.add_attribute("applyAlignment", style.alignment_apply_ ? "1" : "0");
xf_node.add_attribute("applyProtection", style.protection_apply_ ? "1" : "0");
if (style.alignment_apply_)
if (format.alignment_apply_)
{
auto alignment_node = xf_node.add_child("alignment");
if (style.alignment_.has_vertical())
if (format.alignment_.has_vertical())
{
switch (style.alignment_.get_vertical())
switch (format.alignment_.get_vertical())
{
case vertical_alignment::bottom:
alignment_node.add_attribute("vertical", "bottom");
@ -948,9 +1008,9 @@ xml_document style_serializer::write_stylesheet() const
}
}
if (style.alignment_.has_horizontal())
if (format.alignment_.has_horizontal())
{
switch (style.alignment_.get_horizontal())
switch (format.alignment_.get_horizontal())
{
case horizontal_alignment::center:
alignment_node.add_attribute("horizontal", "center");
@ -975,19 +1035,128 @@ xml_document style_serializer::write_stylesheet() const
}
}
if (style.alignment_.get_wrap_text())
if (format.alignment_.get_wrap_text())
{
alignment_node.add_attribute("wrapText", "1");
}
if (format.alignment_.get_shrink_to_fit())
{
alignment_node.add_attribute("shrinkToFit", "1");
}
}
}
auto cell_xfs_node = style_sheet_node.add_child("cellXfs");
const auto &formats = workbook_.get_cell_formats();
cell_xfs_node.add_attribute("count", std::to_string(formats.size()));
for (auto &format : formats)
{
auto xf_node = cell_xfs_node.add_child("xf");
xf_node.add_attribute("numFmtId", std::to_string(format.get_number_format().get_id()));
xf_node.add_attribute("fontId", std::to_string(format.get_font_id()));
if (format.fill_apply_)
{
xf_node.add_attribute("fillId", std::to_string(format.get_fill_id()));
}
if (format.border_apply_)
{
xf_node.add_attribute("borderId", std::to_string(format.get_border_id()));
}
xf_node.add_attribute("xfId", "0");
xf_node.add_attribute("applyNumberFormat", format.number_format_apply_ ? "1" : "0");
xf_node.add_attribute("applyFont", format.font_apply_ ? "1" : "0");
xf_node.add_attribute("applyFill", format.fill_apply_ ? "1" : "0");
xf_node.add_attribute("applyBorder", format.border_apply_ ? "1" : "0");
xf_node.add_attribute("applyAlignment", format.alignment_apply_ ? "1" : "0");
xf_node.add_attribute("applyProtection", format.protection_apply_ ? "1" : "0");
if (format.alignment_apply_)
{
auto alignment_node = xf_node.add_child("alignment");
if (format.alignment_.has_vertical())
{
switch (format.alignment_.get_vertical())
{
case vertical_alignment::bottom:
alignment_node.add_attribute("vertical", "bottom");
break;
case vertical_alignment::center:
alignment_node.add_attribute("vertical", "center");
break;
case vertical_alignment::justify:
alignment_node.add_attribute("vertical", "justify");
break;
case vertical_alignment::top:
alignment_node.add_attribute("vertical", "top");
break;
default:
throw std::runtime_error("invalid alignment");
}
}
if (format.alignment_.has_horizontal())
{
switch (format.alignment_.get_horizontal())
{
case horizontal_alignment::center:
alignment_node.add_attribute("horizontal", "center");
break;
case horizontal_alignment::center_continuous:
alignment_node.add_attribute("horizontal", "center_continuous");
break;
case horizontal_alignment::general:
alignment_node.add_attribute("horizontal", "general");
break;
case horizontal_alignment::justify:
alignment_node.add_attribute("horizontal", "justify");
break;
case horizontal_alignment::left:
alignment_node.add_attribute("horizontal", "left");
break;
case horizontal_alignment::right:
alignment_node.add_attribute("horizontal", "right");
break;
default:
throw std::runtime_error("invalid alignment");
}
}
if (format.alignment_.get_wrap_text())
{
alignment_node.add_attribute("wrapText", "1");
}
if (format.alignment_.get_shrink_to_fit())
{
alignment_node.add_attribute("shrinkToFit", "1");
}
}
}
auto cell_styles_node = style_sheet_node.add_child("cellStyles");
cell_styles_node.add_attribute("count", "1");
auto &styles = workbook_.get_styles();
cell_styles_node.add_attribute("count", std::to_string(styles.size()));
for(auto &cell_style : styles)
{
auto cell_style_node = cell_styles_node.add_child("cellStyle");
cell_style_node.add_attribute("name", "Normal");
cell_style_node.add_attribute("xfId", "0");
cell_style_node.add_attribute("builtinId", "0");
cell_style_node.add_attribute("name", cell_style.get_name());
cell_style_node.add_attribute("xfId", std::to_string(cell_style.get_format_id()));
cell_style_node.add_attribute("builtinId", std::to_string(cell_style.get_builtin_id()));
if (cell_style.get_hidden())
{
cell_style_node.add_attribute("hidden", "1");
}
}
style_sheet_node.add_child("dxfs").add_attribute("count", "0");
@ -996,6 +1165,8 @@ xml_document style_serializer::write_stylesheet() const
table_styles_node.add_attribute("defaultTableStyle", "TableStyleMedium2");
table_styles_node.add_attribute("defaultPivotStyle", "PivotStyleMedium9");
if(!workbook_.get_colors().empty())
{
auto colors_node = style_sheet_node.add_child("colors");
auto indexed_colors_node = colors_node.add_child("indexedColors");
@ -1003,6 +1174,7 @@ xml_document style_serializer::write_stylesheet() const
{
indexed_colors_node.add_child("rgbColor").add_attribute("rgb", c.get_rgb_string());
}
}
auto ext_list_node = style_sheet_node.add_child("extLst");
auto ext_node = ext_list_node.add_child("ext");

View File

@ -95,15 +95,18 @@ void workbook_serializer::read_properties_core(const xml_document &xml)
{
props.creator = root_node.get_child("dc:creator").get_text();
}
if (root_node.has_child("cp:lastModifiedBy"))
{
props.last_modified_by = root_node.get_child("cp:lastModifiedBy").get_text();
}
if (root_node.has_child("dcterms:created"))
{
std::string created_string = root_node.get_child("dcterms:created").get_text();
props.created = w3cdtf_to_datetime(created_string);
}
if (root_node.has_child("dcterms:modified"))
{
std::string modified_string = root_node.get_child("dcterms:modified").get_text();

View File

@ -31,6 +31,16 @@ bool alignment::get_wrap_text() const
return wrap_text_;
}
void alignment::set_shrink_to_fit(bool shrink_to_fit)
{
shrink_to_fit_ = shrink_to_fit;
}
bool alignment::get_shrink_to_fit() const
{
return shrink_to_fit_;
}
void alignment::set_wrap_text(bool wrap_text)
{
wrap_text_ = wrap_text;

237
source/styles/format.cpp Normal file
View File

@ -0,0 +1,237 @@
// 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 <xlnt/cell/cell.hpp>
#include <xlnt/styles/font.hpp>
#include <xlnt/styles/number_format.hpp>
#include <xlnt/styles/protection.hpp>
#include <xlnt/styles/format.hpp>
namespace {
template <class T>
void hash_combine(std::size_t &seed, const T &v)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
}
namespace xlnt {
const color color::black()
{
return color(color::type::rgb, "ff000000");
}
const color color::white()
{
return color(color::type::rgb, "ffffffff");
}
format::format()
: id_(0),
alignment_apply_(false),
border_apply_(false),
border_id_(0),
fill_apply_(false),
fill_id_(0),
font_apply_(false),
font_id_(0),
number_format_apply_(false),
number_format_id_(0),
protection_apply_(false),
pivot_button_(false),
quote_prefix_(false)
{
}
format::format(const format &other)
: id_(other.id_),
alignment_apply_(other.alignment_apply_),
alignment_(other.alignment_),
border_apply_(other.border_apply_),
border_id_(other.border_id_),
border_(other.border_),
fill_apply_(other.fill_apply_),
fill_id_(other.fill_id_),
fill_(other.fill_),
font_apply_(other.font_apply_),
font_id_(other.font_id_),
font_(other.font_),
number_format_apply_(other.number_format_apply_),
number_format_id_(other.number_format_id_),
number_format_(other.number_format_),
protection_apply_(other.protection_apply_),
protection_(other.protection_),
pivot_button_(other.pivot_button_),
quote_prefix_(other.quote_prefix_)
{
}
format &format::operator=(const format &other)
{
id_ = other.id_;
alignment_ = other.alignment_;
alignment_apply_ = other.alignment_apply_;
border_ = other.border_;
border_apply_ = other.border_apply_;
border_id_ = other.border_id_;
fill_ = other.fill_;
fill_apply_ = other.fill_apply_;
fill_id_ = other.fill_id_;
font_ = other.font_;
font_apply_ = other.font_apply_;
font_id_ = other.font_id_;
number_format_ = other.number_format_;
number_format_apply_ = other.number_format_apply_;
number_format_id_ = other.number_format_id_;
protection_ = other.protection_;
protection_apply_ = other.protection_apply_;
pivot_button_ = other.pivot_button_;
quote_prefix_ = other.quote_prefix_;
return *this;
}
std::string format::to_hash_string() const
{
std::string hash_string("format");
hash_string.append(std::to_string(alignment_apply_));
hash_string.append(alignment_apply_ ? std::to_string(alignment_.hash()) : " ");
hash_string.append(std::to_string(border_apply_));
hash_string.append(border_apply_ ? std::to_string(border_id_) : " ");
hash_string.append(std::to_string(font_apply_));
hash_string.append(font_apply_ ? std::to_string(font_id_) : " ");
hash_string.append(std::to_string(fill_apply_));
hash_string.append(fill_apply_ ? std::to_string(fill_id_) : " ");
hash_string.append(std::to_string(number_format_apply_));
hash_string.append(number_format_apply_ ? std::to_string(number_format_id_) : " ");
hash_string.append(std::to_string(protection_apply_));
hash_string.append(protection_apply_ ? std::to_string(protection_.hash()) : " ");
return hash_string;
}
const number_format format::get_number_format() const
{
return number_format_;
}
const border format::get_border() const
{
return border_;
}
const alignment format::get_alignment() const
{
return alignment_;
}
const fill format::get_fill() const
{
return fill_;
}
const font format::get_font() const
{
return font_;
}
const protection format::get_protection() const
{
return protection_;
}
bool format::pivot_button() const
{
return pivot_button_;
}
bool format::quote_prefix() const
{
return quote_prefix_;
}
std::size_t format::get_id() const
{
return id_;
}
std::size_t format::get_fill_id() const
{
return fill_id_;
}
std::size_t format::get_font_id() const
{
return font_id_;
}
std::size_t format::get_border_id() const
{
return border_id_;
}
std::size_t format::get_number_format_id() const
{
return number_format_id_;
}
void format::apply_alignment(bool apply)
{
alignment_apply_ = apply;
}
void format::apply_border(bool apply)
{
border_apply_ = apply;
}
void format::apply_fill(bool apply)
{
fill_apply_ = apply;
}
void format::apply_font(bool apply)
{
font_apply_ = apply;
}
void format::apply_number_format(bool apply)
{
number_format_apply_ = apply;
}
void format::apply_protection(bool apply)
{
protection_apply_ = apply;
}
} // namespace xlnt

View File

@ -21,10 +21,6 @@
//
// @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file
#include <xlnt/cell/cell.hpp>
#include <xlnt/styles/font.hpp>
#include <xlnt/styles/number_format.hpp>
#include <xlnt/styles/protection.hpp>
#include <xlnt/styles/style.hpp>
namespace {
@ -39,199 +35,74 @@ void hash_combine(std::size_t &seed, const T &v)
namespace xlnt {
const color color::black()
{
return color(color::type::rgb, "ff000000");
}
const color color::white()
{
return color(color::type::rgb, "ffffffff");
}
style::style()
: id_(0),
alignment_apply_(false),
border_apply_(false),
border_id_(0),
fill_apply_(false),
fill_id_(0),
font_apply_(false),
font_id_(0),
number_format_apply_(false),
number_format_id_(0),
protection_apply_(false),
pivot_button_(false),
quote_prefix_(false)
{
}
style::style(const style &other)
: id_(other.id_),
alignment_apply_(other.alignment_apply_),
alignment_(other.alignment_),
border_apply_(other.border_apply_),
border_id_(other.border_id_),
border_(other.border_),
fill_apply_(other.fill_apply_),
fill_id_(other.fill_id_),
fill_(other.fill_),
font_apply_(other.font_apply_),
font_id_(other.font_id_),
font_(other.font_),
number_format_apply_(other.number_format_apply_),
number_format_id_(other.number_format_id_),
number_format_(other.number_format_),
protection_apply_(other.protection_apply_),
protection_(other.protection_),
pivot_button_(other.pivot_button_),
quote_prefix_(other.quote_prefix_)
{
}
style &style::operator=(const style &other)
{
id_ = other.id_;
alignment_ = other.alignment_;
alignment_apply_ = other.alignment_apply_;
border_ = other.border_;
border_apply_ = other.border_apply_;
border_id_ = other.border_id_;
fill_ = other.fill_;
fill_apply_ = other.fill_apply_;
fill_id_ = other.fill_id_;
font_ = other.font_;
font_apply_ = other.font_apply_;
font_id_ = other.font_id_;
number_format_ = other.number_format_;
number_format_apply_ = other.number_format_apply_;
number_format_id_ = other.number_format_id_;
protection_ = other.protection_;
protection_apply_ = other.protection_apply_;
pivot_button_ = other.pivot_button_;
quote_prefix_ = other.quote_prefix_;
return *this;
}
std::string style::to_hash_string() const
{
std::string hash_string("style");
hash_string.append(std::to_string(alignment_apply_));
hash_string.append(alignment_apply_ ? std::to_string(alignment_.hash()) : " ");
hash_string.append(std::to_string(border_apply_));
hash_string.append(border_apply_ ? std::to_string(border_id_) : " ");
hash_string.append(std::to_string(font_apply_));
hash_string.append(font_apply_ ? std::to_string(font_id_) : " ");
hash_string.append(std::to_string(fill_apply_));
hash_string.append(fill_apply_ ? std::to_string(fill_id_) : " ");
hash_string.append(std::to_string(number_format_apply_));
hash_string.append(number_format_apply_ ? std::to_string(number_format_id_) : " ");
hash_string.append(std::to_string(protection_apply_));
hash_string.append(protection_apply_ ? std::to_string(protection_.hash()) : " ");
hash_string.append(name_);
hash_string.append(std::to_string(format_id_));
hash_string.append(std::to_string(builtin_id_));
hash_string.append(std::to_string(hidden_ ? 0 : 1));
return hash_string;
}
const number_format style::get_number_format() const
style::style() : name_("style"), format_id_(0), builtin_id_(0), hidden_(false)
{
return number_format_;
}
const border style::get_border() const
style::style(const style &other) : name_(other.name_), format_id_(other.format_id_), builtin_id_(other.builtin_id_), hidden_(other.hidden_)
{
return border_;
}
const alignment style::get_alignment() const
style &style::operator=(const xlnt::style &other)
{
return alignment_;
name_ = other.name_;
builtin_id_ = other.builtin_id_;
format_id_ = other.format_id_;
hidden_ = other.hidden_;
return *this;
}
const fill style::get_fill() const
std::string style::get_name() const
{
return fill_;
return name_;
}
const font style::get_font() const
void style::set_name(const std::string &name)
{
return font_;
name_ = name;
}
const protection style::get_protection() const
std::size_t style::get_format_id() const
{
return protection_;
return format_id_;
}
bool style::pivot_button() const
void style::set_format_id(std::size_t format_id)
{
return pivot_button_;
format_id_ = format_id;
}
bool style::quote_prefix() const
std::size_t style::get_builtin_id() const
{
return quote_prefix_;
return builtin_id_;
}
std::size_t style::get_id() const
void style::set_builtin_id(std::size_t builtin_id)
{
return id_;
builtin_id_ = builtin_id;
}
std::size_t style::get_fill_id() const
void style::set_hidden(bool hidden)
{
return fill_id_;
hidden_ = hidden;
}
std::size_t style::get_font_id() const
bool style::get_hidden() const
{
return font_id_;
}
std::size_t style::get_border_id() const
{
return border_id_;
}
std::size_t style::get_number_format_id() const
{
return number_format_id_;
}
void style::apply_alignment(bool apply)
{
alignment_apply_ = apply;
}
void style::apply_border(bool apply)
{
border_apply_ = apply;
}
void style::apply_fill(bool apply)
{
fill_apply_ = apply;
}
void style::apply_font(bool apply)
{
font_apply_ = apply;
}
void style::apply_number_format(bool apply)
{
number_format_apply_ = apply;
}
void style::apply_protection(bool apply)
{
protection_apply_ = apply;
return hidden_;
}
} // namespace xlnt

View File

@ -39,6 +39,7 @@
#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/protection.hpp>
#include <xlnt/styles/style.hpp>
@ -629,6 +630,22 @@ std::vector<named_range> workbook::get_named_ranges() const
return named_ranges;
}
std::size_t workbook::add_cell_style_format(const xlnt::format &format_)
{
d_->cell_style_formats_.push_back(format_);
d_->cell_style_formats_.back().id_ = d_->cell_style_formats_.size() - 1;
return d_->cell_style_formats_.back().id_;
}
std::size_t workbook::add_cell_format(const xlnt::format &format_)
{
d_->cell_formats_.push_back(format_);
d_->cell_formats_.back().id_ = d_->cell_formats_.size() - 1;
return d_->cell_formats_.back().id_;
}
std::size_t workbook::add_style(const xlnt::style &style_)
{
d_->styles_.push_back(style_);
@ -661,9 +678,9 @@ color workbook::get_indexed_color(const color &indexed_color) const
return d_->colors_.at(indexed_color.get_index());
}
const number_format &workbook::get_number_format(std::size_t style_id) const
const number_format &workbook::get_number_format(std::size_t format_id) const
{
auto number_format_id = d_->styles_[style_id].number_format_id_;
auto number_format_id = d_->cell_formats_[format_id].number_format_id_;
for (const auto &number_format_ : d_->number_formats_)
{
@ -684,7 +701,7 @@ const font &workbook::get_font(std::size_t font_id) const
return d_->fonts_[font_id];
}
std::size_t workbook::set_font(const font &font_, std::size_t style_id)
std::size_t workbook::set_font(const font &font_, std::size_t format_id)
{
auto match = std::find(d_->fonts_.begin(), d_->fonts_.end(), font_);
std::size_t font_id = 0;
@ -699,66 +716,66 @@ std::size_t workbook::set_font(const font &font_, std::size_t style_id)
font_id = match - d_->fonts_.begin();
}
if (d_->styles_.empty())
if (d_->cell_formats_.empty())
{
style new_style;
format new_format;
new_style.id_ = 0;
new_style.border_id_ = 0;
new_style.fill_id_ = 0;
new_style.font_id_ = font_id;
new_style.font_apply_ = true;
new_style.number_format_id_ = 0;
new_format.id_ = 0;
new_format.border_id_ = 0;
new_format.fill_id_ = 0;
new_format.font_id_ = font_id;
new_format.font_apply_ = true;
new_format.number_format_id_ = 0;
if (d_->borders_.empty())
{
d_->borders_.push_back(new_style.get_border());
d_->borders_.push_back(new_format.get_border());
}
if (d_->fills_.empty())
{
d_->fills_.push_back(new_style.get_fill());
d_->fills_.push_back(new_format.get_fill());
}
if (d_->number_formats_.empty())
{
d_->number_formats_.push_back(new_style.get_number_format());
d_->number_formats_.push_back(new_format.get_number_format());
}
d_->styles_.push_back(new_style);
d_->cell_formats_.push_back(new_format);
return 0;
}
// If the style is unchanged, just return it.
auto &existing_style = d_->styles_[style_id];
auto &existing_style = d_->cell_formats_[format_id];
existing_style.font_apply_ = true;
if (font_id == existing_style.font_id_)
{
// no change
return style_id;
return format_id;
}
// Make a new style with this format.
auto new_style = existing_style;
auto new_format = existing_style;
new_style.font_id_ = font_id;
new_style.font_ = font_;
new_format.font_id_ = font_id;
new_format.font_ = font_;
// Check if the new style is already applied to a different cell. If so, reuse it.
auto style_match = std::find(d_->styles_.begin(), d_->styles_.end(), new_style);
auto format_match = std::find(d_->cell_formats_.begin(), d_->cell_formats_.end(), new_format);
if (style_match != d_->styles_.end())
if (format_match != d_->cell_formats_.end())
{
return style_match->get_id();
return format_match->get_id();
}
// No match found, so add it.
new_style.id_ = d_->styles_.size();
d_->styles_.push_back(new_style);
new_format.id_ = d_->cell_formats_.size();
d_->cell_formats_.push_back(new_format);
return new_style.id_;
return new_format.id_;
}
const fill &workbook::get_fill(std::size_t fill_id) const
@ -766,9 +783,9 @@ const fill &workbook::get_fill(std::size_t fill_id) const
return d_->fills_[fill_id];
}
std::size_t workbook::set_fill(const fill & /*fill_*/, std::size_t style_id)
std::size_t workbook::set_fill(const fill & /*fill_*/, std::size_t format_id)
{
return style_id;
return format_id;
}
const border &workbook::get_border(std::size_t border_id) const
@ -776,52 +793,52 @@ const border &workbook::get_border(std::size_t border_id) const
return d_->borders_[border_id];
}
std::size_t workbook::set_border(const border & /*border_*/, std::size_t style_id)
std::size_t workbook::set_border(const border & /*border_*/, std::size_t format_id)
{
return style_id;
return format_id;
}
const alignment &workbook::get_alignment(std::size_t style_id) const
const alignment &workbook::get_alignment(std::size_t format_id) const
{
return d_->styles_[style_id].alignment_;
return d_->cell_formats_[format_id].alignment_;
}
std::size_t workbook::set_alignment(const alignment & /*alignment_*/, std::size_t style_id)
std::size_t workbook::set_alignment(const alignment & /*alignment_*/, std::size_t format_id)
{
return style_id;
return format_id;
}
const protection &workbook::get_protection(std::size_t style_id) const
const protection &workbook::get_protection(std::size_t format_id) const
{
return d_->styles_[style_id].protection_;
return d_->cell_formats_[format_id].protection_;
}
std::size_t workbook::set_protection(const protection & /*protection_*/, std::size_t style_id)
std::size_t workbook::set_protection(const protection & /*protection_*/, std::size_t format_id)
{
return style_id;
return format_id;
}
bool workbook::get_pivot_button(std::size_t style_id) const
bool workbook::get_pivot_button(std::size_t format_id) const
{
return d_->styles_[style_id].pivot_button_;
return d_->cell_formats_[format_id].pivot_button_;
}
bool workbook::get_quote_prefix(std::size_t style_id) const
bool workbook::get_quote_prefix(std::size_t format_id) const
{
return d_->styles_[style_id].quote_prefix_;
return d_->cell_formats_[format_id].quote_prefix_;
}
//TODO: this is terrible!
std::size_t workbook::set_number_format(const xlnt::number_format &format, std::size_t style_id)
std::size_t workbook::set_number_format(const xlnt::number_format &nf, std::size_t style_id)
{
auto match = std::find(d_->number_formats_.begin(), d_->number_formats_.end(), format);
auto match = std::find(d_->number_formats_.begin(), d_->number_formats_.end(), nf);
std::size_t format_id = 0;
if (match == d_->number_formats_.end())
{
d_->number_formats_.push_back(format);
d_->number_formats_.push_back(nf);
if (!format.has_id())
if (!nf.has_id())
{
d_->number_formats_.back().set_id(d_->next_custom_format_id_++);
}
@ -833,39 +850,39 @@ std::size_t workbook::set_number_format(const xlnt::number_format &format, std::
format_id = match->get_id();
}
if (d_->styles_.empty())
if (d_->cell_formats_.empty())
{
style new_style;
format new_format;
new_style.id_ = 0;
new_style.border_id_ = 0;
new_style.fill_id_ = 0;
new_style.font_id_ = 0;
new_style.number_format_id_ = format_id;
new_style.number_format_apply_ = true;
new_format.id_ = 0;
new_format.border_id_ = 0;
new_format.fill_id_ = 0;
new_format.font_id_ = 0;
new_format.number_format_id_ = format_id;
new_format.number_format_apply_ = true;
if (d_->borders_.empty())
{
d_->borders_.push_back(new_style.get_border());
d_->borders_.push_back(new_format.get_border());
}
if (d_->fills_.empty())
{
d_->fills_.push_back(new_style.get_fill());
d_->fills_.push_back(new_format.get_fill());
}
if (d_->fonts_.empty())
{
d_->fonts_.push_back(new_style.get_font());
d_->fonts_.push_back(new_format.get_font());
}
d_->styles_.push_back(new_style);
d_->cell_formats_.push_back(new_format);
return 0;
}
// If the style is unchanged, just return it.
auto existing_style = d_->styles_[style_id];
auto existing_style = d_->cell_formats_[format_id];
existing_style.number_format_apply_ = true;
if (format_id == existing_style.number_format_id_)
@ -875,24 +892,34 @@ std::size_t workbook::set_number_format(const xlnt::number_format &format, std::
}
// Make a new style with this format.
auto new_style = existing_style;
auto new_format = existing_style;
new_style.number_format_id_ = format_id;
new_style.number_format_ = format;
new_format.number_format_id_ = format_id;
new_format.number_format_ = nf;
// Check if the new style is already applied to a different cell. If so, reuse it.
auto style_match = std::find(d_->styles_.begin(), d_->styles_.end(), new_style);
auto format_match = std::find(d_->cell_formats_.begin(), d_->cell_formats_.end(), new_format);
if (style_match != d_->styles_.end())
if (format_match != d_->cell_formats_.end())
{
return style_match->get_id();
return format_match->get_id();
}
// No match found, so add it.
new_style.id_ = d_->styles_.size();
d_->styles_.push_back(new_style);
new_format.id_ = d_->cell_formats_.size();
d_->cell_formats_.push_back(new_format);
return new_style.id_;
return new_format.id_;
}
const std::vector<format> &workbook::get_cell_formats() const
{
return d_->cell_formats_;
}
const std::vector<format> &workbook::get_cell_style_formats() const
{
return d_->cell_style_formats_;
}
const std::vector<style> &workbook::get_styles() const
@ -985,4 +1012,14 @@ bool workbook::contains(const std::string &sheet_title) const
return false;
}
void workbook::set_thumbnail(const std::vector<std::uint8_t> &thumbnail)
{
d_->thumbnail_.assign(thumbnail.begin(), thumbnail.end());
}
const std::vector<std::uint8_t> &workbook::get_thumbnail() const
{
return d_->thumbnail_;
}
} // namespace xlnt

View File

@ -9,6 +9,13 @@
class test_worksheet : public CxxTest::TestSuite
{
public:
void test_roundtrip()
{
xlnt::workbook wb;
wb.load("/Users/thomas/Development/xlnt/tests/data/complex-styles.xlsx");
wb.save("/Users/thomas/Desktop/comparison_temp/out.zip");
}
void test_new_worksheet()
{
xlnt::workbook wb;