clean up api and do more testing

This commit is contained in:
Thomas Fussell 2016-08-01 18:33:43 -04:00
parent e8972ec423
commit 4234a62b8b
28 changed files with 690 additions and 693 deletions

View File

@ -25,12 +25,14 @@
#include <cstddef>
#include <functional>
#include <unordered_map>
#include <xlnt/xlnt_config.hpp>
#include <xlnt/styles/border_style.hpp>
#include <xlnt/styles/color.hpp>
#include <xlnt/styles/diagonal_direction.hpp>
#include <xlnt/styles/side.hpp>
#include <xlnt/utils/hashable.hpp>
#include <xlnt/utils/optional.hpp>
namespace xlnt {
@ -40,46 +42,54 @@ namespace xlnt {
class XLNT_CLASS border : public hashable
{
public:
static border default_border();
enum class XLNT_CLASS side
{
start,
end,
top,
bottom,
diagonal,
vertical,
horizontal
};
std::experimental::optional<side> &get_start();
const std::experimental::optional<side> &get_start() const;
std::experimental::optional<side> &get_end();
const std::experimental::optional<side> &get_end() const;
std::experimental::optional<side> &get_left();
const std::experimental::optional<side> &get_left() const;
std::experimental::optional<side> &get_right();
const std::experimental::optional<side> &get_right() const;
std::experimental::optional<side> &get_top();
const std::experimental::optional<side> &get_top() const;
std::experimental::optional<side> &get_bottom();
const std::experimental::optional<side> &get_bottom() const;
std::experimental::optional<side> &get_diagonal();
const std::experimental::optional<side> &get_diagonal() const;
std::experimental::optional<side> &get_vertical();
const std::experimental::optional<side> &get_vertical() const;
std::experimental::optional<side> &get_horizontal();
const std::experimental::optional<side> &get_horizontal() const;
class XLNT_CLASS border_property
{
public:
bool has_color() const;
const color &get_color() const;
void set_color(const color &c);
bool has_style() const;
border_style get_style() const;
void set_style(border_style style);
private:
bool has_color_ = false;
color color_ = color::black();
bool has_style_ = false;
border_style style_;
};
static border default();
static const std::unordered_map<side, std::string> &get_side_names();
border();
bool has_side(side s) const;
border_property &get_side(side s);
const border_property &get_side(side s) const;
void set_side(side s, const border_property &prop);
protected:
std::string to_hash_string() const override;
private:
std::experimental::optional<side> start_;
std::experimental::optional<side> end_;
std::experimental::optional<side> left_ = side();
std::experimental::optional<side> right_ = side();
std::experimental::optional<side> top_ = side();
std::experimental::optional<side> bottom_ = side();
std::experimental::optional<side> diagonal_ = side();
std::experimental::optional<side> vertical_;
std::experimental::optional<side> horizontal_;
bool outline_ = false;
bool diagonal_up_ = false;
bool diagonal_down_ = false;
diagonal_direction diagonal_direction_ = diagonal_direction::none;
std::unordered_map<side, border_property> sides_;
bool outline_ = true;
diagonal_direction diagonal_direction_ = diagonal_direction::neither;
};
} // namespace xlnt

View File

@ -23,6 +23,7 @@
// @author: see AUTHORS file
#pragma once
#include <array>
#include <string>
#include <xlnt/xlnt_config.hpp>
@ -30,6 +31,59 @@
namespace xlnt {
class XLNT_CLASS indexed_color
{
public:
indexed_color(std::size_t index);
std::size_t get_index() const;
void set_index(std::size_t index);
private:
std::size_t index_;
};
class XLNT_CLASS theme_color
{
public:
theme_color(std::size_t index);
std::size_t get_index() const;
void set_index(std::size_t index);
private:
std::size_t index_;
};
class XLNT_CLASS rgb_color
{
public:
rgb_color(const std::string &hex_string);
rgb_color(std::uint8_t r, std::uint8_t g, std::uint8_t b, std::uint8_t a = 255);
std::string get_hex_string() const;
std::uint8_t get_red() const;
std::uint8_t get_green() const;
std::uint8_t get_blue() const;
std::uint8_t get_alpha() const;
std::array<std::uint8_t, 3> get_rgb() const;
std::array<std::uint8_t, 4> get_rgba() const;
private:
static std::array<std::uint8_t, 4> decode_hex_string(const std::string &hex_string);
std::array<std::uint8_t, 4> rgba_;
};
/// <summary>
/// Colors can be applied to many parts of a cell's style.
/// </summary>
@ -43,8 +97,8 @@ public:
{
indexed,
theme,
auto_,
rgb
rgb,
auto_
};
static const color black();
@ -58,35 +112,38 @@ public:
static const color yellow();
static const color darkyellow();
color();
color();
color(const rgb_color &rgb);
color(const indexed_color &indexed);
color(const theme_color &theme);
color(type t, std::size_t v);
type get_type() const;
color(type t, const std::string &v);
bool is_auto() const;
void set_auto(std::size_t auto_index);
void set_auto(bool value);
void set_index(std::size_t index);
const rgb_color &get_rgb() const;
void set_theme(std::size_t theme);
const indexed_color &get_indexed() const;
type get_type() const;
const theme_color &get_theme() const;
std::size_t get_auto() const;
double get_tint() const;
std::size_t get_index() const;
std::size_t get_theme() const;
std::string get_rgb_string() const;
void set_tint(double tint);
protected:
std::string to_hash_string() const override;
private:
type type_ = type::indexed;
std::size_t index_ = 0;
std::string rgb_string_;
void assert_type(type t) const;
type type_;
rgb_color rgb_;
indexed_color indexed_;
theme_color theme_;
double tint_;
};
} // namespace xlnt

View File

