continue implementing styles

This commit is contained in:
Thomas Fussell 2015-10-18 15:30:46 -04:00
parent d1ea08fd13
commit 2f07e0ae62
27 changed files with 934 additions and 501 deletions

View File

@ -32,6 +32,8 @@
namespace xlnt { namespace xlnt {
enum class calendar;
class cell_reference; class cell_reference;
class comment; class comment;
class relationship; class relationship;
@ -107,28 +109,22 @@ public:
bool has_hyperlink() const; bool has_hyperlink() const;
// style // style
bool has_style() const; std::size_t get_style_id() const;
style &get_style(); const number_format &get_number_format() const;
const style &get_style() const; void set_number_format(const number_format &format);
void set_style(const style &s);
// style shortcuts
std::string get_number_format();
std::string get_number_format() const;
void set_number_format(const std::string &format_code, int index = -1);
font &get_font();
const font &get_font() const; const font &get_font() const;
fill &get_fill(); void set_font(const font &font_);
const fill &get_fill() const; const fill &get_fill() const;
border &get_border(); void set_fill(const fill &fill_);
const border &get_border() const; const border &get_border() const;
alignment &get_alignment(); void set_border(const border &border_);
const alignment &get_alignment() const; const alignment &get_alignment() const;
protection &get_protection(); void set_alignment(const alignment &alignment_);
const protection &get_protection() const; const protection &get_protection() const;
bool pivot_button(); void set_protection(const protection &protection_);
void set_pivot_button(bool b);
bool pivot_button() const; bool pivot_button() const;
bool quote_prefix(); void set_quote_prefix(bool b);
bool quote_prefix() const; bool quote_prefix() const;
// comment // comment
@ -168,6 +164,8 @@ public:
worksheet get_parent(); worksheet get_parent();
const worksheet get_parent() const; const worksheet get_parent() const;
calendar get_base_date() const;
// operators // operators
cell &operator=(const cell &rhs); cell &operator=(const cell &rhs);
@ -178,8 +176,10 @@ public:
friend bool operator<(cell left, cell right); friend bool operator<(cell left, cell right);
private: private:
void set_value_guess_type(const std::string &s);
friend class worksheet; friend class worksheet;
friend struct detail::cell_impl;
friend class style;
cell(detail::cell_impl *d); cell(detail::cell_impl *d);
detail::cell_impl *d_; detail::cell_impl *d_;
}; };

View File

@ -152,6 +152,8 @@ struct datetime
/// </summary> /// </summary>
struct timedelta struct timedelta
{ {
static timedelta from_number(long double number);
timedelta(int days_, int hours_, int minutes_ = 0, int seconds_ = 0, int microseconds_ = 0) timedelta(int days_, int hours_, int minutes_ = 0, int seconds_ = 0, int microseconds_ = 0)
: days(days_), : days(days_),
hours(hours_), hours(hours_),

View File

@ -31,5 +31,6 @@ namespace xlnt {
class workbook; class workbook;
xlnt::workbook load_workbook(const std::vector<std::uint8_t> &bytes); xlnt::workbook load_workbook(const std::vector<std::uint8_t> &bytes);
xlnt::workbook load_workbook(const std::string &filename);
} // namespace xlnt } // namespace xlnt

View File

@ -64,6 +64,8 @@ public:
&& indent_ == other.indent_; && indent_ == other.indent_;
} }
std::size_t hash() const { return 0; }
private: private:
horizontal_alignment horizontal_ = horizontal_alignment::general; horizontal_alignment horizontal_ = horizontal_alignment::general;
vertical_alignment vertical_ = vertical_alignment::bottom; vertical_alignment vertical_ = vertical_alignment::bottom;

View File

@ -23,6 +23,8 @@
// @author: see AUTHORS file // @author: see AUTHORS file
#pragma once #pragma once
#include <cstddef>
#include <xlnt/styles/color.hpp> #include <xlnt/styles/color.hpp>
namespace xlnt { namespace xlnt {
@ -103,6 +105,8 @@ public:
&& diagonal_up == other.diagonal_up && diagonal_up == other.diagonal_up
&& diagonal_down == other.diagonal_down; && diagonal_down == other.diagonal_down;
} }
std::size_t hash() const { return 0; }
}; };
} // namespace xlnt } // namespace xlnt

View File

@ -60,10 +60,12 @@ public:
color start_color = color::white; color start_color = color::white;
color end_color = color::black; color end_color = color::black;
bool operator==(const fill &other) const virtual bool operator==(const fill &other) const
{ {
return type_ == other.type_; return type_ == other.type_;
} }
virtual std::size_t hash() const { return 0; }
}; };
class pattern_fill : public fill class pattern_fill : public fill
@ -72,6 +74,8 @@ public:
void set_pattern_type(const std::string &type) { type_ = type; } void set_pattern_type(const std::string &type) { type_ = type; }
void set_foreground_color(const std::string &hex) { foreground_color_ = hex; } void set_foreground_color(const std::string &hex) { foreground_color_ = hex; }
std::size_t hash() const override { return 0; }
private: private:
std::string type_; std::string type_;
std::string foreground_color_; std::string foreground_color_;

View File

@ -29,6 +29,8 @@
namespace xlnt { namespace xlnt {
class style;
class font class font
{ {
public: public:
@ -56,7 +58,15 @@ public:
&& color_ == other.color_; && color_ == other.color_;
} }
int get_size() const { return size_; }
std::string get_name() const { return name_; }
bool is_bold() const { return bole_; }
std::size_t hash() const { return 0; }
private: private:
friend class style;
std::string name_ = "Calibri"; std::string name_ = "Calibri";
int size_ = 11; int size_ = 11;
bool bold_ = false; bool bold_ = false;

View File

@ -86,55 +86,27 @@ public:
static std::string builtin_format_code(int index); static std::string builtin_format_code(int index);
static format lookup_format(int code); static format lookup_format(int code);
static bool is_date_format(const std::string &format);
static bool is_builtin(const std::string &format); static bool is_builtin(const std::string &format);
number_format() : format_code_(format::general), format_index_(0) {} number_format();
number_format(format code) : format_code_(code), format_index_(reversed_builtin_formats().at(format_strings().at(code))) {} number_format(format code);
number_format(const std::string &code);
format get_format_code() const { return format_code_; } format get_format_code() const;
void set_format_code(format format_code, int index = -1) void set_format_code(format format_code);
{
format_code_ = format_code;
if(format_code_ != format::unknown) void set_format_string(const std::string &format_code);
{ std::string get_format_string() const;
set_format_code_string(format_strings().at(format_code), index);
}
}
void set_format_code_string(const std::string &format_code, int index) int get_format_index() const { return format_index_; }
{
custom_format_code_ = format_code;
format_index_ = index;
const auto &reversed = reversed_builtin_formats(); std::size_t hash() const;
auto match = reversed.find(format_code);
format_code_ = format::unknown;
if(match != reversed.end())
{
format_index_ = match->second;
for(const auto &p : format_strings())
{
if(p.second == format_code)
{
format_code_ = p.first;
break;
}
}
}
}
std::string get_format_code_string() const;
private: private:
std::string custom_format_code_ = ""; format format_code_;
format format_code_ = format::general; int format_index_;
int format_index_ = 0; std::string format_string_;
}; };
} // namespace xlnt } // namespace xlnt

View File

@ -23,6 +23,8 @@
// @author: see AUTHORS file // @author: see AUTHORS file
#pragma once #pragma once
#include <cstddef>
namespace xlnt { namespace xlnt {
class protection class protection
@ -48,6 +50,8 @@ public:
return locked_ == other.locked_ && hidden_ == other.hidden_; return locked_ == other.locked_ && hidden_ == other.hidden_;
} }
std::size_t hash() const { return 0; }
private: private:
type locked_; type locked_;
type hidden_; type hidden_;

View File

