mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
lots of fixes
This commit is contained in:
parent
a87c144340
commit
a7bb9f0e77
|
@ -44,7 +44,16 @@ namespace detail {
|
|||
struct cell_impl;
|
||||
} // namespace detail
|
||||
|
||||
typedef std::string comment;
|
||||
class comment
|
||||
{
|
||||
public:
|
||||
comment(const std::string &type, const std::string &value) : type_(type), value_(value) {}
|
||||
std::string get_type() const { return type_; }
|
||||
std::string get_value() const { return value_; }
|
||||
private:
|
||||
std::string type_;
|
||||
std::string value_;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Describes cell associated properties.
|
||||
|
@ -116,7 +125,8 @@ public:
|
|||
//std::pair<int, int> get_anchor() const;
|
||||
|
||||
comment get_comment() const;
|
||||
void set_comment(comment comment);
|
||||
void set_comment(const comment &comment);
|
||||
void clear_comment();
|
||||
|
||||
std::string get_formula() const;
|
||||
void set_formula(const std::string &formula);
|
||||
|
@ -126,6 +136,10 @@ public:
|
|||
|
||||
void set_null();
|
||||
|
||||
cell offset(row_t row, column_t column);
|
||||
|
||||
worksheet get_parent();
|
||||
|
||||
cell &operator=(const cell &rhs);
|
||||
cell &operator=(bool value);
|
||||
cell &operator=(int value);
|
||||
|
|
|
@ -48,8 +48,77 @@ enum class target_mode
|
|||
class relationship
|
||||
{
|
||||
public:
|
||||
enum class type
|
||||
{
|
||||
invalid,
|
||||
hyperlink,
|
||||
drawing,
|
||||
worksheet,
|
||||
shared_strings,
|
||||
styles,
|
||||
theme,
|
||||
extended_properties,
|
||||
core_properties,
|
||||
office_document
|
||||
};
|
||||
|
||||
static type type_from_string(const std::string &type_string)
|
||||
{
|
||||
if(type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties")
|
||||
{
|
||||
return type::extended_properties;
|
||||
}
|
||||
else if(type_string == "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties")
|
||||
{
|
||||
return type::core_properties;
|
||||
}
|
||||
else if(type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument")
|
||||
{
|
||||
return type::office_document;
|
||||
}
|
||||
else if(type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet")
|
||||
{
|
||||
return type::worksheet;
|
||||
}
|
||||
else if(type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings")
|
||||
{
|
||||
return type::shared_strings;
|
||||
}
|
||||
else if(type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles")
|
||||
{
|
||||
return type::styles;
|
||||
}
|
||||
else if(type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme")
|
||||
{
|
||||
return type::theme;
|
||||
}
|
||||
else if(type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink")
|
||||
{
|
||||
return type::hyperlink;
|
||||
}
|
||||
|
||||
return type::invalid;
|
||||
}
|
||||
|
||||
static std::string type_to_string(type t)
|
||||
{
|
||||
switch(t)
|
||||
{
|
||||
case type::extended_properties: return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
|
||||
case type::core_properties: return "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
|
||||
case type::office_document: return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
|
||||
case type::worksheet: return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet";
|
||||
case type::shared_strings: return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
|
||||
case type::styles: return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
|
||||
case type::theme: return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
|
||||
case type::hyperlink: return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
|
||||
default: return "??";
|
||||
}
|
||||
}
|
||||
|
||||
relationship();
|
||||
relationship(const std::string &type, const std::string &r_id = "", const std::string &target_uri = "");
|
||||
relationship(const std::string &t, const std::string &r_id = "", const std::string &target_uri = "") : relationship(type_from_string(t), r_id, target_uri) {}
|
||||
relationship(type t, const std::string &r_id = "", const std::string &target_uri = "");
|
||||
|
||||
/// <summary>
|
||||
/// gets a string that identifies the relationship.
|
||||
|
@ -71,20 +140,10 @@ public:
|
|||
/// </summary>
|
||||
std::string get_target_uri() const { return target_uri_; }
|
||||
|
||||
type get_type() const { return type_; }
|
||||
std::string get_type_string() const { return type_to_string(type_); }
|
||||
|
||||
private:
|
||||
relationship(const std::string &id, const std::string &relationship_type_, const std::string &source_uri, target_mode target_mode, const std::string &target_uri);
|
||||
//relationship &operator=(const relationship &rhs) = delete;
|
||||
|
||||
enum class type
|
||||
{
|
||||
hyperlink,
|
||||
drawing,
|
||||
worksheet,
|
||||
sharedStrings,
|
||||
styles,
|
||||
theme
|
||||
};
|
||||
|
||||
type type_;
|
||||
std::string id_;
|
||||
std::string source_uri_;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
namespace xlnt {
|
||||
|
||||
class relationship;
|
||||
class workbook;
|
||||
class worksheet;
|
||||
class document_properties;
|
||||
|
@ -38,10 +39,9 @@ class zip_file;
|
|||
class reader
|
||||
{
|
||||
public:
|
||||
static std::unordered_map<std::string, std::pair<std::string, std::string>> read_relationships(const std::string &content);
|
||||
static std::vector<relationship> read_relationships(const std::string &content);
|
||||
static std::pair<std::unordered_map<std::string, std::string>, std::unordered_map<std::string, std::string>> read_content_types(const std::string &content);
|
||||
static std::string determine_document_type(const std::unordered_map<std::string, std::pair<std::string, std::string>> &root_relationships,
|
||||
const std::unordered_map<std::string, std::string> &override_types);
|
||||
static std::string determine_document_type(const std::unordered_map<std::string, std::string> &override_types);
|
||||
static worksheet read_worksheet(std::istream &handle, workbook &wb, const std::string &title, const std::vector<std::string> &string_table);
|
||||
static void read_worksheet(worksheet ws, const std::string &xml_string, const std::vector<std::string> &string_table, const std::vector<int> &number_format_ids);
|
||||
static std::vector<std::string> read_shared_string(const std::string &xml_string);
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "../common/relationship.hpp"
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
class drawing;
|
||||
|
@ -159,7 +161,7 @@ public:
|
|||
|
||||
std::vector<content_type> get_content_types() const;
|
||||
|
||||
void create_relationship(const std::string &id, const std::string &target, const std::string &type);
|
||||
void create_relationship(const std::string &id, const std::string &target, relationship::type type);
|
||||
relationship get_relationship(const std::string &id) const;
|
||||
std::vector<relationship> get_relationships() const;
|
||||
|
||||
|
|
|
@ -30,11 +30,13 @@
|
|||
#include <vector>
|
||||
|
||||
#include "../common/types.hpp"
|
||||
#include "../common/relationship.hpp"
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
class cell;
|
||||
class cell_reference;
|
||||
class comment;
|
||||
class range;
|
||||
class range_reference;
|
||||
class relationship;
|
||||
|
@ -203,7 +205,7 @@ public:
|
|||
range_reference calculate_dimension() const;
|
||||
|
||||
// relationships
|
||||
relationship create_relationship(const std::string &relationship_type, const std::string &target_uri);
|
||||
relationship create_relationship(relationship::type type, const std::string &target_uri);
|
||||
std::vector<relationship> get_relationships();
|
||||
|
||||
// charts
|
||||
|
@ -245,6 +247,11 @@ public:
|
|||
void unset_auto_filter();
|
||||
bool has_auto_filter() const;
|
||||
|
||||
// comments
|
||||
void add_comment(const comment &c);
|
||||
void remove_comment(const comment &c);
|
||||
std::size_t get_comment_count() const;
|
||||
|
||||
void reserve(std::size_t n);
|
||||
|
||||
private:
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
// @author: see AUTHORS file
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
const std::string xlnt_version = "0.1.0";
|
||||
|
||||
const std::string author = "Thomas Fussell";
|
||||
|
|
|
@ -560,7 +560,7 @@ void cell::set_hyperlink(const std::string &hyperlink)
|
|||
}
|
||||
|
||||
d_->has_hyperlink_ = true;
|
||||
d_->hyperlink_ = worksheet(d_->parent_).create_relationship("hyperlink", hyperlink);
|
||||
d_->hyperlink_ = worksheet(d_->parent_).create_relationship(relationship::type::hyperlink, hyperlink);
|
||||
|
||||
if(d_->type_ == type::null)
|
||||
{
|
||||
|
@ -584,6 +584,26 @@ void cell::set_formula(const std::string &formula)
|
|||
d_->string_value = formula;
|
||||
}
|
||||
|
||||
void cell::set_comment(const xlnt::comment &comment)
|
||||
{
|
||||
if(d_->comment_.get_value() == "")
|
||||
{
|
||||
get_parent().add_comment(comment);
|
||||
}
|
||||
|
||||
d_->comment_ = comment;
|
||||
}
|
||||
|
||||
void cell::clear_comment()
|
||||
{
|
||||
if(d_->comment_.get_value() != "")
|
||||
{
|
||||
get_parent().remove_comment(d_->comment_);
|
||||
}
|
||||
|
||||
d_->comment_ = comment("", "");
|
||||
}
|
||||
|
||||
void cell::set_error(const std::string &error)
|
||||
{
|
||||
if(error.length() == 0 || error[0] != '#')
|
||||
|
@ -595,4 +615,19 @@ void cell::set_error(const std::string &error)
|
|||
d_->string_value = error;
|
||||
}
|
||||
|
||||
cell cell::offset(column_t column, row_t row)
|
||||
{
|
||||
return get_parent().get_cell(cell_reference(d_->column + column, d_->row + row));
|
||||
}
|
||||
|
||||
worksheet cell::get_parent()
|
||||
{
|
||||
return worksheet(d_->parent_);
|
||||
}
|
||||
|
||||
comment cell::get_comment() const
|
||||
{
|
||||
return d_->comment_;
|
||||
}
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -4,15 +4,15 @@
|
|||
namespace xlnt {
|
||||
namespace detail {
|
||||
|
||||
cell_impl::cell_impl() : parent_(nullptr), type_(cell::type::null), column(0), row(0), style_(nullptr), merged(false), has_hyperlink_(false)
|
||||
cell_impl::cell_impl() : parent_(nullptr), type_(cell::type::null), column(0), row(0), style_(nullptr), merged(false), has_hyperlink_(false), comment_("", "")
|
||||
{
|
||||
}
|
||||
|
||||
cell_impl::cell_impl(worksheet_impl *parent, int column_index, int row_index) : parent_(parent), type_(cell::type::null), column(column_index), row(row_index), style_(nullptr), merged(false), has_hyperlink_(false)
|
||||
cell_impl::cell_impl(worksheet_impl *parent, int column_index, int row_index) : parent_(parent), type_(cell::type::null), column(column_index), row(row_index), style_(nullptr), merged(false), has_hyperlink_(false), comment_("", "")
|
||||
{
|
||||
}
|
||||
|
||||
cell_impl::cell_impl(const cell_impl &rhs)
|
||||
cell_impl::cell_impl(const cell_impl &rhs) : comment_("", "")
|
||||
{
|
||||
*this = rhs;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ struct cell_impl
|
|||
bool merged;
|
||||
bool is_date_;
|
||||
bool has_hyperlink_;
|
||||
comment comment_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
|
|
@ -60,6 +60,7 @@ struct worksheet_impl
|
|||
margins page_margins_;
|
||||
std::vector<range_reference> merged_cells_;
|
||||
std::unordered_map<std::string, range_reference> named_ranges_;
|
||||
std::vector<comment> comments_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "workbook/workbook.hpp"
|
||||
#include "worksheet/worksheet.hpp"
|
||||
#include "workbook/document_properties.hpp"
|
||||
#include "common/relationship.hpp"
|
||||
#include "common/zip_file.hpp"
|
||||
|
||||
namespace xlnt {
|
||||
|
@ -85,21 +86,21 @@ std::string reader::read_dimension(const std::string &xml_string)
|
|||
return dimension;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::pair<std::string, std::string>> reader::read_relationships(const std::string &content)
|
||||
std::vector<relationship> reader::read_relationships(const std::string &content)
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
doc.load(content.c_str());
|
||||
|
||||
auto root_node = doc.child("Relationships");
|
||||
|
||||
std::unordered_map<std::string, std::pair<std::string, std::string>> relationships;
|
||||
std::vector<relationship> relationships;
|
||||
|
||||
for(auto relationship : root_node.children("Relationship"))
|
||||
{
|
||||
std::string id = relationship.attribute("Id").as_string();
|
||||
std::string type = relationship.attribute("Type").as_string();
|
||||
std::string target = relationship.attribute("Target").as_string();
|
||||
relationships[id] = std::make_pair(target, type);
|
||||
relationships.push_back(xlnt::relationship(type, id, target));
|
||||
}
|
||||
|
||||
return relationships;
|
||||
|
@ -129,24 +130,13 @@ std::pair<std::unordered_map<std::string, std::string>, std::unordered_map<std::
|
|||
return std::make_pair(default_types, override_types);
|
||||
}
|
||||
|
||||
std::string reader::determine_document_type(const std::unordered_map<std::string, std::pair<std::string, std::string>> &root_relationships,
|
||||
const std::unordered_map<std::string, std::string> &override_types)
|
||||
std::string reader::determine_document_type(const std::unordered_map<std::string, std::string> &override_types)
|
||||
{
|
||||
auto relationship_match = std::find_if(root_relationships.begin(), root_relationships.end(),
|
||||
[](const std::pair<std::string, std::pair<std::string, std::string>> &v)
|
||||
{ return v.second.second == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"; });
|
||||
std::string type;
|
||||
|
||||
if(relationship_match != root_relationships.end())
|
||||
if(override_types.find("/xl/workbook.xml") != override_types.end())
|
||||
{
|
||||
std::string office_document_relationship = relationship_match->second.first;
|
||||
|
||||
if(office_document_relationship[0] != '/')
|
||||
{
|
||||
office_document_relationship = std::string("/") + office_document_relationship;
|
||||
}
|
||||
|
||||
type = override_types.at(office_document_relationship);
|
||||
type = override_types.at("/xl/workbook.xml");
|
||||
}
|
||||
|
||||
if(type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml")
|
||||
|
@ -214,12 +204,7 @@ void read_worksheet_common(worksheet ws, const pugi::xml_node &root_node, const
|
|||
else if(cell_node.attribute("s") != nullptr)
|
||||
{
|
||||
auto style_index = cell_node.attribute("s").as_int();
|
||||
auto number_format_id = number_format_ids[style_index];
|
||||
|
||||
if(style_index < 0 || style_index >= number_format_ids.size())
|
||||
{
|
||||
throw std::out_of_range(std::to_string(style_index));
|
||||
}
|
||||
auto number_format_id = number_format_ids.at(style_index);
|
||||
|
||||
if(number_format_id == 0) // integer
|
||||
{
|
||||
|
|
|
@ -2,16 +2,15 @@
|
|||
|
||||
namespace xlnt {
|
||||
|
||||
relationship::relationship(const std::string &t, const std::string &r_id, const std::string &target_uri) : id_(r_id), source_uri_(""), target_uri_(target_uri)
|
||||
relationship::relationship(type t, const std::string &r_id, const std::string &target_uri) : type_(t), id_(r_id), source_uri_(""), target_uri_(target_uri)
|
||||
{
|
||||
if(t == "hyperlink")
|
||||
if(t == type::hyperlink)
|
||||
{
|
||||
type_ = type::hyperlink;
|
||||
target_mode_ = target_mode::external;
|
||||
}
|
||||
}
|
||||
|
||||
relationship::relationship() : id_(""), source_uri_(""), target_uri_("")
|
||||
relationship::relationship() : type_(type::invalid), id_(""), source_uri_(""), target_uri_("")
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,9 @@ workbook_impl::workbook_impl() : active_sheet_index_(0), date_1904_(false)
|
|||
workbook::workbook() : d_(new detail::workbook_impl())
|
||||
{
|
||||
create_sheet("Sheet");
|
||||
create_relationship("rId2", "sharedStrings.xml", relationship::type::shared_strings);
|
||||
create_relationship("rId3", "styles.xml", relationship::type::styles);
|
||||
create_relationship("rId4", "theme/theme1.xml", relationship::type::theme);
|
||||
}
|
||||
|
||||
workbook::~workbook()
|
||||
|
@ -176,6 +179,7 @@ worksheet workbook::create_sheet()
|
|||
}
|
||||
|
||||
d_->worksheets_.push_back(detail::worksheet_impl(this, title));
|
||||
create_relationship("rId" + std::to_string(d_->relationships_.size() + 1), "worksheets/sheet" + std::to_string(d_->worksheets_.size()) + ".xml", relationship::type::worksheet);
|
||||
return worksheet(&d_->worksheets_.back());
|
||||
}
|
||||
|
||||
|
@ -284,21 +288,22 @@ bool workbook::load(const std::string &filename)
|
|||
zip_file f(filename, file_mode::open);
|
||||
//auto core_properties = read_core_properties();
|
||||
//auto app_properties = read_app_properties();
|
||||
auto root_relationships = reader::read_relationships(f.get_file_contents("_rels/.rels"));
|
||||
auto content_types = reader::read_content_types(f.get_file_contents("[Content_Types].xml"));
|
||||
|
||||
auto type = reader::determine_document_type(root_relationships, content_types.second);
|
||||
auto type = reader::determine_document_type(content_types.second);
|
||||
|
||||
if(type != "excel")
|
||||
{
|
||||
throw std::runtime_error("unsupported document type: " + filename);
|
||||
}
|
||||
|
||||
clear();
|
||||
|
||||
auto workbook_relationships = reader::read_relationships(f.get_file_contents("xl/_rels/workbook.xml.rels"));
|
||||
|
||||
for(auto relationship : workbook_relationships)
|
||||
{
|
||||
create_relationship(relationship.first, relationship.second.first, relationship.second.second);
|
||||
create_relationship(relationship.get_id(), relationship.get_target_uri(), relationship.get_type());
|
||||
}
|
||||
|
||||
pugi::xml_document doc;
|
||||
|
@ -311,25 +316,26 @@ bool workbook::load(const std::string &filename)
|
|||
|
||||
auto sheets_node = root_node.child("sheets");
|
||||
|
||||
clear();
|
||||
|
||||
std::vector<std::string> shared_strings;
|
||||
if(f.has_file("xl/sharedStrings.xml"))
|
||||
{
|
||||
shared_strings = xlnt::reader::read_shared_string(f.get_file_contents("xl/sharedStrings.xml"));
|
||||
}
|
||||
|
||||
std::vector<int> number_format_ids;
|
||||
|
||||
if(f.has_file("xl/styles.xml"))
|
||||
{
|
||||
pugi::xml_document styles_doc;
|
||||
styles_doc.load(f.get_file_contents("xl/styles.xml").c_str());
|
||||
auto stylesheet_node = styles_doc.child("styleSheet");
|
||||
auto cell_xfs_node = stylesheet_node.child("cellXfs");
|
||||
|
||||
std::vector<int> number_format_ids;
|
||||
|
||||
for(auto xf_node : cell_xfs_node.children("xf"))
|
||||
{
|
||||
number_format_ids.push_back(xf_node.attribute("numFmtId").as_int());
|
||||
}
|
||||
}
|
||||
|
||||
for(auto sheet_node : sheets_node.children("sheet"))
|
||||
{
|
||||
|
@ -343,7 +349,7 @@ bool workbook::load(const std::string &filename)
|
|||
return true;
|
||||
}
|
||||
|
||||
void workbook::create_relationship(const std::string &id, const std::string &target, const std::string &type)
|
||||
void workbook::create_relationship(const std::string &id, const std::string &target, relationship::type type)
|
||||
{
|
||||
d_->relationships_.push_back(relationship(type, id, target));
|
||||
}
|
||||
|
@ -468,6 +474,10 @@ worksheet workbook::operator[](std::size_t index)
|
|||
void workbook::clear()
|
||||
{
|
||||
d_->worksheets_.clear();
|
||||
d_->relationships_.clear();
|
||||
d_->active_sheet_index_ = 0;
|
||||
d_->date_1904_ = false;
|
||||
d_->drawings_.clear();
|
||||
}
|
||||
|
||||
bool workbook::save(std::vector<unsigned char> &data)
|
||||
|
@ -496,6 +506,16 @@ bool workbook::save(const std::string &filename)
|
|||
|
||||
f.set_file_contents("xl/workbook.xml", writer::write_workbook(*this));
|
||||
|
||||
for(auto relationship : d_->relationships_)
|
||||
{
|
||||
if(relationship.get_type() == relationship::type::worksheet)
|
||||
{
|
||||
std::string sheet_index_string = relationship.get_target_uri().substr(16);
|
||||
std::size_t sheet_index = std::stoi(sheet_index_string.substr(0, sheet_index_string.find('.'))) - 1;
|
||||
f.set_file_contents("xl/" + relationship.get_target_uri(), writer::write_worksheet(get_sheet_by_index(sheet_index)));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -514,7 +534,7 @@ std::vector<content_type> xlnt::workbook::get_content_types() const
|
|||
std::vector<content_type> content_types;
|
||||
content_types.push_back({ true, "xml", "", "application/xml" });
|
||||
content_types.push_back({ true, "rels", "", "application/vnd.openxmlformats-package.relationships+xml" });
|
||||
content_types.push_back({ false, "", "xl/workbook.xml", "applications/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" });
|
||||
content_types.push_back({ false, "", "/xl/workbook.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" });
|
||||
return content_types;
|
||||
}
|
||||
|
||||
|
|
|
@ -299,10 +299,10 @@ std::vector<relationship> worksheet::get_relationships()
|
|||
return d_->relationships_;
|
||||
}
|
||||
|
||||
relationship worksheet::create_relationship(const std::string &relationship_type, const std::string &target_uri)
|
||||
relationship worksheet::create_relationship(relationship::type type, const std::string &target_uri)
|
||||
{
|
||||
std::string r_id = "rId" + std::to_string(d_->relationships_.size() + 1);
|
||||
d_->relationships_.push_back(relationship(relationship_type, r_id, target_uri));
|
||||
d_->relationships_.push_back(relationship(type, r_id, target_uri));
|
||||
return d_->relationships_.back();
|
||||
}
|
||||
|
||||
|
@ -496,4 +496,19 @@ void worksheet::reserve(std::size_t n)
|
|||
d_->cell_map_.reserve(n);
|
||||
}
|
||||
|
||||
void worksheet::add_comment(const xlnt::comment &c)
|
||||
{
|
||||
d_->comments_.push_back(c);
|
||||
}
|
||||
|
||||
void worksheet::remove_comment(const xlnt::comment &c)
|
||||
{
|
||||
d_->comments_.pop_back();
|
||||
}
|
||||
|
||||
std::size_t worksheet::get_comment_count() const
|
||||
{
|
||||
return d_->comments_.size();
|
||||
}
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -162,13 +162,19 @@ std::string writer::write_workbook(const workbook &wb)
|
|||
auto sheets_node = root_node.append_child("sheets");
|
||||
auto defined_names_node = root_node.append_child("definedNames");
|
||||
|
||||
int i = 0;
|
||||
for(auto ws : wb)
|
||||
for(auto relationship : wb.get_relationships())
|
||||
{
|
||||
if(relationship.get_type() == relationship::type::worksheet)
|
||||
{
|
||||
std::string sheet_index_string = relationship.get_target_uri().substr(16);
|
||||
std::size_t sheet_index = std::stoi(sheet_index_string.substr(0, sheet_index_string.find('.'))) - 1;
|
||||
|
||||
auto ws = wb.get_sheet_by_index(sheet_index);
|
||||
|
||||
auto sheet_node = sheets_node.append_child("sheet");
|
||||
sheet_node.append_attribute("name").set_value(ws.get_title().c_str());
|
||||
sheet_node.append_attribute("r:id").set_value((std::string("rId") + std::to_string(i + 1)).c_str());
|
||||
sheet_node.append_attribute("sheetId").set_value(std::to_string(i + 1).c_str());
|
||||
sheet_node.append_attribute("r:id").set_value(relationship.get_id().c_str());
|
||||
sheet_node.append_attribute("sheetId").set_value(std::to_string(sheet_index + 1).c_str());
|
||||
|
||||
if(ws.has_auto_filter())
|
||||
{
|
||||
|
@ -179,8 +185,7 @@ std::string writer::write_workbook(const workbook &wb)
|
|||
std::string name = "'" + ws.get_title() + "'!" + range_reference::make_absolute(ws.get_auto_filter()).to_string();
|
||||
defined_name_node.text().set(name.c_str());
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
auto calc_pr_node = root_node.append_child("calcPr");
|
||||
|
@ -507,9 +512,9 @@ std::string xlnt::writer::write_root_rels()
|
|||
{
|
||||
std::vector<relationship> relationships;
|
||||
|
||||
relationships.push_back(relationship("a"));
|
||||
relationships.push_back(relationship("b"));
|
||||
relationships.push_back(relationship("c"));
|
||||
relationships.push_back(relationship(relationship::type::extended_properties, "rId3", "docProps/app.xml"));
|
||||
relationships.push_back(relationship(relationship::type::core_properties, "rId2", "docProps/core.xml"));
|
||||
relationships.push_back(relationship(relationship::type::office_document, "rId1", "xl/workbook.xml"));
|
||||
|
||||
return write_relationships(relationships);
|
||||
}
|
||||
|
@ -525,7 +530,11 @@ std::string writer::write_relationships(const std::vector<relationship> &relatio
|
|||
auto app_props_node = root_node.append_child("Relationship");
|
||||
app_props_node.append_attribute("Id").set_value(relationship.get_id().c_str());
|
||||
app_props_node.append_attribute("Target").set_value(relationship.get_target_uri().c_str());
|
||||
app_props_node.append_attribute("Type").set_value(relationship.get_target_uri().c_str());
|
||||
app_props_node.append_attribute("Type").set_value(relationship.get_type_string().c_str());
|
||||
if(relationship.get_target_mode() == target_mode::external)
|
||||
{
|
||||
app_props_node.append_attribute("TargetMode").set_value("External");
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
|
|
|
@ -8,23 +8,114 @@
|
|||
class Helper
|
||||
{
|
||||
public:
|
||||
static bool EqualsFileContent(const std::string &reference_file, const std::string &fixture)
|
||||
enum class difference_type
|
||||
{
|
||||
std::string fixture_content;
|
||||
names_differ,
|
||||
missing_attribute,
|
||||
attribute_values_differ,
|
||||
missing_text,
|
||||
text_values_differ,
|
||||
missing_child,
|
||||
child_order_differs,
|
||||
equivalent,
|
||||
};
|
||||
|
||||
if(false)//PathHelper::FileExists(fixture))
|
||||
struct comparison_result
|
||||
{
|
||||
std::fstream fixture_file;
|
||||
fixture_file.open(fixture);
|
||||
std::stringstream ss;
|
||||
ss << fixture_file.rdbuf();
|
||||
fixture_content = ss.str();
|
||||
}
|
||||
else
|
||||
difference_type difference;
|
||||
std::string value_left;
|
||||
std::string value_right;
|
||||
operator bool() const { return difference == difference_type::equivalent; }
|
||||
};
|
||||
|
||||
static comparison_result compare_xml(const pugi::xml_node &left, const pugi::xml_node &right)
|
||||
{
|
||||
fixture_content = fixture;
|
||||
std::string left_temp = left.name();
|
||||
std::string right_temp = right.name();
|
||||
|
||||
if(left_temp != right_temp)
|
||||
{
|
||||
return {difference_type::names_differ, left_temp, right_temp};
|
||||
}
|
||||
|
||||
for(auto left_attribute : left.attributes())
|
||||
{
|
||||
left_temp = left_attribute.name();
|
||||
auto right_attribute = right.attribute(left_attribute.name());
|
||||
|
||||
if(right_attribute == nullptr)
|
||||
{
|
||||
return {difference_type::missing_attribute, left_temp, "((empty))"};
|
||||
}
|
||||
|
||||
left_temp = left_attribute.value();
|
||||
right_temp = right_attribute.value();
|
||||
|
||||
if(left_temp != right_temp)
|
||||
{
|
||||
return {difference_type::attribute_values_differ, left_temp, right_temp};
|
||||
}
|
||||
}
|
||||
|
||||
if(left.text() != nullptr)
|
||||
{
|
||||
left_temp = left.text().as_string();
|
||||
|
||||
if(right.text() == nullptr)
|
||||
{
|
||||
return {difference_type::missing_text, left_temp, "((empty))"};
|
||||
}
|
||||
|
||||
right_temp = right.text().as_string();
|
||||
|
||||
if(left_temp != right_temp)
|
||||
{
|
||||
return {difference_type::text_values_differ, left_temp, right_temp};
|
||||
}
|
||||
}
|
||||
else if(right.text() != nullptr)
|
||||
{
|
||||
right_temp = right.text().as_string();
|
||||
return {difference_type::text_values_differ, "((empty))", right_temp};
|
||||
}
|
||||
|
||||
auto right_child_iter = right.children().begin();
|
||||
for(auto left_child : left.children())
|
||||
{
|
||||
left_temp = left_child.name();
|
||||
|
||||
if(right_child_iter == right.children().end())
|
||||
{
|
||||
return {difference_type::child_order_differs, left_temp, "((end))"};
|
||||
}
|
||||
|
||||
auto right_child = *right_child_iter;
|
||||
right_child_iter++;
|
||||
|
||||
if(left_child.type() == pugi::xml_node_type::node_cdata || left_child.type() == pugi::xml_node_type::node_pcdata)
|
||||
{
|
||||
continue; // ignore text children, these have already been compared
|
||||
}
|
||||
|
||||
auto child_comparison_result = compare_xml(left_child, right_child);
|
||||
|
||||
if(!child_comparison_result)
|
||||
{
|
||||
return child_comparison_result;
|
||||
}
|
||||
}
|
||||
|
||||
if(right_child_iter != right.children().end())
|
||||
{
|
||||
right_temp = right_child_iter->name();
|
||||
return {difference_type::child_order_differs, "((end))", right_temp};
|
||||
}
|
||||
|
||||
return {difference_type::equivalent, "", ""};
|
||||
}
|
||||
|
||||
static bool EqualsFileContent(const std::string &reference_file, const std::string &observed_content)
|
||||
{
|
||||
std::string expected_content;
|
||||
|
||||
if(PathHelper::FileExists(reference_file))
|
||||
|
@ -40,22 +131,12 @@ public:
|
|||
throw std::runtime_error("file not found");
|
||||
}
|
||||
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
doc.load(fixture_content.c_str());
|
||||
std::stringstream ss;
|
||||
doc.save(ss);
|
||||
fixture_content = ss.str();
|
||||
}
|
||||
pugi::xml_document doc_observed;
|
||||
doc_observed.load(observed_content.c_str());
|
||||
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
doc.load(expected_content.c_str());
|
||||
std::stringstream ss;
|
||||
doc.save(ss);
|
||||
expected_content = ss.str();
|
||||
}
|
||||
pugi::xml_document doc_expected;
|
||||
doc_expected.load(expected_content.c_str());
|
||||
|
||||
return expected_content == fixture_content;
|
||||
return compare_xml(doc_expected, doc_observed);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -21,7 +21,7 @@ int main( int argc, char *argv[] ) {
|
|||
return status;
|
||||
}
|
||||
bool suite_test_cell_init = false;
|
||||
#include "c:\Users\taf656\Development\xlnt\tests\test_cell.hpp"
|
||||
#include "/Users/thomas/Development/xlnt/tests/test_cell.hpp"
|
||||
|
||||
static test_cell suite_test_cell;
|
||||
|
||||
|
@ -238,7 +238,25 @@ public:
|
|||
void runTest() { suite_test_cell.test_is_not_date_color_format(); }
|
||||
} testDescription_suite_test_cell_test_is_not_date_color_format;
|
||||
|
||||
#include "c:\Users\taf656\Development\xlnt\tests\test_chart.hpp"
|
||||
static class TestDescription_suite_test_cell_test_comment_count : public CxxTest::RealTestDescription {
|
||||
public:
|
||||
TestDescription_suite_test_cell_test_comment_count() : CxxTest::RealTestDescription( Tests_test_cell, suiteDescription_test_cell, 394, "test_comment_count" ) {}
|
||||
void runTest() { suite_test_cell.test_comment_count(); }
|
||||
} testDescription_suite_test_cell_test_comment_count;
|
||||
|
||||
static class TestDescription_suite_test_cell_test_comment_assignment : public CxxTest::RealTestDescription {
|
||||
public:
|
||||
TestDescription_suite_test_cell_test_comment_assignment() : CxxTest::RealTestDescription( Tests_test_cell, suiteDescription_test_cell, 410, "test_comment_assignment" ) {}
|
||||
void runTest() { suite_test_cell.test_comment_assignment(); }
|
||||
} testDescription_suite_test_cell_test_comment_assignment;
|
||||
|
||||
static class TestDescription_suite_test_cell_test_cell_offset : public CxxTest::RealTestDescription {
|
||||
public:
|
||||
TestDescription_suite_test_cell_test_cell_offset() : CxxTest::RealTestDescription( Tests_test_cell, suiteDescription_test_cell, 424, "test_cell_offset" ) {}
|
||||
void runTest() { suite_test_cell.test_cell_offset(); }
|
||||
} testDescription_suite_test_cell_test_cell_offset;
|
||||
|
||||
#include "/Users/thomas/Development/xlnt/tests/test_chart.hpp"
|
||||
|
||||
static test_chart suite_test_chart;
|
||||
|
||||
|
@ -329,7 +347,7 @@ public:
|
|||
void runTest() { suite_test_chart.test_write_chart_scatter(); }
|
||||
} testDescription_suite_test_chart_test_write_chart_scatter;
|
||||
|
||||
#include "c:\Users\taf656\Development\xlnt\tests\test_named_range.hpp"
|
||||
#include "/Users/thomas/Development/xlnt/tests/test_named_range.hpp"
|
||||
|
||||
static test_named_range suite_test_named_range;
|
||||
|
||||
|
@ -420,7 +438,7 @@ public:
|
|||
void runTest() { suite_test_named_range.test_can_be_saved(); }
|
||||
} testDescription_suite_test_named_range_test_can_be_saved;
|
||||
|
||||
#include "c:\Users\taf656\Development\xlnt\tests\test_number_format.hpp"
|
||||
#include "/Users/thomas/Development/xlnt/tests/test_number_format.hpp"
|
||||
|
||||
static test_number_format suite_test_number_format;
|
||||
|
||||
|
@ -523,7 +541,7 @@ public:
|
|||
void runTest() { suite_test_number_format.test_mac_date(); }
|
||||
} testDescription_suite_test_number_format_test_mac_date;
|
||||
|
||||
#include "c:\Users\taf656\Development\xlnt\tests\test_props.hpp"
|
||||
#include "/Users/thomas/Development/xlnt/tests/test_props.hpp"
|
||||
|
||||
static test_props suite_test_props;
|
||||
|
||||
|
@ -566,7 +584,7 @@ public:
|
|||
void runTest() { suite_test_props.test_write_properties_app(); }
|
||||
} testDescription_suite_test_props_test_write_properties_app;
|
||||
|
||||
#include "c:\Users\taf656\Development\xlnt\tests\test_read.hpp"
|
||||
#include "/Users/thomas/Development/xlnt/tests/test_read.hpp"
|
||||
|
||||
static test_read suite_test_read;
|
||||
|
||||
|
@ -699,7 +717,7 @@ public:
|
|||
void runTest() { suite_test_read.test_read_date_value(); }
|
||||
} testDescription_suite_test_read_test_read_date_value;
|
||||
|
||||
#include "c:\Users\taf656\Development\xlnt\tests\test_strings.hpp"
|
||||
#include "/Users/thomas/Development/xlnt/tests/test_strings.hpp"
|
||||
|
||||
static test_strings suite_test_strings;
|
||||
|
||||
|
@ -730,7 +748,7 @@ public:
|
|||
void runTest() { suite_test_strings.test_formatted_string_table(); }
|
||||
} testDescription_suite_test_strings_test_formatted_string_table;
|
||||
|
||||
#include "c:\Users\taf656\Development\xlnt\tests\test_style.hpp"
|
||||
#include "/Users/thomas/Development/xlnt/tests/test_style.hpp"
|
||||
|
||||
static test_style suite_test_style;
|
||||
|
||||
|
@ -827,7 +845,7 @@ public:
|
|||
void runTest() { suite_test_style.test_read_cell_style(); }
|
||||
} testDescription_suite_test_style_test_read_cell_style;
|
||||
|
||||
#include "c:\Users\taf656\Development\xlnt\tests\test_theme.hpp"
|
||||
#include "/Users/thomas/Development/xlnt/tests/test_theme.hpp"
|
||||
|
||||
static test_theme suite_test_theme;
|
||||
|
||||
|
@ -840,7 +858,7 @@ public:
|
|||
void runTest() { suite_test_theme.test_write_theme(); }
|
||||
} testDescription_suite_test_theme_test_write_theme;
|
||||
|
||||
#include "c:\Users\taf656\Development\xlnt\tests\test_workbook.hpp"
|
||||
#include "/Users/thomas/Development/xlnt/tests/test_workbook.hpp"
|
||||
|
||||
static test_workbook suite_test_workbook;
|
||||
|
||||
|
@ -961,7 +979,7 @@ public:
|
|||
void runTest() { suite_test_workbook.test_write_regular_float(); }
|
||||
} testDescription_suite_test_workbook_test_write_regular_float;
|
||||
|
||||
#include "c:\Users\taf656\Development\xlnt\tests\test_worksheet.hpp"
|
||||
#include "/Users/thomas/Development/xlnt/tests/test_worksheet.hpp"
|
||||
|
||||
static test_worksheet suite_test_worksheet;
|
||||
|
||||
|
@ -1130,7 +1148,7 @@ public:
|
|||
void runTest() { suite_test_worksheet.test_printer_settings(); }
|
||||
} testDescription_suite_test_worksheet_test_printer_settings;
|
||||
|
||||
#include "c:\Users\taf656\Development\xlnt\tests\test_write.hpp"
|
||||
#include "/Users/thomas/Development/xlnt/tests/test_write.hpp"
|
||||
|
||||
static test_write suite_test_write;
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void test_column_letter_boundries()
|
||||
void test_column_letter_boundaries()
|
||||
{
|
||||
TS_ASSERT_THROWS(xlnt::cell_reference::column_string_from_index(0),
|
||||
xlnt::column_string_index_exception);
|
||||
|
@ -337,6 +337,16 @@ public:
|
|||
TS_ASSERT_EQUALS(cell, xlnt::time(3, 40));
|
||||
}
|
||||
|
||||
void test_timedelta()
|
||||
{
|
||||
xlnt::worksheet ws = wb.create_sheet();
|
||||
xlnt::cell cell(ws, "A1");
|
||||
|
||||
cell = xlnt::timedelta().days(1).hours(3);
|
||||
TS_ASSERT_EQUALS(cell, 1.125);
|
||||
TS_ASSERT_EQUALS(cell.get_data_type(), xlnt::cell::type::numeric);
|
||||
}
|
||||
|
||||
void test_date_format_on_non_date()
|
||||
{
|
||||
xlnt::worksheet ws = wb.create_sheet();
|
||||
|
@ -391,6 +401,42 @@ public:
|
|||
TS_ASSERT(!cell.is_date());
|
||||
}
|
||||
|
||||
void test_comment_count()
|
||||
{
|
||||
xlnt::worksheet ws = wb.create_sheet();
|
||||
xlnt::cell cell(ws, "A1");
|
||||
|
||||
TS_ASSERT(ws.get_comment_count() == 0);
|
||||
cell.set_comment(xlnt::comment("text", "author"));
|
||||
TS_ASSERT(ws.get_comment_count() == 1);
|
||||
cell.set_comment(xlnt::comment("text", "author"));
|
||||
TS_ASSERT(ws.get_comment_count() == 1);
|
||||
cell.clear_comment();
|
||||
TS_ASSERT(ws.get_comment_count() == 0);
|
||||
cell.clear_comment();
|
||||
TS_ASSERT(ws.get_comment_count() == 0);
|
||||
}
|
||||
|
||||
void test_comment_assignment()
|
||||
{
|
||||
xlnt::worksheet ws = wb.create_sheet();
|
||||
xlnt::cell cell(ws, "A1");
|
||||
|
||||
xlnt::comment c("text", "author");
|
||||
cell.set_comment(c);
|
||||
TS_ASSERT_THROWS_ANYTHING(ws.get_cell("A2").set_comment(c));
|
||||
ws.get_cell("A2").set_comment(xlnt::comment("text2", "author2"));
|
||||
TS_ASSERT_THROWS_ANYTHING(ws.get_cell("A1").set_comment(ws.get_cell("A2").get_comment()));
|
||||
ws.get_cell("A1").clear_comment();
|
||||
TS_ASSERT_THROWS_NOTHING(ws.get_cell("A2").set_comment(c));
|
||||
}
|
||||
|
||||
void test_cell_offset()
|
||||
{
|
||||
xlnt::worksheet ws = wb.create_sheet();
|
||||
TS_ASSERT(ws.get_cell("B15").offset(1, 2).get_reference() == "C17");
|
||||
}
|
||||
|
||||
private:
|
||||
xlnt::workbook wb;
|
||||
};
|
||||
|
|
|
@ -164,7 +164,7 @@ public:
|
|||
|
||||
void test_bad_relationship_type()
|
||||
{
|
||||
xlnt::relationship rel("bad_type");
|
||||
xlnt::relationship rel("bad");
|
||||
}
|
||||
|
||||
void test_append_list()
|
||||
|
|
Loading…
Reference in New Issue
Block a user