@ -34,7 +34,7 @@ namespace xlnt {
/// </summary>
enum class XLNT_CLASS diagonal_direction
{
none,
neither,
up,
down,
both

View File

@ -106,7 +106,7 @@ private:
bool subscript_ = false;
underline_style underline_ = underline_style::none;
bool strikethrough_ = false;
color color_ = color(xlnt::color::type::theme, 1);
color color_ = theme_color(1);
bool has_family_ = true;
std::size_t family_ = 2;
bool has_scheme_ = true;

View File

@ -1,60 +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 <cstddef>
#include <xlnt/xlnt_config.hpp>
#include <xlnt/styles/border_style.hpp>
#include <xlnt/styles/color.hpp>
#include <xlnt/utils/hashable.hpp>
#include <xlnt/utils/optional.hpp>
namespace xlnt {
/// <summary>
/// Describes the one of the sides of a border of a particular cell.
/// </summary>
class XLNT_CLASS side : public hashable
{
public:
side();
std::experimental::optional<border_style> &get_border_style();
const std::experimental::optional<border_style> &get_border_style() const;
std::experimental::optional<color> &get_color();
const std::experimental::optional<color> &get_color() const;
protected:
std::string to_hash_string() const override;
private:
std::experimental::optional<border_style> border_style_;
std::experimental::optional<color> color_;
};
} // namespace xlnt

View File

@ -109,24 +109,54 @@ public:
// general properties
/// <summary>
/// Returns true if guess_types is enabled for this workbook.
/// </summary>
bool get_guess_types() const;
/// <summary>
/// Set to true to guess the type represented by a string set as the value
/// for a cell and then set the actual value of the cell to that type.
/// For example, cell.set_value("1") with guess_types enabled will set
/// type of the cell to numeric and it's value to the number 1.
/// </summary>
void set_guess_types(bool guess);
/// <summary>
/// ?
/// </summary>
bool get_data_only() const;
/// <summary>
/// ?
/// </summary>
void set_data_only(bool data_only);
bool get_read_only() const;
void set_read_only(bool read_only);
// add worksheets
/// <summary>
/// Create a sheet after the last sheet in this workbook and return it.
/// </summary>
worksheet create_sheet();
worksheet create_sheet(std::size_t index);
worksheet create_sheet(const std::string &title);
worksheet create_sheet(std::size_t index, const std::string &title);
worksheet create_sheet(const std::string &title, const relationship &rel);
/// <summary>
/// Create a sheet at the specified index and return it.
/// </summary>
worksheet create_sheet(std::size_t index);
/// <summary>
/// This should be private...
/// </summary>
worksheet create_sheet_with_rel(const std::string &title, const relationship &rel);
/// <summary>
/// Create a new sheet initializing it with all of the data from the provided worksheet.
/// </summary>
void copy_sheet(worksheet worksheet);
/// <summary>
/// Create a new sheet at the specified index initializing it with all of the data
/// from the provided worksheet.
void copy_sheet(worksheet worksheet, std::size_t index);
// get worksheets
@ -175,30 +205,97 @@ public:
// remove worksheets
/// <summary>
/// Remove the given worksheet from this workbook.
/// </summary>
void remove_sheet(worksheet worksheet);
/// <summary>
/// Delete every cell in this worksheet. After this is called, the
/// worksheet will be equivalent to a newly created sheet at the same
/// index and with the same title.
/// </summary>
void clear();
// iterators
/// <summary>
/// Returns an iterator to the first worksheet in this workbook.
/// </summary>
iterator begin();
/// <summary>
/// Returns an iterator to the worksheet following the last worksheet of the workbook.
/// This worksheet acts as a placeholder; attempting to access it will cause an
/// exception to be thrown.
/// </summary>
iterator end();
/// <summary>
/// Returns a const iterator to the first worksheet in this workbook.
/// </summary>
const_iterator begin() const;
/// <summary>
/// Returns a const iterator to the worksheet following the last worksheet of the workbook.
/// This worksheet acts as a placeholder; attempting to access it will cause an
/// exception to be thrown.
/// </summary>
const_iterator end() const;
/// <summary>
/// Returns an iterator to the first worksheet in this workbook.
/// </summary>
const_iterator cbegin() const;
/// <summary>
/// Returns a const iterator to the worksheet following the last worksheet of the workbook.
/// This worksheet acts as a placeholder; attempting to access it will cause an
/// exception to be thrown.
/// </summary>
const_iterator cend() const;
/// <summary>
/// Returns a reverse iterator to the last worksheet in this workbook.
/// </summary>
reverse_iterator rbegin();
/// <summary>
/// Returns an iterator to the worksheet preceeding the first worksheet of the workbook.
/// This worksheet acts as a placeholder; attempting to access it will cause an
/// exception to be thrown.
/// </summary>
reverse_iterator rend();
/// <summary>
/// Returns a const reverse iterator to the last worksheet in this workbook.
/// </summary>
const_reverse_iterator rbegin() const;
/// <summary>
/// Returns a const reverse iterator to the worksheet preceeding the first worksheet of the workbook.
/// This worksheet acts as a placeholder; attempting to access it will cause an
/// exception to be thrown.
/// </summary>
const_reverse_iterator rend() const;
/// <summary>
/// Returns a const reverse iterator to the last worksheet in this workbook.
/// </summary>
const_reverse_iterator crbegin() const;
/// <summary>
/// Returns a const reverse iterator to the worksheet preceeding the first worksheet of the workbook.
/// This worksheet acts as a placeholder; attempting to access it will cause an
/// exception to be thrown.
/// </summary>
const_reverse_iterator crend() const;
std::vector<std::string> get_sheet_names() const;
/// <summary>
/// Returns a temporary vector containing the titles of each sheet in the order
/// of the sheets in the workbook.
/// </summary>
std::vector<std::string> get_sheet_titles() const;
document_properties &get_properties();
const document_properties &get_properties() const;
@ -308,12 +405,7 @@ public:
private:
friend class excel_serializer;
friend class worksheet;
/// <summary>
/// Helper function to calculate an index from a worksheet filename.
/// </summary>
static std::size_t index_from_ws_filename(const std::string &filename);
friend class worksheet;
/// <summary>
/// Get the name of the next unused relationship.

View File

@ -72,7 +72,6 @@ public:
worksheet();
worksheet(const worksheet &rhs);
worksheet(workbook &parent_workbook, const std::string &title = std::string());
std::string to_string() const;
workbook &get_workbook();
@ -85,7 +84,6 @@ public:
std::string get_title() const;
void set_title(const std::string &title);
std::string make_unique_sheet_name(const std::string &value);
// freeze panes
cell_reference get_frozen_panes() const;
@ -102,8 +100,6 @@ public:
range get_range(const range_reference &reference);
const range get_range(const std::string &reference_string) const;
const range get_range(const range_reference &reference) const;
range get_squared_range(column_t min_col, row_t min_row, column_t max_col, row_t max_row);
const range get_squared_range(column_t min_col, row_t min_row, column_t max_col, row_t max_row) const;
range rows() const;
range rows(const std::string &range_string) const;
range rows(int row_offset, int column_offset) const;

View File

@ -60,18 +60,20 @@ cell_impl::cell_impl(const cell_impl &rhs)
cell_impl &cell_impl::operator=(const cell_impl &rhs)
{
type_ = rhs.type_;
parent_ = rhs.parent_;
column_ = rhs.column_;
row_ = rhs.row_;
value_text_ = rhs.value_text_;
value_numeric_ = rhs.value_numeric_;
value_text_ = rhs.value_text_;
has_hyperlink_ = rhs.has_hyperlink_;
hyperlink_ = rhs.hyperlink_;
formula_ = rhs.formula_;
column_ = rhs.column_;
row_ = rhs.row_;
is_merged_ = rhs.is_merged_;
has_hyperlink_ = rhs.has_hyperlink_;
type_ = rhs.type_;
has_format_ = rhs.has_format_;
format_id_ = rhs.format_id_;
has_format_ = rhs.has_format_;
has_style_ = rhs.has_style_;
style_id_ = rhs.style_id_;
if (rhs.comment_ != nullptr)
{

View File

@ -158,8 +158,8 @@ bool load_workbook(xlnt::zip_file &archive, bool guess_types, bool data_only, xl
continue;
}
auto ws = wb.create_sheet(sheet_node.attribute("name").value(), rel);
ws.set_id(sheet_node.attribute("sheetId").as_ullong());
auto ws = wb.create_sheet_with_rel(sheet_node.attribute("name").value(), rel);
ws.set_id(static_cast<std::size_t>(sheet_node.attribute("sheetId").as_ullong()));
xlnt::worksheet_serializer worksheet_serializer(ws);
pugi::xml_document worksheet_xml;
worksheet_xml.load(archive.read("xl/" + rel.get_target_uri()).c_str());

View File

@ -148,8 +148,6 @@ bool format_condition::satisfied_by(long double number) const
{
switch (type)
{
case condition_type::equal:
return number == value;
case condition_type::greater_or_equal:
return number >= value;
case condition_type::greater_than:
@ -160,6 +158,9 @@ bool format_condition::satisfied_by(long double number) const
return number < value;
case condition_type::not_equal:
return number != value;
case condition_type::equal:
default:
return number == value;
}
}

View File

@ -104,10 +104,10 @@ const std::unordered_map<std::string, xlnt::font::underline_style> &get_string_u
map = new std::unordered_map<std::string, xlnt::font::underline_style>
{
{ "double", xlnt::font::underline_style::double_ },
{ "double-accounting", xlnt::font::underline_style::double_accounting },
{ "doubleAccounting", xlnt::font::underline_style::double_accounting },
{ "none", xlnt::font::underline_style::none },
{ "single", xlnt::font::underline_style::single },
{ "single-accounting", xlnt::font::underline_style::single_accounting }
{ "singleAccounting", xlnt::font::underline_style::single_accounting }
};
}
@ -133,7 +133,7 @@ const std::unordered_map<xlnt::font::underline_style, std::string, EnumClassHash
xlnt::font::underline_style underline_style_from_string(const std::string &underline_string)
{
return get_string_underline_style_map().at(string_lower(underline_string));
return get_string_underline_style_map().at(underline_string);
}
std::string underline_style_to_string(xlnt::font::underline_style underline_style)
@ -413,23 +413,8 @@ xlnt::protection read_protection(const pugi::xml_node protection_node)
{
xlnt::protection prot;
if (is_true(protection_node.attribute("locked").value()))
{
prot.set_locked(true);
}
else if (!is_false(protection_node.attribute("locked").value()))
{
throw std::runtime_error("bad protection value");
}
if (is_true(protection_node.attribute("hidden").value()))
{
prot.set_hidden(true);
}
else if (!is_false(protection_node.attribute("hidden").value()))
{
throw std::runtime_error("bad protection value");
}
prot.set_locked(is_true(protection_node.attribute("locked").value()));
prot.set_hidden(is_true(protection_node.attribute("hidden").value()));
return prot;
}
@ -480,24 +465,32 @@ void read_number_formats(const pugi::xml_node number_formats_node, std::vector<x
xlnt::color read_color(const pugi::xml_node &color_node)
{
xlnt::color result;
if (color_node.attribute("auto"))
{
return result;
}
if (color_node.attribute("rgb"))
{
return xlnt::color(xlnt::color::type::rgb, color_node.attribute("rgb").value());
result = xlnt::rgb_color(color_node.attribute("rgb").value());
}
else if (color_node.attribute("theme"))
{
return xlnt::color(xlnt::color::type::theme, string_to_size_t(color_node.attribute("theme").value()));
result = xlnt::theme_color(string_to_size_t(color_node.attribute("theme").value()));
}
else if (color_node.attribute("indexed"))
{
return xlnt::color(xlnt::color::type::indexed, string_to_size_t(color_node.attribute("indexed").value()));
}
else if (color_node.attribute("auto"))
{
return xlnt::color(xlnt::color::type::auto_, string_to_size_t(color_node.attribute("auto").value()));
result = xlnt::indexed_color(string_to_size_t(color_node.attribute("indexed").value()));
}
throw std::runtime_error("bad color");
if (color_node.attribute("tint"))
{
result.set_tint(color_node.attribute("tint").as_double());
}
return result;
}
xlnt::font read_font(const pugi::xml_node font_node)
@ -667,18 +660,18 @@ void read_fills(const pugi::xml_node &fills_node, std::vector<xlnt::fill> &fills
}
}
xlnt::side read_side(const pugi::xml_node &side_node)
xlnt::border::border_property read_side(const pugi::xml_node &side_node)
{
xlnt::side new_side;
xlnt::border::border_property new_side;
if (side_node.attribute("style"))
{
new_side.get_border_style() = border_style_from_string(side_node.attribute("style").value());
new_side.set_style(border_style_from_string(side_node.attribute("style").value()));
}
if (side_node.child("color"))
{
new_side.get_color() = read_color(side_node.child("color"));
new_side.set_color(read_color(side_node.child("color")));
}
return new_side;
@ -688,52 +681,16 @@ xlnt::border read_border(const pugi::xml_node &border_node)
{
xlnt::border new_border;
if (border_node.child("start"))
{
new_border.get_start() = read_side(border_node.child("start"));
}
for (const auto &side_name : xlnt::border::get_side_names())
{
if (border_node.child(side_name.second.c_str()))
{
auto side = read_side(border_node.child(side_name.second.c_str()));
new_border.set_side(side_name.first, side);
}
}
if (border_node.child("end"))
{
new_border.get_end() = read_side(border_node.child("end"));
}
if (border_node.child("left"))
{
new_border.get_left() = read_side(border_node.child("left"));
}
if (border_node.child("right"))
{
new_border.get_right() = read_side(border_node.child("right"));
}
if (border_node.child("top"))
{
new_border.get_top() = read_side(border_node.child("top"));
}
if (border_node.child("bottom"))
{
new_border.get_bottom() = read_side(border_node.child("bottom"));
}
if (border_node.child("diagonal"))
{
new_border.get_diagonal() = read_side(border_node.child("diagonal"));
}
if (border_node.child("vertical"))
{
new_border.get_vertical() = read_side(border_node.child("vertical"));
}
if (border_node.child("horizontal"))
{
new_border.get_horizontal() = read_side(border_node.child("horizontal"));
}
return new_border;
return new_border;
}
void read_borders(const pugi::xml_node &borders_node, std::vector<xlnt::border> &borders)
@ -822,19 +779,11 @@ void read_formats(const pugi::xml_node &formats_node, const xlnt::detail::styles
{
xlnt::format format;
read_base_format(format_node, stylesheet, format);
// TODO do all formats have xfId?
if(format_node.attribute("xfId"))
{
auto style_index = string_to_size_t(format_node.attribute("xfId").value());
auto style_name = stylesheet.style_name_map.at(style_index);
format_styles.push_back(style_name);
}
else
{
format_styles.push_back("");
}
auto style_index = string_to_size_t(format_node.attribute("xfId").value());
auto style_name = stylesheet.style_name_map.at(style_index);
format_styles.push_back(style_name);
formats.push_back(format);
}
}
@ -882,20 +831,21 @@ bool write_color(const xlnt::color &color, pugi::xml_node color_node)
{
switch (color.get_type())
{
case xlnt::color::type::auto_:
color_node.append_attribute("auto").set_value(std::to_string(color.get_auto()).c_str());
break;
case xlnt::color::type::theme:
color_node.append_attribute("theme").set_value(std::to_string(color.get_theme()).c_str());
color_node.append_attribute("theme")
.set_value(std::to_string(color.get_theme().get_index()).c_str());
break;
case xlnt::color::type::indexed:
color_node.append_attribute("indexed").set_value(std::to_string(color.get_index()).c_str());
color_node.append_attribute("indexed")
.set_value(std::to_string(color.get_indexed().get_index()).c_str());
break;
case xlnt::color::type::rgb:
color_node.append_attribute("rgb").set_value(color.get_rgb_string().c_str());
default:
color_node.append_attribute("rgb")
.set_value(color.get_rgb().get_hex_string().c_str());
break;
default:
throw std::runtime_error("bad type");
}
return true;
@ -1039,37 +989,26 @@ bool write_borders(const std::vector<xlnt::border> &borders, pugi::xml_node &bor
{
auto border_node = borders_node.append_child("border");
std::vector<std::tuple<std::string, const std::experimental::optional<xlnt::side>>> sides;
sides.push_back(std::make_tuple("start", border_.get_start()));
sides.push_back(std::make_tuple("end", border_.get_end()));
sides.push_back(std::make_tuple("left", border_.get_left()));
sides.push_back(std::make_tuple("right", border_.get_right()));
sides.push_back(std::make_tuple("top", border_.get_top()));
sides.push_back(std::make_tuple("bottom", border_.get_bottom()));
sides.push_back(std::make_tuple("diagonal", border_.get_diagonal()));
sides.push_back(std::make_tuple("vertical", border_.get_vertical()));
sides.push_back(std::make_tuple("horizontal", border_.get_horizontal()));
for (const auto &side_tuple : sides)
for (const auto &side_name : xlnt::border::get_side_names())
{
std::string current_name = std::get<0>(side_tuple);
const auto current_side = std::get<1>(side_tuple);
const auto &current_name = side_name.second;
const auto &current_side_type = side_name.first;
if (current_side)
if (border_.has_side(current_side_type))
{
auto side_node = border_node.append_child(current_name.c_str());
const auto &current_side = border_.get_side(current_side_type);
if (current_side->get_border_style())
if (current_side.has_style())
{
auto style_string = border_style_to_string(*current_side->get_border_style());
auto style_string = border_style_to_string(current_side.get_style());
side_node.append_attribute("style").set_value(style_string.c_str());
}
if (current_side->get_color())
if (current_side.has_color())
{
auto color_node = side_node.append_child("color");
write_color(*current_side->get_color(), color_node);
write_color(current_side.get_color(), color_node);
}
}
}
@ -1219,7 +1158,9 @@ bool write_colors(const std::vector<xlnt::color> &colors, pugi::xml_node &colors
for (auto &c : colors)
{
indexed_colors_node.append_child("rgbColor").append_attribute("rgb").set_value(c.get_rgb_string().c_str());
auto rgb_color_node = indexed_colors_node.append_child("rgbColor");
auto rgb_attribute = rgb_color_node.append_attribute("rgb");
rgb_attribute.set_value(c.get_rgb().get_hex_string().c_str());
}
return true;

View File

@ -46,7 +46,6 @@ class base_format;
class style;
class number_format;
class protection;
class side;
class style;
namespace detail { struct stylesheet; }

View File

@ -217,11 +217,11 @@ void workbook_serializer::write_properties_app(pugi::xml_document &xml) const
heading_pairs_vector_node.append_child("vt:variant").append_child("vt:lpstr").text().set("Worksheets");
heading_pairs_vector_node.append_child("vt:variant")
.append_child("vt:i4")
.text().set(std::to_string(workbook_.get_sheet_names().size()).c_str());
.text().set(std::to_string(workbook_.get_sheet_titles().size()).c_str());
auto titles_of_parts_node = root_node.append_child("TitlesOfParts");
auto titles_of_parts_vector_node = titles_of_parts_node.append_child("vt:vector");
titles_of_parts_vector_node.append_attribute("size").set_value(std::to_string(workbook_.get_sheet_names().size()).c_str());
titles_of_parts_vector_node.append_attribute("size").set_value(std::to_string(workbook_.get_sheet_titles().size()).c_str());
titles_of_parts_vector_node.append_attribute("baseType").set_value("lpstr");
for (auto ws : workbook_)

View File

@ -21,130 +21,145 @@
//
// @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file
#include <xlnt/utils/exceptions.hpp>
#include <xlnt/styles/border.hpp>
namespace xlnt {
std::experimental::optional<side> &border::get_start()
bool border::border_property::has_color() const
{
return start_;
return has_color_;
}
const std::experimental::optional<side> &border::get_start() const
const color &border::border_property::get_color() const
{
return start_;
if (!has_color_)
{
throw invalid_attribute();
}
return color_;
}
std::experimental::optional<side> &border::get_end()
void border::border_property::set_color(const color &c)
{
return end_;
has_color_ = true;
color_ = c;
}
const std::experimental::optional<side> &border::get_end() const
bool border::border_property::has_style() const
{
return end_;
return has_style_;
}
std::experimental::optional<side> &border::get_left()
border_style border::border_property::get_style() const
{
return left_;
if (!has_style_)
{
throw invalid_attribute();
}
return style_;
}
const std::experimental::optional<side> &border::get_left() const
void border::border_property::set_style(border_style s)
{
return left_;
has_style_ = true;
style_ = s;
}
std::experimental::optional<side> &border::get_right()
border border::default()
{
return right_;
return border();
}
const std::experimental::optional<side> &border::get_right() const
border::border()
{
return right_;
sides_ =
{
{ xlnt::border::side::start, border_property() },
{ xlnt::border::side::end, border_property() },
{ xlnt::border::side::top, border_property() },
{ xlnt::border::side::bottom, border_property() },
{ xlnt::border::side::diagonal, border_property() }
};
}
std::experimental::optional<side> &border::get_top()
const std::unordered_map<xlnt::border::side, std::string> &border::get_side_names()
{
return top_;
static auto *sides =
new std::unordered_map<xlnt::border::side, std::string>
{
{ xlnt::border::side::start, "left" },
{ xlnt::border::side::end, "right" },
{ xlnt::border::side::top, "top" },
{ xlnt::border::side::bottom, "bottom" },
{ xlnt::border::side::diagonal, "diagonal" },
{ xlnt::border::side::vertical, "vertical" },
{ xlnt::border::side::horizontal, "horizontal" }
};
return *sides;
}
const std::experimental::optional<side> &border::get_top() const
bool border::has_side(side s) const
{
return top_;
return sides_.find(s) != sides_.end();
}
std::experimental::optional<side> &border::get_bottom()
const border::border_property &border::get_side(side s) const
{
return bottom_;
if (has_side(s))
{
return sides_.at(s);
}
throw key_not_found();
}
const std::experimental::optional<side> &border::get_bottom() const
void border::set_side(side s, const border_property &prop)
{
return bottom_;
}
std::experimental::optional<side> &border::get_diagonal()
{
return diagonal_;
}
const std::experimental::optional<side> &border::get_diagonal() const
{
return diagonal_;
}
std::experimental::optional<side> &border::get_vertical()
{
return vertical_;
}
const std::experimental::optional<side> &border::get_vertical() const
{
return vertical_;
}
std::experimental::optional<side> &border::get_horizontal()
{
return horizontal_;
}
const std::experimental::optional<side> &border::get_horizontal() const
{
return horizontal_;
sides_[s] = prop;
}
std::string border::to_hash_string() const
{
std::string hash_string;
hash_string.append(start_ ? "1" : "0");
if (start_) hash_string.append(std::to_string(start_->hash()));
hash_string.append(end_ ? "1" : "0");
if (end_) hash_string.append(std::to_string(end_->hash()));
hash_string.append(left_ ? "1" : "0");
if (left_) hash_string.append(std::to_string(left_->hash()));
hash_string.append(right_ ? "1" : "0");
if (right_) hash_string.append(std::to_string(right_->hash()));
hash_string.append(top_ ? "1" : "0");
if (top_) hash_string.append(std::to_string(top_->hash()));
hash_string.append(bottom_ ? "1" : "0");
if (bottom_) hash_string.append(std::to_string(bottom_->hash()));
hash_string.append(diagonal_ ? "1" : "0");
if (diagonal_) hash_string.append(std::to_string(diagonal_->hash()));
hash_string.append(vertical_ ? "1" : "0");
if (vertical_) hash_string.append(std::to_string(vertical_->hash()));
hash_string.append(horizontal_ ? "1" : "0");
if (horizontal_) hash_string.append(std::to_string(horizontal_->hash()));
for (const auto &side_name : get_side_names())
{
hash_string.append(side_name.second);
if (has_side(side_name.first))
{
const auto &side_properties = get_side(side_name.first);
if (side_properties.has_style())
{
hash_string.append(std::to_string(static_cast<std::size_t>(side_properties.get_style())));
}
else
{
hash_string.push_back('=');
}
if (side_properties.has_color())
{
hash_string.append(std::to_string(std::hash<xlnt::hashable>()(side_properties.get_color())));
}
else
{
hash_string.push_back('=');
}
}
else
{
hash_string.push_back('=');
}
hash_string.push_back(' ');
}
return hash_string;
}

View File

@ -21,90 +21,100 @@
//
// @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file
#include <stdexcept>
#include <xlnt/styles/color.hpp>
#include <xlnt/utils/exceptions.hpp>
namespace xlnt {
indexed_color::indexed_color(std::size_t index) : index_(index)
{
}
theme_color::theme_color(std::size_t index) : index_(index)
{
}
const color color::black()
{
return color(color::type::rgb, "ff000000");
return color(rgb_color("ff000000"));
}
const color color::white()
{
return color(color::type::rgb, "ffffffff");
return color(rgb_color("ffffffff"));
}
const color color::red()
{
return color(color::type::rgb, "ffff0000");
return color(rgb_color("ffff0000"));
}
const color color::darkred()
{
return color(color::type::rgb, "ff8b0000");
return color(rgb_color("ff8b0000"));
}
const color color::blue()
{
return color(color::type::rgb, "ff0000ff");
return color(rgb_color("ff0000ff"));
}
const color color::darkblue()
{
return color(color::type::rgb, "ff00008b");
return color(rgb_color("ff00008b"));
}
const color color::green()
{
return color(color::type::rgb, "ff00ff00");
return color(rgb_color("ff00ff00"));
}
const color color::darkgreen()
{
return color(color::type::rgb, "ff008b00");
return color(rgb_color("ff008b00"));
}
const color color::yellow()
{
return color(color::type::rgb, "ffffff00");
return color(rgb_color("ffffff00"));
}
const color color::darkyellow()
{
return color(color::type::rgb, "ffcccc00");
return color(rgb_color("ffcccc00"));
}
color::color()
: type_(type::auto_),
rgb_(rgb_color(0, 0, 0, 0)),
indexed_(0),
theme_(0)
{
}
color::color(type t, std::size_t v) : type_(t), index_(v)
color::color(const rgb_color &rgb)
: type_(type::rgb),
rgb_(rgb),
indexed_(0),
theme_(0)
{
}
color::color(type t, const std::string &v) : type_(t), rgb_string_(v)
color::color(const indexed_color &indexed)
: type_(type::indexed),
rgb_(rgb_color(0, 0, 0, 0)),
indexed_(indexed),
theme_(0)
{
}
void color::set_auto(std::size_t auto_index)
color::color(const theme_color &theme)
: type_(type::theme),
rgb_(rgb_color(0, 0, 0, 0)),
indexed_(0),
theme_(theme)
{
type_ = type::auto_;
index_ = auto_index;
}
void color::set_index(std::size_t index)
{
type_ = type::indexed;
index_ = index;
}
void color::set_theme(std::size_t theme)
{
type_ = type::theme;
index_ = theme;
}
color::type color::get_type() const
@ -112,44 +122,82 @@ color::type color::get_type() const
return type_;
}
std::size_t color::get_auto() const
bool color::is_auto() const
{
if (type_ != type::auto_)
{
throw std::runtime_error("not auto color");
}
return index_;
return type_ == type::auto_;
}
std::size_t color::get_index() const
const indexed_color &color::get_indexed() const
{
if (type_ != type::indexed)
{
throw std::runtime_error("not indexed color");
}
return index_;
assert_type(type::indexed);
return indexed_;
}
std::size_t color::get_theme() const
const theme_color &color::get_theme() const
{
if (type_ != type::theme)
{
throw std::runtime_error("not theme color");
}
return index_;
assert_type(type::theme);
return theme_;
}
std::string color::get_rgb_string() const
std::string rgb_color::get_hex_string() const
{
if (type_ != type::rgb)
{
throw std::runtime_error("not rgb color");
}
static const char* digits = "0123456789abcdef";
std::string hex_string(8, '0');
auto out_iter = hex_string.begin();
return rgb_string_;
for (auto byte : { rgba_[3], rgba_[0], rgba_[1], rgba_[2] })
{
for (auto i = 0; i < 2; ++i)
{
auto nibble = byte >> (4 * (1 - i)) & 0xf;
*(out_iter++) = digits[nibble];
}
}
return hex_string;
}
std::array<std::uint8_t, 4> rgb_color::decode_hex_string(const std::string &hex_string)
{
auto x = strtoul(hex_string.c_str(), NULL, 16);
auto a = static_cast<std::uint8_t>(x >> 24);
auto r = static_cast<std::uint8_t>((x >> 16) & 0xff);
auto g = static_cast<std::uint8_t>((x >> 8) & 0xff);
auto b = static_cast<std::uint8_t>(x & 0xff);
return { r, g, b, a };
}
rgb_color::rgb_color(const std::string &hex_string)
: rgba_(decode_hex_string(hex_string))
{
}
rgb_color::rgb_color(std::uint8_t r, std::uint8_t g, std::uint8_t b, std::uint8_t a)
: rgba_({r, g, b, a})
{
}
std::size_t indexed_color::get_index() const
{
return index_;
}
std::size_t theme_color::get_index() const
{
return index_;
}
const rgb_color &color::get_rgb() const
{
assert_type(type::rgb);
return rgb_;
}
void color::set_tint(double tint)
{
tint_ = tint;
}
std::string color::to_hash_string() const
@ -157,17 +205,33 @@ std::string color::to_hash_string() const
std::string hash_string = "color";
hash_string.append(std::to_string(static_cast<std::size_t>(type_)));
hash_string.append(std::to_string(static_cast<double>(tint_)));
if (type_ != type::rgb)
{
hash_string.append(std::to_string(index_));
}
else
{
hash_string.append(rgb_string_);
}
if (type_ == type::indexed)
{
hash_string.append("indexed");
hash_string.append(std::to_string(indexed_.get_index()));
}
else if (type_ == type::theme)
{
hash_string.append("theme");
hash_string.append(std::to_string(theme_.get_index()));
}
else if (type_ == type::rgb)
{
hash_string.append("rgb");
hash_string.append(rgb_.get_hex_string());
}
return hash_string;
}
void color::assert_type(type t) const
{
if (t != type_)
{
throw invalid_attribute();
}
}
} // namespace xlnt

View File

@ -36,7 +36,7 @@ font::font()
subscript_(false),
underline_(underline_style::none),
strikethrough_(false),
color_(xlnt::color::type::theme, 1),
color_(theme_color(1)),
has_family_(true),
family_(2),
has_scheme_(true),

View File

@ -26,31 +26,28 @@ public:
for (auto pair : known_colors)
{
TS_ASSERT_EQUALS(pair.first.get_rgb_string(), pair.second);
TS_ASSERT_EQUALS(pair.first.get_rgb().get_hex_string(), pair.second);
}
}
void test_non_rgb_colors()
{
xlnt::color indexed;
indexed.set_index(1);
TS_ASSERT_EQUALS(indexed.get_index(), 1);
TS_ASSERT_THROWS(indexed.get_auto(), std::runtime_error);
xlnt::color auto_;
TS_ASSERT(auto_.is_auto());
TS_ASSERT_THROWS(auto_.get_theme(), std::runtime_error);
TS_ASSERT_THROWS(auto_.get_indexed(), std::runtime_error);
TS_ASSERT_THROWS(auto_.get_rgb(), std::runtime_error);
xlnt::color indexed = xlnt::indexed_color(1);
TS_ASSERT(!indexed.is_auto());
TS_ASSERT_EQUALS(indexed.get_indexed().get_index(), 1);
TS_ASSERT_THROWS(indexed.get_theme(), std::runtime_error);
TS_ASSERT_THROWS(indexed.get_rgb_string(), std::runtime_error);
TS_ASSERT_THROWS(indexed.get_rgb(), std::runtime_error);
xlnt::color auto_;
auto_.set_auto(2);
TS_ASSERT_EQUALS(auto_.get_auto(), 2);
TS_ASSERT_THROWS(auto_.get_theme(), std::runtime_error);
TS_ASSERT_THROWS(auto_.get_index(), std::runtime_error);
TS_ASSERT_THROWS(auto_.get_rgb_string(), std::runtime_error);
xlnt::color theme;
theme.set_theme(3);
TS_ASSERT_EQUALS(theme.get_theme(), 3);
TS_ASSERT_THROWS(theme.get_auto(), std::runtime_error);
TS_ASSERT_THROWS(theme.get_index(), std::runtime_error);
TS_ASSERT_THROWS(theme.get_rgb_string(), std::runtime_error);
xlnt::color theme = xlnt::theme_color(3);
TS_ASSERT(!theme.is_auto());
TS_ASSERT_EQUALS(theme.get_theme().get_index(), 3);
TS_ASSERT_THROWS(theme.get_indexed(), std::runtime_error);
TS_ASSERT_THROWS(theme.get_rgb(), std::runtime_error);
}
};

View File

@ -32,11 +32,11 @@ public:
fill.get_pattern_fill().set_foreground_color(xlnt::color::black());
TS_ASSERT(fill.get_pattern_fill().get_foreground_color());
TS_ASSERT_EQUALS(*fill.get_pattern_fill().get_foreground_color(), xlnt::color::black());
TS_ASSERT_EQUALS((*fill.get_pattern_fill().get_foreground_color()).get_rgb().get_hex_string(), xlnt::color::black().get_rgb().get_hex_string());
fill.get_pattern_fill().set_background_color(xlnt::color::green());
TS_ASSERT(fill.get_pattern_fill().get_background_color());
TS_ASSERT_EQUALS(*fill.get_pattern_fill().get_background_color(), xlnt::color::green());
TS_ASSERT_EQUALS((*fill.get_pattern_fill().get_background_color()).get_rgb().get_hex_string(), xlnt::color::green().get_rgb().get_hex_string());
const auto &const_fill = fill;
TS_ASSERT(const_fill.get_pattern_fill().get_foreground_color());

View File

@ -19,8 +19,8 @@ public:
// border_style
auto ws = wb.get_active_sheet();
auto e30 = ws.get_cell("E30");
TS_ASSERT_EQUALS(e30.get_border().get_top()->get_color(), xlnt::color(xlnt::color::type::indexed, 10));
TS_ASSERT_EQUALS(e30.get_border().get_top()->get_border_style(), xlnt::border_style::thin);
TS_ASSERT_EQUALS(e30.get_border().get_side(xlnt::border::side::top).get_color().get_indexed().get_index(), 10);
TS_ASSERT_EQUALS(e30.get_border().get_side(xlnt::border::side::top).get_style(), xlnt::border_style::thin);
// underline_style
auto f30 = ws.get_cell("F30");
@ -32,7 +32,7 @@ public:
TS_ASSERT_EQUALS(e21.get_fill().get_type(), xlnt::fill::type::gradient);
TS_ASSERT_EQUALS(e21.get_fill().get_gradient_fill().get_type(), xlnt::gradient_fill::type::linear);
TS_ASSERT_EQUALS(e21.get_fill().get_gradient_fill().get_stops().size(), 2);
TS_ASSERT_EQUALS(e21.get_fill().get_gradient_fill().get_stops().at(0), xlnt::color(xlnt::color::type::rgb, "FFFF0000"));
TS_ASSERT_EQUALS(e21.get_fill().get_gradient_fill().get_stops().at(1), xlnt::color(xlnt::color::type::rgb, "FF0000FF"));
TS_ASSERT_EQUALS(e21.get_fill().get_gradient_fill().get_stops().at(0).get_rgb().get_hex_string(), "ffff0000");
TS_ASSERT_EQUALS(e21.get_fill().get_gradient_fill().get_stops().at(1).get_rgb().get_hex_string(), "ff0000ff");
}
};

View File

@ -93,6 +93,13 @@ public:
xlnt::protection hidden(true, true);
ws.get_cell("E1").set_protection(hidden);
xlnt::border b;
xlnt::border::border_property prop;
prop.set_style(xlnt::border_style::dashdot);
prop.set_color(xlnt::rgb_color("ffff0000"));
b.set_side(xlnt::border::side::top, prop);
ws.get_cell("D10").set_border(b);
std::string expected = path_helper::read_file(path_helper::get_data_directory("/writer/expected/simple-styles.xml"));
TS_ASSERT(style_xml_matches(expected, wb));
}

View File

@ -25,26 +25,6 @@ public:
auto last = std::distance(wb.begin(), wb.end()) - 1;
TS_ASSERT_EQUALS(new_sheet, wb[last]);
}
void test_create_sheet_with_name()
{
xlnt::workbook wb;
auto new_sheet = wb.create_sheet("LikeThisName");
auto last = std::distance(wb.begin(), wb.end()) - 1;
TS_ASSERT_EQUALS(new_sheet, wb[last]);
TS_ASSERT_THROWS(wb.create_sheet(std::string(40, 'a')), std::runtime_error);
TS_ASSERT_THROWS(wb.create_sheet("a:a"), std::runtime_error);
TS_ASSERT_EQUALS(wb.create_sheet("LikeThisName").get_title(), "LikeThisName1");
}
void test_create_sheet_with_name_at_index()
{
xlnt::workbook wb;
TS_ASSERT_EQUALS(wb.get_sheet_by_index(0).get_title(), "Sheet");
wb.create_sheet(0, "LikeThisName");
TS_ASSERT_EQUALS(wb.get_sheet_by_index(0).get_title(), "LikeThisName");
TS_ASSERT_EQUALS(wb.get_sheet_by_index(1).get_title(), "Sheet");
}
void test_add_correct_sheet()
{
@ -72,9 +52,9 @@ public:
ws.get_cell("B3").set_value(2);
ws.set_title("Active");
wb.copy_sheet(ws, 0);
TS_ASSERT_EQUALS(wb.get_sheet_names().at(0), "Sheet");
TS_ASSERT_EQUALS(wb.get_sheet_titles().at(0), "Sheet");
TS_ASSERT_EQUALS(wb.get_sheet_by_index(0).get_cell("B3").get_value<int>(), 2);
TS_ASSERT_EQUALS(wb.get_sheet_names().at(1), "Active");
TS_ASSERT_EQUALS(wb.get_sheet_titles().at(1), "Active");
TS_ASSERT_EQUALS(wb.get_sheet_by_index(1).get_cell("B3").get_value<int>(), 2);
}
@ -154,24 +134,11 @@ public:
void test_get_sheet_names()
{
xlnt::workbook wb;
wb.clear();
std::vector<std::string> names = {"Sheet", "Sheet1", "Sheet2", "Sheet3", "Sheet4", "Sheet5"};
for(std::size_t count = 0; count < names.size(); count++)
{
wb.create_sheet();
}
auto actual_names = wb.get_sheet_names();
std::sort(actual_names.begin(), actual_names.end());
std::sort(names.begin(), names.end());
for(std::size_t count = 0; count < names.size(); count++)
{
TS_ASSERT_EQUALS(actual_names[count], names[count]);
}
wb.create_sheet().set_title("test_get_sheet_titles");
const std::vector<std::string> expected_titles = { "Sheet", "test_get_sheet_titles" };
TS_ASSERT_EQUALS(wb.get_sheet_titles(), expected_titles);
}
void test_add_named_range()
@ -244,8 +211,8 @@ public:
{
xlnt::workbook wb;
wb.create_sheet("Sheet1");
wb.create_sheet("Sheet2");
wb.create_sheet().set_title("Sheet1");
wb.create_sheet().set_title("Sheet2");
auto iter = wb.begin();
@ -268,8 +235,8 @@ public:
{
xlnt::workbook wb;
wb.create_sheet("Sheet1");
wb.create_sheet("Sheet2");
wb.create_sheet().set_title("Sheet1");
wb.create_sheet().set_title("Sheet2");
auto iter = wb.begin();
@ -342,7 +309,7 @@ public:
wb.clear_formats();
TS_ASSERT(!wb.get_active_sheet().get_cell("B2").has_format());
wb.clear();
TS_ASSERT(wb.get_sheet_names().empty());
TS_ASSERT(wb.get_sheet_titles().empty());
}
void test_comparison()

View File

@ -70,7 +70,7 @@ workbook_impl::workbook_impl()
workbook::workbook() : d_(new detail::workbook_impl())
{
create_sheet("Sheet");
create_sheet();
create_relationship("rId2", "styles.xml", relationship::type::styles);
create_relationship("rId3", "theme/theme1.xml", relationship::type::theme);
@ -327,68 +327,7 @@ worksheet workbook::create_sheet(std::size_t index)
return worksheet(&d_->worksheets_[index]);
}
// TODO: There should be a better way to do this...
std::size_t workbook::index_from_ws_filename(const std::string &ws_filename)
{
std::string sheet_index_string(ws_filename);
sheet_index_string = sheet_index_string.substr(0, sheet_index_string.find('.'));
sheet_index_string = sheet_index_string.substr(sheet_index_string.find_last_of('/'));
auto iter = sheet_index_string.end();
iter--;
while (isdigit(*iter))
iter--;
auto first_digit = static_cast<std::size_t>(iter - sheet_index_string.begin());
sheet_index_string = sheet_index_string.substr(first_digit + 1);
auto sheet_index = static_cast<std::size_t>(std::stoll(sheet_index_string) - 1);
return sheet_index;
}
worksheet workbook::create_sheet(std::size_t index, const std::string &title)
{
auto ws = create_sheet(index);
ws.set_title(title);
return ws;
}
worksheet workbook::create_sheet(const std::string &title)
{
if (title.length() > 31)
{
throw invalid_sheet_title(title);
}
if (std::find_if(title.begin(), title.end(), [](char c) {
return c == '*' || c == ':' || c == '/' || c == '\\' || c == '?' || c == '[' || c == ']';
}) != title.end())
{
throw invalid_sheet_title(title);
}
std::string unique_title = title;
if (std::find_if(d_->worksheets_.begin(), d_->worksheets_.end(), [&](detail::worksheet_impl &ws) {
return worksheet(&ws).get_title() == unique_title;
}) != d_->worksheets_.end())
{
std::size_t suffix = 1;
while (std::find_if(d_->worksheets_.begin(), d_->worksheets_.end(), [&](detail::worksheet_impl &ws) {
return worksheet(&ws).get_title() == unique_title;
}) != d_->worksheets_.end())
{
unique_title = title + std::to_string(suffix);
suffix++;
}
}
auto ws = create_sheet();
ws.set_title(unique_title);
return ws;
}
worksheet workbook::create_sheet(const std::string &title, const relationship &rel)
worksheet workbook::create_sheet_with_rel(const std::string &title, const relationship &rel)
{
auto sheet_id = d_->worksheets_.size() + 1;
d_->worksheets_.push_back(detail::worksheet_impl(this, sheet_id, title));
@ -426,7 +365,7 @@ workbook::const_iterator workbook::cend() const
return const_iterator(*this, d_->worksheets_.size());
}
std::vector<std::string> workbook::get_sheet_names() const
std::vector<std::string> workbook::get_sheet_titles() const
{
std::vector<std::string> names;

View File

@ -7,6 +7,7 @@
#include <xlnt/worksheet/header.hpp>
#include <xlnt/worksheet/header_footer.hpp>
#include <xlnt/worksheet/worksheet.hpp>
#include <xlnt/workbook/workbook.hpp>
class test_worksheet : public CxxTest::TestSuite
{
@ -14,14 +15,14 @@ public:
void test_new_worksheet()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
TS_ASSERT(ws.get_workbook() == wb);
}
void test_get_cell()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
auto cell = ws.get_cell(xlnt::cell_reference(1, 1));
TS_ASSERT_EQUALS(cell.get_reference(), "A1");
}
@ -29,50 +30,20 @@ public:
void test_invalid_cell()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
TS_ASSERT_THROWS(xlnt::cell_reference invalid(xlnt::column_t((xlnt::column_t::index_t)0), 0), xlnt::invalid_cell_reference);
}
void test_worksheet_dimension()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
TS_ASSERT_EQUALS("A1:A1", ws.calculate_dimension());
ws.get_cell("B12").set_value("AAA");
TS_ASSERT_EQUALS("B12:B12", ws.calculate_dimension());
}
void test_squared_range()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
const std::vector<std::vector<std::string>> expected =
{
{ "A1", "B1", "C1" },
{ "A2", "B2", "C2" },
{ "A3", "B3", "C3" },
{ "A4", "B4", "C4" }
};
auto rows = ws.get_squared_range(1, 1, 3, 4);
auto expected_row_iter = expected.begin();
for(auto row : rows)
{
auto expected_cell_iter = (*expected_row_iter).begin();
for(auto cell : row)
{
TS_ASSERT_EQUALS(cell.get_reference(), *expected_cell_iter);
expected_cell_iter++;
}
expected_row_iter++;
}
}
void test_fill_rows()
{
std::size_t row = 0;
@ -80,7 +51,7 @@ public:
std::string coordinate = "A1";
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.get_cell("A1").set_value("first");
ws.get_cell("C9").set_value("last");
@ -98,7 +69,7 @@ public:
void test_iter_rows()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
const std::vector<std::vector<std::string>> expected =
{
@ -128,7 +99,7 @@ public:
void test_iter_rows_offset()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
auto rows = ws.rows("A1:C4", 1, 3);
const std::vector<std::vector<std::string>> expected =
@ -158,7 +129,7 @@ public:
void test_iter_rows_offset_int_int()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
auto rows = ws.rows(1, 3);
const std::vector<std::vector<std::string>> expected =
@ -188,7 +159,7 @@ public:
void test_get_named_range()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
wb.create_named_range("test_range", ws, "C5");
auto xlrange = ws.get_named_range("test_range");
TS_ASSERT_EQUALS(1, xlrange.length());
@ -205,7 +176,7 @@ public:
void test_get_bad_named_range()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
TS_ASSERT_THROWS(ws.get_named_range("bad_range"), xlnt::key_not_found);
}
@ -223,14 +194,14 @@ public:
void test_remove_named_range_bad()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
TS_ASSERT_THROWS(ws.remove_named_range("bad_range"), std::runtime_error);
}
void test_cell_alternate_coordinates()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
auto cell = ws.get_cell(xlnt::cell_reference(4, 8));
TS_ASSERT_EQUALS(cell.get_reference(), "D8");
}
@ -252,7 +223,7 @@ public:
void test_hyperlink_value()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.get_cell("A1").set_hyperlink("http://test.com");
TS_ASSERT_EQUALS("http://test.com", ws.get_cell("A1").get_value<std::string>());
ws.get_cell("A1").set_value("test");
@ -263,7 +234,7 @@ public:
void test_append()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.append(std::vector<std::string> {"value"});
TS_ASSERT_EQUALS("value", ws.get_cell("A1").get_value<std::string>());
}
@ -271,7 +242,7 @@ public:
void test_append_list()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.append(std::vector<std::string> {"This is A1", "This is B1"});
@ -282,7 +253,7 @@ public:
void test_append_dict_letter()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
const std::unordered_map<std::string, std::string> dict_letter =
{
@ -299,7 +270,7 @@ public:
void test_append_dict_index()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
const std::unordered_map<int, std::string> dict_index =
{
@ -313,10 +284,6 @@ public:
TS_ASSERT_EQUALS("This is C1", ws.get_cell("C1").get_value<std::string>());
}
// void test_bad_append() {}
// void test_append_range() {}
void test_append_iterator()
{
std::vector<int> range;
@ -327,7 +294,7 @@ public:
}
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.append(range.begin(), range.end());
TS_ASSERT_EQUALS(ws[xlnt::cell_reference("AD1")].get_value<int>(), 29);
@ -336,7 +303,7 @@ public:
void test_append_2d_list()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.append(std::vector<std::string> {"This is A1", "This is B1"});
ws.append(std::vector<std::string> {"This is A2", "This is B2"});
@ -348,26 +315,11 @@ public:
TS_ASSERT_EQUALS(vals[1][0].get_value<std::string>(), "This is A2");
TS_ASSERT_EQUALS(vals[1][1].get_value<std::string>(), "This is B2");
}
// void test_append_cell()
// {
// Right now, a cell cannot be created without a parent worksheet.
// This should be possible by instantiating a cell_impl, but the
// memory management is complicated.
// xlnt::workbook wb;
// xlnt::worksheet ws(wb);
// xlnt::cell cell;
// cell.set_value(25);
// ws.append({ cell });
// TS_ASSERT_EQUALS(cell.get_value<int>(), 25);
// }
void test_rows()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.get_cell("A1").set_value("first");
ws.get_cell("C9").set_value("last");
@ -387,7 +339,7 @@ public:
void test_no_rows()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
TS_ASSERT_EQUALS(ws.rows().length(), 1);
TS_ASSERT_EQUALS(ws.rows()[0].length(), 1);
@ -396,7 +348,7 @@ public:
void test_no_cols()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
TS_ASSERT_EQUALS(ws.columns().length(), 1);
TS_ASSERT_EQUALS(ws.columns()[0].length(), 1);
@ -405,7 +357,7 @@ public:
void test_one_cell()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
auto cell = ws.get_cell("A1");
@ -419,7 +371,7 @@ public:
void test_cols()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.get_cell("A1").set_value("first");
ws.get_cell("C9").set_value("last");
@ -435,7 +387,7 @@ public:
void test_auto_filter()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.auto_filter(ws.get_range("a1:f1"));
TS_ASSERT_EQUALS(ws.get_auto_filter(), "A1:F1");
@ -450,18 +402,16 @@ public:
void test_getitem()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
xlnt::cell cell = ws[xlnt::cell_reference("A1")];
TS_ASSERT_EQUALS(cell.get_reference().to_string(), "A1");
TS_ASSERT_EQUALS(cell.get_data_type(), xlnt::cell::type::null);
}
// void test_getitem_invalid() {}
void test_setitem()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws[xlnt::cell_reference("A12")].set_value(5);
TS_ASSERT(ws[xlnt::cell_reference("A12")].get_value<int>() == 5);
}
@ -469,21 +419,18 @@ public:
void test_getslice()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
auto cell_range = ws("A1", "B2");
TS_ASSERT_EQUALS(cell_range[0][0], ws.get_cell("A1"));
TS_ASSERT_EQUALS(cell_range[1][0], ws.get_cell("A2"));
TS_ASSERT_EQUALS(cell_range[0][1], ws.get_cell("B1"));
TS_ASSERT_EQUALS(cell_range[1][1], ws.get_cell("B2"));
}
// void test_get_column() {}
// void test_get_row() {}
void test_freeze()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.freeze_panes(ws.get_cell("b2"));
TS_ASSERT_EQUALS(ws.get_frozen_panes(), "B2");
@ -501,7 +448,7 @@ public:
void test_merged_cells_lookup()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.get_cell("A2").set_value("test");
ws.merge_cells("A1:N50");
auto all_merged = ws.get_merged_ranges();
@ -517,14 +464,14 @@ public:
void test_merged_cell_ranges()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
TS_ASSERT_EQUALS(ws.get_merged_ranges().size(), 0);
}
void test_merge_range_string()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.get_cell("A1").set_value(1);
ws.get_cell("D4").set_value(16);
ws.merge_cells("A1:D4");
@ -536,7 +483,7 @@ public:
void test_merge_coordinate()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.merge_cells(1, 1, 4, 4);
std::vector<xlnt::range_reference> expected = { xlnt::range_reference("A1:D4") };
TS_ASSERT_EQUALS(ws.get_merged_ranges(), expected);
@ -545,7 +492,7 @@ public:
void test_unmerge_bad()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
TS_ASSERT_THROWS(ws.unmerge_cells("A1:D3"), std::runtime_error);
}
@ -553,7 +500,7 @@ public:
void test_unmerge_range_string()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.merge_cells("A1:D4");
TS_ASSERT_EQUALS(ws.get_merged_ranges().size(), 1);
ws.unmerge_cells("A1:D4");
@ -563,7 +510,7 @@ public:
void test_unmerge_coordinate()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.merge_cells("A1:D4");
TS_ASSERT_EQUALS(ws.get_merged_ranges().size(), 1);
ws.unmerge_cells(1, 1, 4, 4);
@ -627,7 +574,7 @@ public:
void test_freeze_panes_horiz()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.freeze_panes("A4");
auto view = ws.get_sheet_view();
@ -644,7 +591,7 @@ public:
void test_freeze_panes_vert()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.freeze_panes("D1");
auto view = ws.get_sheet_view();
@ -661,7 +608,7 @@ public:
void test_freeze_panes_both()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.freeze_panes("D4");
auto view = ws.get_sheet_view();
@ -681,14 +628,14 @@ public:
void test_min_column()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
TS_ASSERT_EQUALS(ws.get_lowest_column(), 1);
}
void test_max_column()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws[xlnt::cell_reference("F1")].set_value(10);
ws[xlnt::cell_reference("F2")].set_value(32);
ws[xlnt::cell_reference("F3")].set_formula("=F1+F2");
@ -699,14 +646,14 @@ public:
void test_min_row()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
TS_ASSERT_EQUALS(ws.get_lowest_row(), 1);
}
void test_max_row()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.append();
ws.append(std::vector<int> { 5 });
ws.append();
@ -717,7 +664,7 @@ public:
void test_const_iterators()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.append({"A1", "B1", "C1"});
ws.append({"A2", "B2", "C2"});
@ -745,7 +692,7 @@ public:
void test_const_reverse_iterators()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.append({"A1", "B1", "C1"});
ws.append({"A2", "B2", "C2"});
@ -780,7 +727,7 @@ public:
void test_column_major_iterators()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.append({"A1", "B1", "C1"});
ws.append({"A2", "B2", "C2"});
@ -819,7 +766,7 @@ public:
void test_reverse_column_major_iterators()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.append({"A1", "B1", "C1"});
ws.append({"A2", "B2", "C2"});
@ -861,7 +808,7 @@ public:
void test_const_column_major_iterators()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.append({"A1", "B1", "C1"});
ws.append({"A2", "B2", "C2"});
@ -898,7 +845,7 @@ public:
void test_const_reverse_column_major_iterators()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.append({"A1", "B1", "C1"});
ws.append({"A2", "B2", "C2"});
@ -1096,19 +1043,6 @@ public:
TS_ASSERT_EQUALS((*row_iter).get_value<bool>(), false);
}
void test_get_squared_range()
{
xlnt::workbook wb;
auto ws = wb.get_active_sheet();
ws.get_cell("A2").set_value(3.14);
ws.get_cell("B3").set_value(false);
auto range = ws.get_squared_range(1, 2, 2, 3);
TS_ASSERT_EQUALS((*(*range.begin()).begin()).get_value<double>(), 3.14);
TS_ASSERT_EQUALS((*(--(*(--range.end())).end())).get_value<bool>(), false);
}
void test_operators()
{
xlnt::workbook wb;
@ -1138,7 +1072,7 @@ public:
void test_reserve()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.reserve(1000);
//TODO: actual tests go here
@ -1147,7 +1081,7 @@ public:
void test_iterate()
{
xlnt::workbook wb;
xlnt::worksheet ws(wb);
auto ws = wb.get_active_sheet();
ws.get_cell("B3").set_value("B3");
ws.get_cell("C7").set_value("C7");
@ -1209,4 +1143,14 @@ public:
TS_ASSERT_EQUALS(ws.get_point_pos({0, 0}), "A1");
}
void test_named_range_named_cell_reference()
{
xlnt::workbook wb;
auto ws = wb.get_active_sheet();
TS_ASSERT_THROWS(ws.create_named_range("A1", "A2"), std::runtime_error);
TS_ASSERT_THROWS(ws.create_named_range("XFD1048576", "A2"), std::runtime_error);
TS_ASSERT_THROWS_NOTHING(ws.create_named_range("XFE1048576", "A2"));
TS_ASSERT_THROWS_NOTHING(ws.create_named_range("XFD1048577", "A2"));
}
};