@ -23,64 +23,55 @@
// @author: see AUTHORS file // @author: see AUTHORS file
#pragma once #pragma once
#include "font.hpp"
#include "fill.hpp"
#include "borders.hpp"
#include "alignment.hpp"
#include "color.hpp"
#include "number_format.hpp"
#include "protection.hpp"
namespace xlnt { namespace xlnt {
namespace detail {
struct cell_impl;
} // namespace detail
class alignment;
class border;
class font;
class fill;
class number_format;
class protection;
class cell;
class style class style
{ {
public: public:
style(bool is_static = false) : static_(is_static) {} const style default_style();
style();
style(const style &rhs); style(const style &rhs);
style &operator=(const style &rhs);
style copy() const; style copy() const;
font &get_font(); std::size_t hash() const;
const font &get_font() const; const font &get_font() const;
void set_font(font font);
fill &get_fill();
const fill &get_fill() const; const fill &get_fill() const;
void set_fill(fill &fill);
border &get_border();
const border &get_border() const; const border &get_border() const;
void set_border(border borders); const alignment &get_alignment() const;
const number_format &get_number_format() const;
alignment &get_alignment();
const alignment get_alignment() const;
void set_alignment(alignment alignment);
number_format &get_number_format() { return number_format_; }
const number_format &get_number_format() const { return number_format_; }
void set_number_format(number_format number_format);
protection &get_protection();
const protection &get_protection() const; const protection &get_protection() const;
void set_protection(protection protection); bool pivot_button() const;
bool quote_prefix() const;
bool pivot_button();
void set_pivot_button(bool pivot);
bool quote_prefix();
void set_quote_prefix(bool quote);
private: private:
bool static_ = false; cell get_parent();
font font_; const cell get_parent() const;
fill fill_; detail::cell_impl *parent_;
border border_; std::size_t font_id_;
alignment alignment_; std::size_t fill_id_;
number_format number_format_; std::size_t border_id_;
protection protection_; std::size_t alignment_id_;
bool pivot_button_; std::size_t number_format_id_;
bool quote_prefix_; std::size_t protection_id_;
std::size_t style_id_;
}; };
} // namespace xlnt } // namespace xlnt

View File

@ -41,11 +41,13 @@ class drawing;
class fill; class fill;
class font; class font;
class named_range; class named_range;
class number_format;
class pattern_fill; class pattern_fill;
class protection; class protection;
class range; class range;
class range_reference; class range_reference;
class relationship; class relationship;
class style;
class worksheet; class worksheet;
class zip_file; class zip_file;
@ -206,11 +208,36 @@ public:
void add_color(color c); void add_color(color c);
void add_number_format(const std::string &format); void add_number_format(const std::string &format);
const std::unordered_map<std::size_t, alignment> &get_alignments() const;
const std::unordered_map<std::size_t, border> &get_borders() const;
const std::unordered_map<std::size_t, fill> &get_fills() const;
const std::unordered_map<std::size_t, font> &get_fonts() const;
const std::unordered_map<std::size_t, number_format> &get_number_formats() const;
const std::unordered_map<std::size_t, protection> &get_protections() const;
const number_format &get_number_format(std::size_t style_id) const;
std::size_t set_number_format(const number_format &format, std::size_t style_id);
const font &get_font(std::size_t style_id) const;
std::size_t set_font(const font &font_, std::size_t style_id);
const fill &get_fill(std::size_t style_id) const;
std::size_t set_fill(const fill &fill_, std::size_t style_id);
const border &get_border(std::size_t style_id) const;
std::size_t set_border(const border &border_, std::size_t style_id);
const alignment &get_alignment(std::size_t style_id) const;
std::size_t set_alignment(const alignment &alignment_, std::size_t style_id);
const protection &get_protection(std::size_t style_id) const;
std::size_t set_protection(const protection &protection_, std::size_t style_id);
bool get_pivot_button(std::size_t style_id) const;
bool get_quote_prefix(std::size_t style_id) const;
void set_code_name(const std::string &code_name); void set_code_name(const std::string &code_name);
bool has_loaded_theme(); bool has_loaded_theme();
std::string get_loaded_theme(); std::string get_loaded_theme();
style get_style(std::size_t style_id);
std::size_t add_style(style style_);
private: private:
friend class worksheet; friend class worksheet;
std::shared_ptr<detail::workbook_impl> d_; std::shared_ptr<detail::workbook_impl> d_;

View File

@ -39,10 +39,8 @@ public:
style_writer(workbook &wb); style_writer(workbook &wb);
style_writer(const style_writer &); style_writer(const style_writer &);
style_writer &operator=(const style_writer &); style_writer &operator=(const style_writer &);
std::unordered_map<std::size_t, std::string> get_style_by_hash() const;
std::string write_table() const;
std::vector<style> get_styles() const;
std::string write_table() const;
std::string write_number_formats(); std::string write_number_formats();
private: private:
@ -56,7 +54,6 @@ private:
void write_dxfs(); void write_dxfs();
void write_table_styles(); void write_table_styles();
std::vector<style> style_list_;
workbook &wb_; workbook &wb_;
}; };

View File

@ -6,12 +6,12 @@
#include <xlnt/cell/cell_reference.hpp> #include <xlnt/cell/cell_reference.hpp>
#include <xlnt/cell/comment.hpp> #include <xlnt/cell/comment.hpp>
#include <xlnt/common/datetime.hpp> #include <xlnt/common/datetime.hpp>
#include <xlnt/common/relationship.hpp>
#include <xlnt/worksheet/worksheet.hpp>
#include <xlnt/common/exceptions.hpp> #include <xlnt/common/exceptions.hpp>
#include <xlnt/common/relationship.hpp>
#include <xlnt/workbook/workbook.hpp> #include <xlnt/workbook/workbook.hpp>
#include <xlnt/workbook/document_properties.hpp> #include <xlnt/workbook/document_properties.hpp>
#include <xlnt/common/exceptions.hpp> #include <xlnt/worksheet/worksheet.hpp>
#include <xlnt/styles/color.hpp>
#include "detail/cell_impl.hpp" #include "detail/cell_impl.hpp"
#include "detail/comment_impl.hpp" #include "detail/comment_impl.hpp"
@ -87,6 +87,36 @@ std::vector<std::string> split_string(const std::string &string, char delim)
return split; return split;
} }
std::vector<std::string> split_string_any(const std::string &string, const std::string &delims)
{
std::vector<std::string> split;
std::string::size_type previous_index = 0;
auto separator_index = string.find_first_of(delims);
while(separator_index != std::string::npos)
{
auto part = string.substr(previous_index, separator_index - previous_index);
if(!part.empty())
{
split.push_back(part);
}
previous_index = separator_index + 1;
separator_index = string.find_first_of(delims, previous_index);
}
split.push_back(string.substr(previous_index));
return split;
}
bool is_date_format(const std::string &format_string)
{
auto not_in = format_string.find_first_not_of("/-:, mMyYdDhHsS");
return not_in == std::string::npos;
}
bool is_valid_color(const std::string &color) bool is_valid_color(const std::string &color)
{ {
static const std::vector<std::string> colors = { "Black", "Green" static const std::vector<std::string> colors = { "Black", "Green"
@ -288,14 +318,180 @@ format_sections parse_format_sections(const std::string &combined)
return result; return result;
} }
std::string format_section(long double number, const section &format) const std::vector<std::string> MonthNames =
{ {
if(number == static_cast<long long int>(number)) "January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
};
std::string format_section(long double number, const section &format, xlnt::calendar base_date)
{ {
return std::to_string(static_cast<long long int>(number)); const std::string unquoted = "$+(:^'{<=-/)!&~}> ";
std::string result;
if(is_date_format(format.value))
{
const std::string date_unquoted = ",-/: ";
const std::vector<std::string> dates =
{
"m",
"mm",
"mmm",
"mmmmm",
"mmmmmm",
"d",
"dd",
"ddd",
"dddd",
"yy",
"yyyy"
"h",
"[h]",
"hh",
"m",
"[m]",
"mm",
"s",
"[s]",
"ss",
"AM/PM",
"am/pm",
"A/P",
"a/p"
};
auto split = split_string_any(format.value, date_unquoted);
std::string::size_type index = 0, prev = 0;
auto d = xlnt::datetime::from_number(number, base_date);
bool processed_month = false;
for(auto part : split)
{
while(format.value.substr(index, part.size()) != part)
{
index++;
} }
return std::to_string(number); auto between = format.value.substr(prev, index - prev);
result.append(between);
if(part == "m" && !processed_month)
{
result.append(std::to_string(d.month));
processed_month = true;
}
if(part == "mm" && !processed_month)
{
if(d.month < 10)
{
result.append("0");
}
result.append(std::to_string(d.month));
processed_month = true;
}
if(part == "mmm" && !processed_month)
{
result.append(MonthNames.at(d.month - 1).substr(0, 3));
processed_month = true;
}
if(part == "mmmm" && !processed_month)
{
result.append(MonthNames.at(d.month - 1));
processed_month = true;
}
if(part == "d")
{
result.append(std::to_string(d.day));
}
if(part == "dd")
{
if(d.day < 10)
{
result.append("0");
}
result.append(std::to_string(d.day));
}
if(part == "yyyy")
{
result.append(std::to_string(d.year));
}
if(part == "h")
{
result.append(std::to_string(d.hour));
processed_month = true;
}
if(part == "hh")
{
if(d.hour < 10)
{
result.append("0");
}
result.append(std::to_string(d.hour));
processed_month = true;
}
if(part == "m")
{
result.append(std::to_string(d.minute));
}
if(part == "mm")
{
if(d.minute < 10)
{
result.append("0");
}
result.append(std::to_string(d.minute));
}
if(part == "s")
{
result.append(std::to_string(d.second));
}
if(part == "ss")
{
if(d.second < 10)
{
result.append("0");
}
result.append(std::to_string(d.second));
}
index += part.size();
prev = index;
}
if(index < format.value.size())
{
result.append(format.value.substr(index));
}
}
else if(number == static_cast<long long int>(number))
{
result = std::to_string(static_cast<long long int>(number));
}
else
{
result = std::to_string(number);
}
return result;
} }
std::string format_section(const std::string &text, const section &format) std::string format_section(const std::string &text, const section &format)
@ -334,21 +530,21 @@ std::string format_section(const std::string &text, const section &format)
return first_part + middle_part + last_part; return first_part + middle_part + last_part;
} }
std::string format_number(long double number, const std::string &format) std::string format_number(long double number, const std::string &format, xlnt::calendar base_date)
{ {
auto sections = parse_format_sections(format); auto sections = parse_format_sections(format);
if(number > 0) if(number > 0)
{ {
return format_section(number, sections.first); return format_section(number, sections.first, base_date);
} }
else if(number < 0) else if(number < 0)
{ {
return format_section(number, sections.second); return format_section(number, sections.second, base_date);
} }
// number == 0 // number == 0
return format_section(number, sections.third); return format_section(number, sections.third, base_date);
} }
std::string format_text(const std::string &text, const std::string &format) std::string format_text(const std::string &text, const std::string &format)
@ -358,12 +554,6 @@ std::string format_text(const std::string &text, const std::string &format)
return format_section(text, sections.fourth); return format_section(text, sections.fourth);
} }
bool is_date_format(const std::string &format_string)
{
auto not_in = format_string.find_first_not_of("/-:, mMyYdDhHsS");
return not_in == std::string::npos;
}
} }
namespace xlnt { namespace xlnt {
@ -411,7 +601,6 @@ bool cell::garbage_collectible() const
template<> template<>
void cell::set_value(bool b) void cell::set_value(bool b)
{ {
d_->is_date_ = false;
d_->value_numeric_ = b ? 1 : 0; d_->value_numeric_ = b ? 1 : 0;
d_->type_ = type::boolean; d_->type_ = type::boolean;
} }
@ -419,7 +608,6 @@ void cell::set_value(bool b)
template<> template<>
void cell::set_value(std::int8_t i) void cell::set_value(std::int8_t i)
{ {
d_->is_date_ = false;
d_->value_numeric_ = static_cast<long double>(i); d_->value_numeric_ = static_cast<long double>(i);
d_->type_ = type::numeric; d_->type_ = type::numeric;
} }
@ -427,7 +615,6 @@ void cell::set_value(std::int8_t i)
template<> template<>
void cell::set_value(std::int16_t i) void cell::set_value(std::int16_t i)
{ {
d_->is_date_ = false;
d_->value_numeric_ = static_cast<long double>(i); d_->value_numeric_ = static_cast<long double>(i);
d_->type_ = type::numeric; d_->type_ = type::numeric;
} }
@ -435,7 +622,6 @@ void cell::set_value(std::int16_t i)
template<> template<>
void cell::set_value(std::int32_t i) void cell::set_value(std::int32_t i)
{ {
d_->is_date_ = false;
d_->value_numeric_ = static_cast<long double>(i); d_->value_numeric_ = static_cast<long double>(i);
d_->type_ = type::numeric; d_->type_ = type::numeric;
} }
@ -443,7 +629,6 @@ void cell::set_value(std::int32_t i)
template<> template<>
void cell::set_value(std::int64_t i) void cell::set_value(std::int64_t i)
{ {
d_->is_date_ = false;
d_->value_numeric_ = static_cast<long double>(i); d_->value_numeric_ = static_cast<long double>(i);
d_->type_ = type::numeric; d_->type_ = type::numeric;
} }
@ -451,7 +636,6 @@ void cell::set_value(std::int64_t i)
template<> template<>
void cell::set_value(std::uint8_t i) void cell::set_value(std::uint8_t i)
{ {
d_->is_date_ = false;
d_->value_numeric_ = static_cast<long double>(i); d_->value_numeric_ = static_cast<long double>(i);
d_->type_ = type::numeric; d_->type_ = type::numeric;
} }
@ -459,7 +643,6 @@ void cell::set_value(std::uint8_t i)
template<> template<>
void cell::set_value(std::uint16_t i) void cell::set_value(std::uint16_t i)
{ {
d_->is_date_ = false;
d_->value_numeric_ = static_cast<long double>(i); d_->value_numeric_ = static_cast<long double>(i);
d_->type_ = type::numeric; d_->type_ = type::numeric;
} }
@ -467,7 +650,6 @@ void cell::set_value(std::uint16_t i)
template<> template<>
void cell::set_value(std::uint32_t i) void cell::set_value(std::uint32_t i)
{ {
d_->is_date_ = false;
d_->value_numeric_ = static_cast<long double>(i); d_->value_numeric_ = static_cast<long double>(i);
d_->type_ = type::numeric; d_->type_ = type::numeric;
} }
@ -475,7 +657,6 @@ void cell::set_value(std::uint32_t i)
template<> template<>
void cell::set_value(std::uint64_t i) void cell::set_value(std::uint64_t i)
{ {
d_->is_date_ = false;
d_->value_numeric_ = static_cast<long double>(i); d_->value_numeric_ = static_cast<long double>(i);
d_->type_ = type::numeric; d_->type_ = type::numeric;
} }
@ -484,7 +665,6 @@ void cell::set_value(std::uint64_t i)
template<> template<>
void cell::set_value(unsigned long i) void cell::set_value(unsigned long i)
{ {
d_->is_date_ = false;
d_->value_numeric_ = static_cast<long double>(i); d_->value_numeric_ = static_cast<long double>(i);
d_->type_ = type::numeric; d_->type_ = type::numeric;
} }
@ -494,7 +674,6 @@ void cell::set_value(unsigned long i)
template<> template<>
void cell::set_value(long long i) void cell::set_value(long long i)
{ {
d_->is_date_ = false;
d_->value_numeric_ = static_cast<long double>(i); d_->value_numeric_ = static_cast<long double>(i);
d_->type_ = type::numeric; d_->type_ = type::numeric;
} }
@ -502,7 +681,6 @@ void cell::set_value(long long i)
template<> template<>
void cell::set_value(unsigned long long i) void cell::set_value(unsigned long long i)
{ {
d_->is_date_ = false;
d_->value_numeric_ = static_cast<long double>(i); d_->value_numeric_ = static_cast<long double>(i);
d_->type_ = type::numeric; d_->type_ = type::numeric;
} }
@ -511,7 +689,6 @@ void cell::set_value(unsigned long long i)
template<> template<>
void cell::set_value(float f) void cell::set_value(float f)
{ {
d_->is_date_ = false;
d_->value_numeric_ = static_cast<long double>(f); d_->value_numeric_ = static_cast<long double>(f);
d_->type_ = type::numeric; d_->type_ = type::numeric;
} }
@ -519,7 +696,6 @@ void cell::set_value(float f)
template<> template<>
void cell::set_value(double d) void cell::set_value(double d)
{ {
d_->is_date_ = false;
d_->value_numeric_ = static_cast<long double>(d); d_->value_numeric_ = static_cast<long double>(d);
d_->type_ = type::numeric; d_->type_ = type::numeric;
} }
@ -527,7 +703,6 @@ void cell::set_value(double d)
template<> template<>
void cell::set_value(long double d) void cell::set_value(long double d)
{ {
d_->is_date_ = false;
d_->value_numeric_ = static_cast<long double>(d); d_->value_numeric_ = static_cast<long double>(d);
d_->type_ = type::numeric; d_->type_ = type::numeric;
} }
@ -550,44 +725,43 @@ void cell::set_value(cell c)
d_->type_ = c.d_->type_; d_->type_ = c.d_->type_;
d_->value_numeric_ = c.d_->value_numeric_; d_->value_numeric_ = c.d_->value_numeric_;
d_->value_string_ = c.d_->value_string_; d_->value_string_ = c.d_->value_string_;
d_->is_date_ = c.d_->is_date_;
d_->hyperlink_ = c.d_->hyperlink_; d_->hyperlink_ = c.d_->hyperlink_;
d_->has_hyperlink_ = c.d_->has_hyperlink_; d_->has_hyperlink_ = c.d_->has_hyperlink_;
d_->formula_ = c.d_->formula_; d_->formula_ = c.d_->formula_;
set_style(c.get_style()); d_->style_id_ = c.d_->style_id_;
set_comment(c.get_comment()); set_comment(c.get_comment());
} }
template<> template<>
void cell::set_value(date d) void cell::set_value(date d)
{ {
auto base_date = get_parent().get_parent().get_properties().excel_base_date; d_->type_ = type::numeric;
d_->set_date(d.to_number(base_date), xlnt::number_format::format::date_yyyymmdd2); d_->value_numeric_ = d.to_number(get_base_date());
set_number_format(number_format(number_format::format::date_yyyymmdd2));
} }
template<> template<>
void cell::set_value(datetime d) void cell::set_value(datetime d)
{ {
auto base_date = get_parent().get_parent().get_properties().excel_base_date; d_->type_ = type::numeric;
d_->set_date(d.to_number(base_date), xlnt::number_format::format::date_datetime); d_->value_numeric_ = d.to_number(get_base_date());
set_number_format(number_format(number_format::format::date_datetime));
} }
template<> template<>
void cell::set_value(time t) void cell::set_value(time t)
{ {
d_->set_date(t.to_number(), xlnt::number_format::format::date_time6); d_->type_ = type::numeric;
d_->value_numeric_ = t.to_number();
set_number_format(number_format(number_format::format::date_time6));
} }
template<> template<>
void cell::set_value(timedelta t) void cell::set_value(timedelta t)
{ {
d_->set_date(t.to_number(), xlnt::number_format::format::date_timedelta); d_->type_ = type::numeric;
d_->is_date_ = false; // a timedelta isn't actually a date, still uses mostly the same code d_->value_numeric_ = t.to_number();
} set_number_format(number_format(number_format::format::date_timedelta));
bool cell::has_style() const
{
return d_->style_ != nullptr;
} }
row_t cell::get_row() const row_t cell::get_row() const
@ -612,9 +786,9 @@ bool cell::is_merged() const
bool cell::is_date() const bool cell::is_date() const
{ {
if(get_data_type() == type::numeric && has_style()) if(get_data_type() == type::numeric)
{ {
auto number_format = get_style().get_number_format().get_format_code_string(); auto number_format = get_number_format().get_format_string();
if(number_format != "General") if(number_format != "General")
{ {
@ -648,21 +822,6 @@ bool cell::operator==(const cell &comparand) const
return d_ == comparand.d_; return d_ == comparand.d_;
} }
style &cell::get_style()
{
return d_->get_style(true);
}
const style &cell::get_style() const
{
return d_->get_style();
}
void cell::set_style(const xlnt::style &s)
{
get_style() = s;
}
cell &cell::operator=(const cell &rhs) cell &cell::operator=(const cell &rhs)
{ {
*d_ = *rhs.d_; *d_ = *rhs.d_;
@ -874,54 +1033,44 @@ std::size_t cell::get_xf_index() const
return d_->xf_index_; return d_->xf_index_;
} }
std::string cell::get_number_format() const number_format &cell::get_number_format() const
{ {
return get_style().get_number_format().get_format_code_string(); return get_parent().get_parent().get_number_format(d_->style_id_);
} }
std::string cell::get_number_format() const const font &cell::get_font() const
{ {
return get_style().get_number_format().get_format_code_string(); return get_parent().get_parent().get_font(d_->style_id_);
}
font &cell::get_font()
{
return get_style().get_font();
}
fill &cell::get_fill()
{
return get_style().get_fill();
} }
const fill &cell::get_fill() const const fill &cell::get_fill() const
{ {
return get_style().get_fill(); return get_parent().get_parent().get_fill(d_->style_id_);
} }
border &cell::get_border() const border &cell::get_border() const
{ {
return get_style().get_border(); return get_parent().get_parent().get_border(d_->style_id_);
} }
alignment &cell::get_alignment() const alignment &cell::get_alignment() const
{ {
return get_style().get_alignment(); return get_parent().get_parent().get_alignment(d_->style_id_);
} }
protection &cell::get_protection() const protection &cell::get_protection() const
{ {
return get_style().get_protection(); return get_parent().get_parent().get_protection(d_->style_id_);
} }
bool cell::pivot_button() bool cell::pivot_button() const
{ {
return get_style().pivot_button(); return get_parent().get_parent().get_pivot_button(d_->style_id_);
} }
bool cell::quote_prefix() bool cell::quote_prefix() const
{ {
return get_style().quote_prefix(); return get_parent().get_parent().get_quote_prefix(d_->style_id_);
} }
void cell::clear_value() void cell::clear_value()
@ -1021,25 +1170,24 @@ time cell::get_value() const
template<> template<>
datetime cell::get_value() const datetime cell::get_value() const
{ {
return datetime::from_number(d_->value_numeric_, xlnt::calendar::windows_1900); return datetime::from_number(d_->value_numeric_, get_base_date());
} }
template<> template<>
date cell::get_value() const date cell::get_value() const
{ {
return date::from_number(static_cast<int>(d_->value_numeric_), xlnt::calendar::windows_1900); return date::from_number(static_cast<int>(d_->value_numeric_), get_base_date());
} }
template<> template<>
timedelta cell::get_value() const timedelta cell::get_value() const
{ {
return timedelta(0, 0); return timedelta::from_number(d_->value_numeric_);
//return timedelta::from_number(d_->value_numeric_);
} }
void cell::set_number_format(const std::string &format_string, int index) void cell::set_number_format(const number_format &number_format_)
{ {
get_style().get_number_format().set_format_code_string(format_string, index); d_->style_id_ = get_parent().get_parent().set_number_format(number_format_, d_->style_id_);
} }
template<> template<>
@ -1055,23 +1203,18 @@ bool cell::has_value() const
std::string cell::to_string() const std::string cell::to_string() const
{ {
std::string number_format = "General"; auto nf = get_number_format();
if(has_style())
{
number_format = get_style().get_number_format().get_format_code_string();
}
switch(get_data_type()) switch(get_data_type())
{ {
case cell::type::null: case cell::type::null:
return ""; return "";
case cell::type::numeric: case cell::type::numeric:
return format_number(get_value<long double>(), number_format); return format_number(get_value<long double>(), nf.get_format_string(), get_base_date());
case cell::type::string: case cell::type::string:
case cell::type::formula: case cell::type::formula:
case cell::type::error: case cell::type::error:
return format_text(get_value<std::string>(), number_format); return format_text(get_value<std::string>(), nf.get_format_string());
case cell::type::boolean: case cell::type::boolean:
return get_value<long double>() == 0 ? "FALSE" : "TRUE"; return get_value<long double>() == 0 ? "FALSE" : "TRUE";
default: default:
@ -1079,4 +1222,14 @@ std::string cell::to_string() const
} }
} }
std::size_t cell::get_style_id() const
{
return d_->style_id_;
}
calendar cell::get_base_date() const
{
return get_parent().get_parent().get_properties().excel_base_date;
}
} // namespace xlnt } // namespace xlnt

View File

@ -187,4 +187,9 @@ double timedelta::to_number() const
return days + hours / 24.0; return days + hours / 24.0;
} }
timedelta timedelta::from_number(long double number)
{
return timedelta(static_cast<long long int>(number), 0);
}
} // namespace xlnt } // namespace xlnt