View File

@ -34,6 +34,7 @@
#include <xlnt/utils/exceptions.hpp>
#include <xlnt/workbook/named_range.hpp>
#include <xlnt/workbook/workbook.hpp>
#include <xlnt/workbook/worksheet_iterator.hpp>
#include <xlnt/worksheet/cell_iterator.hpp>
#include <xlnt/worksheet/const_cell_iterator.hpp>
#include <xlnt/worksheet/const_range_iterator.hpp>
@ -61,11 +62,6 @@ worksheet::worksheet(const worksheet &rhs) : d_(rhs.d_)
{
}
worksheet::worksheet(workbook &parent, const std::string &title)
: d_(title == "" ? parent.create_sheet().d_ : parent.create_sheet(title).d_)
{
}
bool worksheet::has_frozen_panes() const
{
return get_frozen_panes() != cell_reference("A1");
@ -73,14 +69,17 @@ bool worksheet::has_frozen_panes() const
std::string worksheet::unique_sheet_name(const std::string &value) const
{
auto names = get_workbook().get_sheet_names();
auto names = get_workbook().get_sheet_titles();
auto match = std::find(names.begin(), names.end(), value);
std::size_t append = 0;
while (match != names.end())
{
append++;
match = std::find(names.begin(), names.end(), value + std::to_string(append));
}
return append == 0 ? value : value + std::to_string(append);
}
@ -98,7 +97,7 @@ void worksheet::create_named_range(const std::string &name, const range_referenc
{
auto temp = cell_reference::split_reference(name);
if (column_t(temp.first).index <= column_t("XFD").index || temp.second <= 1048576)
if (column_t(temp.first).index <= column_t("XFD").index && temp.second <= 1048576)
{
throw std::runtime_error("named range name must be outside the range A1-XFD1048576");
}
@ -108,8 +107,7 @@ void worksheet::create_named_range(const std::string &name, const range_referenc
{
// must not be a valid cell reference
}
d_->named_ranges_[name] = named_range(name, targets);
}
@ -246,7 +244,25 @@ std::string worksheet::get_title() const
void worksheet::set_title(const std::string &title)
{
d_->title_ = title;
if (title.length() > 31)
{
throw invalid_sheet_title(title);
}
if (title.find_first_of("*:/\\?[]") != std::string::npos)
{
throw invalid_sheet_title(title);
}
auto same_title = std::find_if(get_workbook().begin(), get_workbook().end(),
[&](worksheet ws) { return ws.get_title() == title; });
if (same_title != get_workbook().end() && *same_title != *this)
{
throw invalid_sheet_title(title);
}
d_->title_ = title;
}
cell_reference worksheet::get_frozen_panes() const
@ -456,18 +472,6 @@ const range worksheet::get_range(const range_reference &reference) const
return range(*this, reference);
}
range worksheet::get_squared_range(column_t min_col, row_t min_row, column_t max_col, row_t max_row)
{
range_reference reference(min_col, min_row, max_col, max_row);
return get_range(reference);
}
const range worksheet::get_squared_range(column_t min_col, row_t min_row, column_t max_col, row_t max_row) const
{
range_reference reference(min_col, min_row, max_col, max_row);
return get_range(reference);
}
const std::vector<relationship> &worksheet::get_relationships() const
{
return d_->relationships_;

View File

@ -9,7 +9,7 @@
<scheme val="minor"/>
</font>
<font>
<u/>
<u val="doubleAccounting"/>
<sz val="12"/>
<color theme="10"/>
<name val="Calibri"/>
@ -25,7 +25,9 @@
<scheme val="minor"/>
</font>
<font>
<b/>
<b val="0"/>
<strike val="0"/>
<i val="0"/>
<sz val="12"/>
<color theme="1"/>
<name val="Arial"/>

View File

@ -20,7 +20,7 @@
<patternFill patternType="gray125"/>
</fill>
</fills>
<borders count="1">
<borders count="2">
<border>
<left/>
<right/>
@ -28,11 +28,20 @@
<bottom/>
<diagonal/>
</border>
<border>
<left/>
<right/>
<top style="dashdot">
<color rgb="ffff0000"/>
</top>
<bottom/>
<diagonal/>
</border>
</borders>
<cellStyleXfs count="1">
<xf numFmtId="0" fontId="0" fillId="0" borderId="0"/>
</cellStyleXfs>
<cellXfs count="5">
<cellXfs count="6">
<xf borderId="0" fillId="0" fontId="0" numFmtId="0" quotePrefix="0" pivotButton="0" xfId="0"/>
<xf borderId="0" fillId="0" fontId="0" numFmtId="9" quotePrefix="0" pivotButton="0" xfId="0"/>
<xf borderId="0" fillId="0" fontId="0" numFmtId="164" quotePrefix="0" pivotButton="0" xfId="0"/>
@ -40,9 +49,10 @@
<xf applyProtection="1" borderId="0" fillId="0" fontId="0" quotePrefix="0" pivotButton="0" numFmtId="0" xfId="0">
<protection hidden="1" locked="1"/>
</xf>
<xf numFmtId="0" fontId="0" fillId="0" borderId="1" applyBorder="1" xfId="0" />
</cellXfs>
<cellStyles count="1">
<cellStyle name="Normal" hidden="0" xfId="0" builtinId="0"/>
</cellStyles>
<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleLight16"/>
</styleSheet>
</styleSheet>

View File

@ -28,6 +28,15 @@
<bottom/>
<diagonal/>
</border>
<border>
<left/>
<right/>
<top style="dashdot">
<color rgb="ffff0000"/>
</top>
<bottom/>
<diagonal/>
</border>
</borders>
<cellStyleXfs count="1">
<xf numFmtId="0" fontId="0" fillId="0" borderId="0"/>
@ -40,10 +49,11 @@
<xf applyProtection="1" borderId="0" fillId="0" fontId="0" numFmtId="0" xfId="0">
<protection hidden="1" locked="1"/>
</xf>
<xf numFmtId="0" fontId="0" fillId="0" borderId="1" applyBorder="1" xfId="0" />
</cellXfs>
<cellStyles count="1">
<cellStyle name="Normal" xfId="0" builtinId="0"/>
</cellStyles>
<dxfs count="0" />
<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleLight16"/>
</styleSheet>
</styleSheet>