View File

@ -6,30 +6,6 @@
namespace xlnt { namespace xlnt {
namespace detail { namespace detail {
cell::type type_;
worksheet_impl *parent_;
column_t column_;
row_t row_;
std::string value_string_;
long double value_numeric_;
std::string formula_;
bool has_hyperlink_;
relationship hyperlink_;
bool is_merged_;
bool is_date_;
std::size_t xf_index_;
std::unique_ptr<style> style_;
std::unique_ptr<comment_impl> comment_;
cell_impl::cell_impl() : cell_impl(1, 1) cell_impl::cell_impl() : cell_impl(1, 1)
{ {
} }
@ -46,9 +22,8 @@ cell_impl::cell_impl(worksheet_impl *parent, column_t column, row_t row)
value_numeric_(0), value_numeric_(0),
has_hyperlink_(false), has_hyperlink_(false),
is_merged_(false), is_merged_(false),
is_date_(false),
xf_index_(0), xf_index_(0),
style_(nullptr), style_id_(1),
comment_(nullptr) comment_(nullptr)
{ {
} }
@ -68,14 +43,9 @@ cell_impl &cell_impl::operator=(const cell_impl &rhs)
column_ = rhs.column_; column_ = rhs.column_;
row_ = rhs.row_; row_ = rhs.row_;
is_merged_ = rhs.is_merged_; is_merged_ = rhs.is_merged_;
is_date_ = rhs.is_date_;
has_hyperlink_ = rhs.has_hyperlink_; has_hyperlink_ = rhs.has_hyperlink_;
type_ = rhs.type_; type_ = rhs.type_;
style_id_ = rhs.style_id_;
if(rhs.style_ != nullptr)
{
style_.reset(new style(*rhs.style_));
}
if(rhs.comment_ != nullptr) if(rhs.comment_ != nullptr)
{ {

View File

@ -8,6 +8,7 @@
#include <xlnt/common/datetime.hpp> #include <xlnt/common/datetime.hpp>
#include <xlnt/common/types.hpp> #include <xlnt/common/types.hpp>
#include <xlnt/common/relationship.hpp> #include <xlnt/common/relationship.hpp>
#include <xlnt/styles/number_format.hpp>
#include "comment_impl.hpp" #include "comment_impl.hpp"
@ -123,37 +124,13 @@ struct cell_impl
cell_impl(const cell_impl &rhs); cell_impl(const cell_impl &rhs);
cell_impl &operator=(const cell_impl &rhs); cell_impl &operator=(const cell_impl &rhs);
style &get_style(bool create_if_null) cell self()
{ {
if(style_ == nullptr && create_if_null) return xlnt::cell(this);
{
style_.reset(new style());
}
return *style_;
}
const style &get_style() const
{
if(style_ == nullptr)
{
throw std::runtime_error("call has_style to check if const cell has a style before accessing it");
}
return *style_;
}
void set_date(long double number, xlnt::number_format::format format_code)
{
is_date_ = true;
get_style(true).get_number_format().set_format_code(format_code);
value_numeric_ = number;
type_ = cell::type::numeric;
} }
void set_string(const std::string &s, bool guess_types) void set_string(const std::string &s, bool guess_types)
{ {
is_date_ = false;
value_string_ = check_string(s); value_string_ = check_string(s);
type_ = cell::type::string; type_ = cell::type::string;
@ -175,7 +152,7 @@ struct cell_impl
{ {
value_numeric_ = percentage.second; value_numeric_ = percentage.second;
type_ = cell::type::numeric; type_ = cell::type::numeric;
get_style(true).get_number_format().set_format_code(xlnt::number_format::format::percentage); self().set_number_format(xlnt::number_format(xlnt::number_format::format::percentage));
} }
else else
{ {
@ -183,7 +160,9 @@ struct cell_impl
if (time.first) if (time.first)
{ {
set_date(time.second.to_number(), xlnt::number_format::format::date_time6); type_ = cell::type::numeric;
self().set_number_format(xlnt::number_format(number_format::format::date_time6));
value_numeric_ = time.second.to_number();
} }
else else
{ {
@ -215,11 +194,10 @@ struct cell_impl
relationship hyperlink_; relationship hyperlink_;
bool is_merged_; bool is_merged_;
bool is_date_;
std::size_t xf_index_; std::size_t xf_index_;
std::size_t style_id_;
std::unique_ptr<style> style_;
std::unique_ptr<comment_impl> comment_; std::unique_ptr<comment_impl> comment_;
}; };

View File

@ -17,7 +17,22 @@ struct workbook_impl
drawings_(other.drawings_), drawings_(other.drawings_),
properties_(other.properties_), properties_(other.properties_),
guess_types_(other.guess_types_), guess_types_(other.guess_types_),
data_only_(other.data_only_) data_only_(other.data_only_),
next_style_id_(other.next_style_id_),
alignments_(other.alignments_),
borders_(other.borders_),
fills_(other.fills_),
fonts_(other.fonts_),
number_formats_(other.number_formats_),
protections_(other.protections_),
style_alignment_(other.style_alignment_),
style_border_(other.style_border_),
style_fill_(other.style_fill_),
style_font_(other.style_font_),
style_number_format_(other.style_number_format_),
style_protection_(other.style_protection_),
style_pivot_button_(other.style_pivot_button_),
style_quote_prefix_(other.style_quote_prefix_)
{ {
} }
@ -33,6 +48,21 @@ struct workbook_impl
properties_ = other.properties_; properties_ = other.properties_;
guess_types_ = other.guess_types_; guess_types_ = other.guess_types_;
data_only_ = other.data_only_; data_only_ = other.data_only_;
next_style_id_ = other.next_style_id_;
alignments_ = other.alignments_;
borders_ = other.borders_;
fills_ = other.fills_;
fonts_ = other.fonts_;
number_formats_ = other.number_formats_;
protections_ = other.protections_;
style_alignment_ = other.style_alignment_;
style_border_ = other.style_border_;
style_fill_ = other.style_fill_;
style_font_ = other.style_font_;
style_number_format_ = other.style_number_format_;
style_protection_ = other.style_protection_;
style_pivot_button_ = other.style_pivot_button_;
style_quote_prefix_ = other.style_quote_prefix_;
return *this; return *this;
} }
@ -44,6 +74,22 @@ struct workbook_impl
document_properties properties_; document_properties properties_;
bool guess_types_; bool guess_types_;
bool data_only_; bool data_only_;
std::size_t next_style_id_;
std::unordered_map<std::size_t, alignment> alignments_;
std::unordered_map<std::size_t, border> borders_;
std::unordered_map<std::size_t, fill> fills_;
std::unordered_map<std::size_t, font> fonts_;
std::unordered_map<std::size_t, number_format> number_formats_;
std::unordered_map<std::size_t, protection> protections_;
std::unordered_map<std::size_t, std::size_t> style_alignment_;
std::unordered_map<std::size_t, std::size_t> style_border_;
std::unordered_map<std::size_t, std::size_t> style_fill_;
std::unordered_map<std::size_t, std::size_t> style_font_;
std::unordered_map<std::size_t, std::size_t> style_number_format_;
std::unordered_map<std::size_t, std::size_t> style_protection_;
std::unordered_map<std::size_t, bool> style_pivot_button_;
std::unordered_map<std::size_t, bool> style_quote_prefix_;
}; };
} // namespace detail } // namespace detail

View File

@ -124,6 +124,20 @@ const std::unordered_map<std::string, int> &number_format::reversed_builtin_form
return formats; return formats;
} }
number_format::number_format() : number_format(format::general)
{
}
number_format::number_format(format code) : format_code_(code), format_index_(0)
{
set_format_code(code);
}
number_format::number_format(const std::string &format_string) : number_format(format::general)
{
set_format_string(format_string);
}
number_format::format number_format::lookup_format(int code) number_format::format number_format::lookup_format(int code)
{ {
if(builtin_formats().find(code) == builtin_formats().end()) if(builtin_formats().find(code) == builtin_formats().end())
@ -142,14 +156,58 @@ number_format::format number_format::lookup_format(int code)
return match->first; return match->first;
} }
std::string number_format::get_format_code_string() const std::string number_format::get_format_string() const
{ {
if(builtin_formats().find(format_index_) == builtin_formats().end()) return format_string_;
{
return custom_format_code_;
} }
return builtin_formats().at(format_index_); number_format::format number_format::get_format_code() const
{
return format_code_;
}
std::size_t number_format::hash() const
{
std::hash<std::string> hasher;
return hasher(format_string_);
}
void number_format::set_format_string(const std::string &format_string)
{
format_string_ = format_string;
format_index_ = -1;
format_code_ = format::unknown;
const auto &reversed = reversed_builtin_formats();
if(reversed.find(format_string) != reversed.end())
{
format_index_ = reversed.at(format_string);
for(const auto &pair : format_strings())
{
if(pair.second == format_string)
{
format_code_ = pair.first;
break;
}
}
}
}
void number_format::set_format_code(xlnt::number_format::format format_code)
{
format_code_ = format_code;
format_string_ = format_strings().at(format_code);
try
{
format_index_ = reversed_builtin_formats().at(format_string_);
}
catch(std::out_of_range)
{
format_index_ = -1;
}
} }
} // namespace xlnt } // namespace xlnt

View File

@ -12,6 +12,7 @@
#include <xlnt/workbook/workbook.hpp> #include <xlnt/workbook/workbook.hpp>
#include <xlnt/worksheet/range_reference.hpp> #include <xlnt/worksheet/range_reference.hpp>
#include <xlnt/worksheet/worksheet.hpp> #include <xlnt/worksheet/worksheet.hpp>
#include <xlnt/styles/number_format.hpp>
namespace { namespace {
@ -164,20 +165,16 @@ void read_worksheet_common(xlnt::worksheet ws, const pugi::xml_node &root_node,
if(match != custom_number_formats.end()) if(match != custom_number_formats.end())
{ {
ws.get_cell(address).get_style().get_number_format().set_format_code_string(match->second, number_format_id); xlnt::number_format nf(match->second);
auto cell = ws.get_cell(address);
cell.set_number_format(nf);
} }
} }
else else
{ {
ws.get_cell(address).get_style().get_number_format().set_format_code(format); xlnt::number_format nf(format);
} auto cell = ws.get_cell(address);
cell.set_number_format(nf);
//TODO: this is bad
if(ws.get_cell(address).get_style().get_number_format().get_format_code_string().find_first_of("mdyhs") != std::string::npos)
{
auto base_date = ws.get_parent().get_properties().excel_base_date;
auto converted = xlnt::datetime::from_number(std::stold(value_string), base_date);
ws.get_cell(address).set_value(converted.to_number(xlnt::calendar::windows_1900));
} }
} }
} }

View File

@ -1,69 +1,92 @@
#include <xlnt/cell/cell.hpp>
#include <xlnt/styles/style.hpp> #include <xlnt/styles/style.hpp>
#include "font.hpp"
#include "number_format.hpp"
#include "protection.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 { namespace xlnt {
style::style(const style &rhs) : number_format_(rhs.number_format_), protection_(rhs.protection_) style::style()
{ {
} }
void style::set_protection(xlnt::protection protection) style::style(const style &other)
{ {
protection_ = protection;
} }
void style::set_number_format(xlnt::number_format format) const cell style::get_parent() const
{ {
number_format_ = format; return cell(parent_);
} }
border &style::get_border() std::size_t style::hash() const
{ {
return border_; std::size_t seed = 100;
std::hash<std::string> string_hash;
auto font_ = get_font();
hash_combine(seed, string_hash(font_.name_));
hash_combine(seed, font_.size_);
hash_combine(seed, static_cast<std::size_t>(font_.underline_));
std::size_t bools = font_.bold_;
bools = bools << 1 & font_.italic_;
bools = bools << 1 & font_.strikethrough_;
bools = bools << 1 & font_.superscript_;
bools = bools << 1 & font_.subscript_;
hash_combine(seed, bools);
return seed;
} }
bool style::pivot_button() const number_format &style::get_number_format() const
{ {
return pivot_button_; return get_parent().get_number_format();
} }
bool style::quote_prefix() const border &style::get_border() const
{ {
return quote_prefix_; return get_parent().get_border();
} }
alignment &style::get_alignment() const alignment &style::get_alignment() const
{ {
return alignment_; return get_parent().get_alignment();
}
fill &style::get_fill()
{
return fill_;
} }
const fill &style::get_fill() const const fill &style::get_fill() const
{ {
return fill_; return get_parent().get_fill();
} }
font &style::get_font() const font &style::get_font() const
{ {
return font_; return get_parent().get_font();
} }
protection &style::get_protection() const protection &style::get_protection() const
{ {
return protection_; return get_parent().get_protection();
} }
void style::set_pivot_button(bool pivot) bool style::pivot_button() const
{ {
pivot_button_ = pivot; return get_parent().pivot_button();
} }
void style::set_quote_prefix(bool quote) bool style::quote_prefix() const
{ {
quote_prefix_ = quote; return get_parent().quote_prefix();
} }
} // namespace xlnt } // namespace xlnt

View File

@ -1,6 +1,12 @@
#include <sstream> #include <sstream>
#include <pugixml.hpp> #include <pugixml.hpp>
#include <xlnt/styles/alignment.hpp>
#include <xlnt/styles/borders.hpp>
#include <xlnt/styles/fill.hpp>
#include <xlnt/styles/font.hpp>
#include <xlnt/styles/number_format.hpp>
#include <xlnt/styles/protection.hpp>
#include <xlnt/writer/style_writer.hpp> #include <xlnt/writer/style_writer.hpp>
#include <xlnt/workbook/workbook.hpp> #include <xlnt/workbook/workbook.hpp>
#include <xlnt/worksheet/worksheet.hpp> #include <xlnt/worksheet/worksheet.hpp>
@ -14,46 +20,6 @@ style_writer::style_writer(xlnt::workbook &wb) : wb_(wb)
} }
std::unordered_map<std::size_t, std::string> style_writer::get_style_by_hash() const
{
std::unordered_map<std::size_t, std::string> styles;
for(auto ws : wb_)
{
for(auto row : ws.rows())
{
for(auto cell : row)
{
if(cell.has_style())
{
styles[1] = "style";
}
}
}
}
return styles;
}
std::vector<style> style_writer::get_styles() const
{
std::vector<style> styles;
for(auto ws : wb_)
{
for(auto row : ws.rows())
{
for(auto cell : row)
{
if(cell.has_style())
{
styles.push_back(cell.get_style());
}
}
}
}
return styles;
}
std::string style_writer::write_table() const std::string style_writer::write_table() const
{ {
pugi::xml_document doc; pugi::xml_document doc;
@ -63,36 +29,53 @@ std::string style_writer::write_table() const
style_sheet_node.append_attribute("mc:Ignorable").set_value("x14ac"); style_sheet_node.append_attribute("mc:Ignorable").set_value("x14ac");
style_sheet_node.append_attribute("xmlns:x14ac").set_value("http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"); style_sheet_node.append_attribute("xmlns:x14ac").set_value("http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac");
std::vector<style> custom_styles; auto num_fmts_node = style_sheet_node.append_child("numFmts");
for(auto style : get_styles()) auto &num_fmts = wb_.get_number_formats();
num_fmts_node.append_attribute("count").set_value(static_cast<int>(num_fmts.size()));
int custom_index = 164;
for(auto &num_fmt : num_fmts)
{ {
if((int)style.get_number_format().get_format_code() > 163) auto num_fmt_node = num_fmts_node.append_child("numFmt");
if(num_fmt.second.get_format_code() == number_format::format::unknown)
{ {
custom_styles.push_back(style); num_fmt_node.append_attribute("numFmtId").set_value(custom_index++);
} }
else
{
num_fmt_node.append_attribute("numFmtId").set_value(num_fmt.second.get_format_index());
} }
if(!custom_styles.empty()) num_fmt_node.append_attribute("formatCode").set_value("General");
{
} }
auto fonts_node = style_sheet_node.append_child("fonts"); auto fonts_node = style_sheet_node.append_child("fonts");
fonts_node.append_attribute("count").set_value(1); auto &fonts = wb_.get_fonts();
fonts_node.append_attribute("count").set_value(static_cast<int>(fonts.size()));
fonts_node.append_attribute("x14ac:knownFonts").set_value(1); fonts_node.append_attribute("x14ac:knownFonts").set_value(1);
for(auto &f : fonts)
{
auto font_node = fonts_node.append_child("font"); auto font_node = fonts_node.append_child("font");
auto size_node = font_node.append_child("sz"); auto size_node = font_node.append_child("sz");
size_node.append_attribute("val").set_value(11); size_node.append_attribute("val").set_value(f.second.get_size());
auto color_node = font_node.append_child("color"); auto color_node = font_node.append_child("color");
color_node.append_attribute("theme").set_value(1); color_node.append_attribute("theme").set_value(1);
auto name_node = font_node.append_child("name"); auto name_node = font_node.append_child("name");
name_node.append_attribute("val").set_value("Calibri"); name_node.append_attribute("val").set_value(f.second.get_name().c_str());
auto family_node = font_node.append_child("family"); auto family_node = font_node.append_child("family");
family_node.append_attribute("val").set_value(2); family_node.append_attribute("val").set_value(2);
auto scheme_node = font_node.append_child("scheme"); auto scheme_node = font_node.append_child("scheme");
scheme_node.append_attribute("val").set_value("minor"); scheme_node.append_attribute("val").set_value("minor");
if(f.second.is_bold())
{
auto bold_node = font_node.append_child("b");
bold_node.append_attribute("val").set_value(1);
}
}
auto fills_node = style_sheet_node.append_child("fills"); auto fills_node = style_sheet_node.append_child("fills");
fills_node.append_attribute("count").set_value(2); fills_node.append_attribute("count").set_value(2);
fills_node.append_child("fill").append_child("patternFill").append_attribute("patternType").set_value("none"); fills_node.append_child("fill").append_child("patternFill").append_attribute("patternType").set_value("none");

View File

@ -13,6 +13,12 @@
#include <xlnt/common/zip_file.hpp> #include <xlnt/common/zip_file.hpp>
#include <xlnt/drawing/drawing.hpp> #include <xlnt/drawing/drawing.hpp>
#include <xlnt/reader/reader.hpp> #include <xlnt/reader/reader.hpp>
#include <xlnt/styles/alignment.hpp>
#include <xlnt/styles/borders.hpp>
#include <xlnt/styles/fill.hpp>
#include <xlnt/styles/font.hpp>
#include <xlnt/styles/number_format.hpp>
#include <xlnt/styles/protection.hpp>
#include <xlnt/workbook/document_properties.hpp> #include <xlnt/workbook/document_properties.hpp>
#include <xlnt/workbook/named_range.hpp> #include <xlnt/workbook/named_range.hpp>
#include <xlnt/workbook/workbook.hpp> #include <xlnt/workbook/workbook.hpp>
@ -56,9 +62,8 @@ static std::string create_temporary_filename()
namespace xlnt { namespace xlnt {
namespace detail { namespace detail {
workbook_impl::workbook_impl() : active_sheet_index_(0), guess_types_(false), data_only_(false) workbook_impl::workbook_impl() : active_sheet_index_(0), guess_types_(false), data_only_(false), next_style_id_(0)
{ {
} }
} // namespace detail } // namespace detail
@ -69,6 +74,14 @@ workbook::workbook() : d_(new detail::workbook_impl())
create_relationship("rId2", "sharedStrings.xml", relationship::type::shared_strings); create_relationship("rId2", "sharedStrings.xml", relationship::type::shared_strings);
create_relationship("rId3", "styles.xml", relationship::type::styles); create_relationship("rId3", "styles.xml", relationship::type::styles);
create_relationship("rId4", "theme/theme1.xml", relationship::type::theme); create_relationship("rId4", "theme/theme1.xml", relationship::type::theme);
set_alignment(alignment(), 1);
set_border(border(), 1);
set_fill(fill(), 1);
set_font(font(), 1);
set_number_format(number_format(), 1);
set_protection(protection(), 1);
d_->style_pivot_button_[1] = false;
d_->style_quote_prefix_[1] = false;
} }
workbook::iterator::iterator(workbook &wb, std::size_t index) : wb_(wb), index_(index) workbook::iterator::iterator(workbook &wb, std::size_t index) : wb_(wb), index_(index)
@ -717,4 +730,182 @@ void workbook::set_data_only(bool data_only)
return named_ranges; return named_ranges;
} }
std::size_t workbook::add_style(xlnt::style style_)
{
return 1;
} }
const number_format &workbook::get_number_format(std::size_t style_id) const
{
return d_->number_formats_[d_->style_number_format_[style_id]];
}
const font &workbook::get_font(std::size_t style_id) const
{
return d_->fonts_[d_->style_font_[style_id]];
}
std::size_t workbook::set_font(const font &font_, std::size_t style_id)
{
auto hash = font_.hash();
if(d_->number_formats_.find(hash) == d_->number_formats_.end())
{
d_->fonts_[hash] = font_;
}
d_->style_font_[d_->next_style_id_] = hash;
d_->style_alignment_[d_->next_style_id_] = d_->style_alignment_[style_id];
d_->style_border_[d_->next_style_id_] = d_->style_border_[style_id];
d_->style_fill_[d_->next_style_id_] = d_->style_fill_[style_id];
d_->style_number_format_[d_->next_style_id_] = d_->style_number_format_[style_id];
d_->style_protection_[d_->next_style_id_] = d_->style_protection_[style_id];
d_->style_pivot_button_[d_->next_style_id_] = d_->style_pivot_button_[style_id];
d_->style_quote_prefix_[d_->next_style_id_] = d_->style_quote_prefix_[style_id];
return d_->next_style_id_++;
}
const fill &workbook::get_fill(std::size_t style_id) const
{
return d_->fills_[d_->style_fill_[style_id]];
}
std::size_t workbook::set_fill(const fill &fill_, std::size_t style_id)
{
auto hash = fill_.hash();
if(d_->fills_.find(hash) == d_->fills_.end())
{
d_->fills_[hash] = fill_;
}
d_->style_fill_[d_->next_style_id_] = hash;
d_->style_alignment_[d_->next_style_id_] = d_->style_alignment_[style_id];
d_->style_border_[d_->next_style_id_] = d_->style_border_[style_id];
d_->style_font_[d_->next_style_id_] = d_->style_font_[style_id];
d_->style_number_format_[d_->next_style_id_] = d_->style_number_format_[style_id];
d_->style_protection_[d_->next_style_id_] = d_->style_protection_[style_id];
d_->style_pivot_button_[d_->next_style_id_] = d_->style_pivot_button_[style_id];
d_->style_quote_prefix_[d_->next_style_id_] = d_->style_quote_prefix_[style_id];
return d_->next_style_id_++;
}
const border &workbook::get_border(std::size_t style_id) const
{
return d_->borders_[d_->style_border_[style_id]];
}
std::size_t workbook::set_border(const border &border_, std::size_t style_id)
{
auto hash = border_.hash();
if(d_->borders_.find(hash) == d_->borders_.end())
{
d_->borders_[hash] = border_;
}
d_->style_border_[d_->next_style_id_] = hash;
d_->style_alignment_[d_->next_style_id_] = d_->style_alignment_[style_id];
d_->style_font_[d_->next_style_id_] = d_->style_font_[style_id];
d_->style_fill_[d_->next_style_id_] = d_->style_fill_[style_id];
d_->style_number_format_[d_->next_style_id_] = d_->style_number_format_[style_id];
d_->style_protection_[d_->next_style_id_] = d_->style_protection_[style_id];
d_->style_pivot_button_[d_->next_style_id_] = d_->style_pivot_button_[style_id];
d_->style_quote_prefix_[d_->next_style_id_] = d_->style_quote_prefix_[style_id];
return d_->next_style_id_++;
}
const alignment &workbook::get_alignment(std::size_t style_id) const
{
return d_->alignments_[d_->style_alignment_[style_id]];
}
std::size_t workbook::set_alignment(const alignment &alignment_, std::size_t style_id)
{
auto hash = alignment_.hash();
if(d_->alignments_.find(hash) == d_->alignments_.end())
{
d_->alignments_[hash] = alignment_;
}
d_->style_alignment_[d_->next_style_id_] = hash;
d_->style_border_[d_->next_style_id_] = d_->style_border_[style_id];
d_->style_font_[d_->next_style_id_] = d_->style_font_[style_id];
d_->style_fill_[d_->next_style_id_] = d_->style_fill_[style_id];
d_->style_number_format_[d_->next_style_id_] = d_->style_number_format_[style_id];
d_->style_protection_[d_->next_style_id_] = d_->style_protection_[style_id];
d_->style_pivot_button_[d_->next_style_id_] = d_->style_pivot_button_[style_id];
d_->style_quote_prefix_[d_->next_style_id_] = d_->style_quote_prefix_[style_id];
return d_->next_style_id_++;
}
const protection &workbook::get_protection(std::size_t style_id) const
{
return d_->protections_[d_->style_protection_[style_id]];
}
std::size_t workbook::set_protection(const protection &protection_, std::size_t style_id)
{
auto hash = protection_.hash();
if(d_->protections_.find(hash) == d_->protections_.end())
{
d_->protections_[hash] = protection_;
}
d_->style_protection_[d_->next_style_id_] = hash;
d_->style_alignment_[d_->next_style_id_] = d_->style_alignment_[style_id];
d_->style_border_[d_->next_style_id_] = d_->style_border_[style_id];
d_->style_font_[d_->next_style_id_] = d_->style_font_[style_id];
d_->style_fill_[d_->next_style_id_] = d_->style_fill_[style_id];
d_->style_number_format_[d_->next_style_id_] = d_->style_number_format_[style_id];
d_->style_pivot_button_[d_->next_style_id_] = d_->style_pivot_button_[style_id];
d_->style_quote_prefix_[d_->next_style_id_] = d_->style_quote_prefix_[style_id];
return d_->next_style_id_++;
}
bool workbook::get_pivot_button(std::size_t style_id) const
{
return d_->style_pivot_button_[style_id];
}
bool workbook::get_quote_prefix(std::size_t style_id) const
{
return d_->style_quote_prefix_[style_id];
}
std::size_t workbook::set_number_format(const xlnt::number_format &format, std::size_t style_id)
{
auto hash = format.hash();
if(d_->number_formats_.find(hash) == d_->number_formats_.end())
{
d_->number_formats_[hash] = format;
}
d_->style_number_format_[d_->next_style_id_] = hash;
d_->style_alignment_[d_->next_style_id_] = d_->style_alignment_[style_id];
d_->style_border_[d_->next_style_id_] = d_->style_border_[style_id];
d_->style_font_[d_->next_style_id_] = d_->style_font_[style_id];
d_->style_fill_[d_->next_style_id_] = d_->style_fill_[style_id];
d_->style_protection_[d_->next_style_id_] = d_->style_protection_[style_id];
d_->style_pivot_button_[d_->next_style_id_] = d_->style_pivot_button_[style_id];
d_->style_quote_prefix_[d_->next_style_id_] = d_->style_quote_prefix_[style_id];
return d_->next_style_id_++;
}
} // namespace xlnt

View File

@ -7,6 +7,15 @@ xlnt::workbook load_workbook(const std::vector<std::uint8_t> &bytes)
{ {
xlnt::workbook wb; xlnt::workbook wb;
wb.load(bytes); wb.load(bytes);
return wb;
}
xlnt::workbook load_workbook(const std::string &filename)
{
xlnt::workbook wb;
wb.load(filename);
return wb; return wb;
} }

View File

@ -105,17 +105,6 @@ std::string write_worksheet(worksheet ws, const std::vector<std::string> &string
if(!style_id_by_hash.empty()) if(!style_id_by_hash.empty())
{ {
for(auto row : ws.rows())
{
for(auto cell : row)
{
if(cell.has_style())
{
styled_columns.push_back(cell_reference::column_index_from_string(cell.get_column()));
}
}
}
auto cols_node = root_node.append_child("cols"); auto cols_node = root_node.append_child("cols");
std::sort(styled_columns.begin(), styled_columns.end()); std::sort(styled_columns.begin(), styled_columns.end());
@ -268,10 +257,8 @@ std::string write_worksheet(worksheet ws, const std::vector<std::string> &string
} }
} }
if(cell.has_style()) auto style_id = cell.get_style_id();
{ cell_node.append_attribute("s").set_value((unsigned int)style_id);
cell_node.append_attribute("s").set_value(1);
}
} }
} }
} }

View File

@ -4,8 +4,21 @@
#include <iostream> #include <iostream>
#include <cxxtest/TestSuite.h> #include <cxxtest/TestSuite.h>
#include <xlnt/xlnt.hpp> #include <xlnt/cell/cell.hpp>
#include <xlnt/reader/reader.hpp> #include <xlnt/cell/cell_reference.hpp>
#include <xlnt/cell/comment.hpp>
#include <xlnt/common/datetime.hpp>
#include <xlnt/common/exceptions.hpp>
#include <xlnt/reader/workbook_reader.hpp>
#include <xlnt/styles/alignment.hpp>
#include <xlnt/styles/borders.hpp>
#include <xlnt/styles/font.hpp>
#include <xlnt/styles/fill.hpp>
#include <xlnt/styles/number_format.hpp>
#include <xlnt/styles/protection.hpp>
#include <xlnt/worksheet/range.hpp>
#include <xlnt/worksheet/worksheet.hpp>
#include <xlnt/workbook/workbook.hpp>
class test_cell : public CxxTest::TestSuite class test_cell : public CxxTest::TestSuite
{ {
@ -18,6 +31,23 @@ public:
wb_guess_types.set_guess_types(true); wb_guess_types.set_guess_types(true);
} }
void test_debug()
{
xlnt::workbook wb = xlnt::load_workbook("/Users/thomas/Development/xlnt/samples/sample1.xlsx");
for(auto ws : wb)
{
for(auto row : ws.rows())
{
for(auto cell : row)
{
std::cout << cell << ", ";
}
std::cout << std::endl;
}
}
}
void test_infer_numeric() void test_infer_numeric()
{ {
auto ws = wb_guess_types.create_sheet(); auto ws = wb_guess_types.create_sheet();
@ -171,7 +201,7 @@ public:
TS_ASSERT(cell.get_data_type() == xlnt::cell::type::numeric); TS_ASSERT(cell.get_data_type() == xlnt::cell::type::numeric);
TS_ASSERT(cell.get_value<long double>() == 40372.27616898148L); TS_ASSERT(cell.get_value<long double>() == 40372.27616898148L);
TS_ASSERT(cell.is_date()); TS_ASSERT(cell.is_date());
TS_ASSERT(cell.get_number_format() == "yyyy-mm-dd h:mm:ss"); TS_ASSERT(cell.get_number_format().get_format_string() == "yyyy-mm-dd h:mm:ss");
} }
void test_insert_date() void test_insert_date()
@ -183,7 +213,7 @@ public:
TS_ASSERT(cell.get_data_type() == xlnt::cell::type::numeric); TS_ASSERT(cell.get_data_type() == xlnt::cell::type::numeric);
TS_ASSERT(cell.get_value<long double>() == 40372.L); TS_ASSERT(cell.get_value<long double>() == 40372.L);
TS_ASSERT(cell.is_date()); TS_ASSERT(cell.is_date());
TS_ASSERT(cell.get_number_format() == "yyyy-mm-dd"); TS_ASSERT(cell.get_number_format().get_format_string() == "yyyy-mm-dd");
} }
void test_insert_time() void test_insert_time()
@ -195,7 +225,7 @@ public:
TS_ASSERT(cell.get_data_type() == xlnt::cell::type::numeric); TS_ASSERT(cell.get_data_type() == xlnt::cell::type::numeric);
TS_ASSERT(cell.get_value<long double>() == 0.04375L); TS_ASSERT(cell.get_value<long double>() == 0.04375L);
TS_ASSERT(cell.is_date()); TS_ASSERT(cell.is_date());
TS_ASSERT(cell.get_number_format() == "h:mm:ss"); TS_ASSERT(cell.get_number_format().get_format_string() == "h:mm:ss");
} }
void test_cell_formatted_as_date1() void test_cell_formatted_as_date1()
@ -279,7 +309,7 @@ public:
TS_ASSERT(cell.get_value<long double>() == 1.125); TS_ASSERT(cell.get_value<long double>() == 1.125);
TS_ASSERT(cell.get_data_type() == xlnt::cell::type::numeric); TS_ASSERT(cell.get_data_type() == xlnt::cell::type::numeric);
TS_ASSERT(!cell.is_date()); TS_ASSERT(!cell.is_date());
TS_ASSERT(cell.get_number_format() == "[hh]:mm:ss"); TS_ASSERT(cell.get_number_format().get_format_string() == "[hh]:mm:ss");
} }
void test_repr() void test_repr()
@ -406,8 +436,8 @@ public:
ws.get_parent().add_number_format("dd--hh--mm"); ws.get_parent().add_number_format("dd--hh--mm");
xlnt::cell cell(ws, "A1"); xlnt::cell cell(ws, "A1");
cell.set_number_format("dd--hh--mm"); cell.set_number_format(xlnt::number_format("dd--hh--mm"));
TS_ASSERT(cell.get_number_format() == "dd--hh--mm"); TS_ASSERT(cell.get_number_format().get_format_string() == "dd--hh--mm");
} }
void _test_alignment() void _test_alignment()
@ -439,7 +469,7 @@ public:
auto ws = wb.create_sheet(); auto ws = wb.create_sheet();
xlnt::cell cell(ws, "A1"); xlnt::cell cell(ws, "A1");
cell.get_style().set_pivot_button(true); cell.set_pivot_button(true);
TS_ASSERT(cell.pivot_button()); TS_ASSERT(cell.pivot_button());
} }
@ -448,7 +478,7 @@ public:
auto ws = wb.create_sheet(); auto ws = wb.create_sheet();
xlnt::cell cell(ws, "A1"); xlnt::cell cell(ws, "A1");
cell.get_style().set_quote_prefix(true); cell.set_quote_prefix(true);
TS_ASSERT(cell.quote_prefix()); TS_ASSERT(cell.quote_prefix());
} }
}; };

View File

@ -93,7 +93,7 @@ public:
{ {
auto wb = workbook_with_styles(); auto wb = workbook_with_styles();
auto ws = wb["Sheet1"]; auto ws = wb["Sheet1"];
auto code = ws.get_cell("A1").get_style().get_number_format().get_format_code(); auto code = ws.get_cell("A1").get_number_format().get_format_code();
auto expected = xlnt::number_format::format::general; auto expected = xlnt::number_format::format::general;
TS_ASSERT_EQUALS(code, expected); TS_ASSERT_EQUALS(code, expected);
} }
@ -102,7 +102,7 @@ public:
{ {
auto wb = workbook_with_styles(); auto wb = workbook_with_styles();
auto ws = wb["Sheet1"]; auto ws = wb["Sheet1"];
auto code = ws.get_cell("A2").get_style().get_number_format().get_format_code(); auto code = ws.get_cell("A2").get_number_format().get_format_code();
auto expected = xlnt::number_format::format::date_xlsx14; auto expected = xlnt::number_format::format::date_xlsx14;
TS_ASSERT_EQUALS(code, expected); TS_ASSERT_EQUALS(code, expected);
} }
@ -111,7 +111,7 @@ public:
{ {
auto wb = workbook_with_styles(); auto wb = workbook_with_styles();
auto ws = wb["Sheet1"]; auto ws = wb["Sheet1"];
auto code = ws.get_cell("A3").get_style().get_number_format().get_format_code(); auto code = ws.get_cell("A3").get_number_format().get_format_code();
auto expected = xlnt::number_format::format::number_00; auto expected = xlnt::number_format::format::number_00;
TS_ASSERT_EQUALS(code, expected); TS_ASSERT_EQUALS(code, expected);
} }
@ -120,7 +120,7 @@ public:
{ {
auto wb = workbook_with_styles(); auto wb = workbook_with_styles();
auto ws = wb["Sheet1"]; auto ws = wb["Sheet1"];
auto code = ws.get_cell("A4").get_style().get_number_format().get_format_code(); auto code = ws.get_cell("A4").get_number_format().get_format_code();
auto expected = xlnt::number_format::format::date_time3; auto expected = xlnt::number_format::format::date_time3;
TS_ASSERT_EQUALS(code, expected); TS_ASSERT_EQUALS(code, expected);
} }
@ -129,7 +129,7 @@ public:
{ {
auto wb = workbook_with_styles(); auto wb = workbook_with_styles();
auto ws = wb["Sheet1"]; auto ws = wb["Sheet1"];
auto code = ws.get_cell("A5").get_style().get_number_format().get_format_code(); auto code = ws.get_cell("A5").get_number_format().get_format_code();
auto expected = xlnt::number_format::format::percentage_00; auto expected = xlnt::number_format::format::percentage_00;
TS_ASSERT_EQUALS(code, expected); TS_ASSERT_EQUALS(code, expected);
} }
@ -162,14 +162,14 @@ public:
{ {
auto wb = date_std_1900(); auto wb = date_std_1900();
auto ws = wb["Sheet1"]; auto ws = wb["Sheet1"];
TS_ASSERT_EQUALS(ws.get_cell("A1").get_style().get_number_format().get_format_code(), xlnt::number_format::format::date_xlsx14); TS_ASSERT_EQUALS(ws.get_cell("A1").get_number_format().get_format_code(), xlnt::number_format::format::date_xlsx14);
} }
void test_read_date_style_mac() void test_read_date_style_mac()
{ {
auto wb = date_mac_1904(); auto wb = date_mac_1904();
auto ws = wb["Sheet1"]; auto ws = wb["Sheet1"];
TS_ASSERT_EQUALS(ws.get_cell("A1").get_style().get_number_format().get_format_code(), xlnt::number_format::format::date_xlsx14); TS_ASSERT_EQUALS(ws.get_cell("A1").get_number_format().get_format_code(), xlnt::number_format::format::date_xlsx14);
} }
void test_read_compare_mac_win_dates() void test_read_compare_mac_win_dates()

View File

@ -16,7 +16,7 @@ public:
xlnt::workbook wbk; xlnt::workbook wbk;
wbk.get_active_sheet().get_cell("A2").set_value("xlnt"); wbk.get_active_sheet().get_cell("A2").set_value("xlnt");
wbk.get_active_sheet().get_cell("B5").set_value(88); wbk.get_active_sheet().get_cell("B5").set_value(88);
wbk.get_active_sheet().get_cell("B5").get_style().set_number_format(xlnt::number_format(xlnt::number_format::format::percentage_00)); wbk.get_active_sheet().get_cell("B5").set_number_format(xlnt::number_format(xlnt::number_format::format::percentage_00));
wbk.save(temp_file.GetFilename()); wbk.save(temp_file.GetFilename());
if(PathHelper::FileExists(temp_file.GetFilename())) if(PathHelper::FileExists(temp_file.GetFilename()))
@ -97,17 +97,6 @@ public:
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_formula.xml", content)); TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_formula.xml", content));
} }
void test_write_style()
{
xlnt::workbook wb_guess_types;
wb_guess_types.set_guess_types(true);
auto ws = wb_guess_types.create_sheet();
ws.get_cell("F1").set_value("13%");
auto style_id_by_hash = xlnt::style_writer(wb_guess_types).get_style_by_hash();
auto content = xlnt::write_worksheet(ws, {}, style_id_by_hash);
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_style.xml", content));
}
void test_write_height() void test_write_height()
{ {
auto ws = wb_.create_sheet(); auto ws = wb_.create_sheet();