mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
implement sheetFormatPr, x14ac:dyDescent, reordering workbook rels so sheets come first after insertions
This commit is contained in:
parent
90633d0e8e
commit
0f0d3de75f
|
@ -839,6 +839,11 @@ private:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void swap(workbook &other);
|
void swap(workbook &other);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sheet 1 should be rId1, sheet 2 should be rId2, etc.
|
||||||
|
/// </summary>
|
||||||
|
void reorder_relationships();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An opaque pointer to a structure that holds all of the data relating to this workbook.
|
/// An opaque pointer to a structure that holds all of the data relating to this workbook.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
53
include/xlnt/worksheet/sheet_format_properties.hpp
Normal file
53
include/xlnt/worksheet/sheet_format_properties.hpp
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright (c) 2018 Thomas Fussell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE
|
||||||
|
//
|
||||||
|
// @license: http://www.opensource.org/licenses/mit-license.php
|
||||||
|
// @author: see AUTHORS file
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <xlnt/xlnt_config.hpp>
|
||||||
|
#include <xlnt/utils/optional.hpp>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// General worksheet formatting properties.
|
||||||
|
/// </summary>
|
||||||
|
class XLNT_API sheet_format_properties
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// The base column width
|
||||||
|
/// </summary>
|
||||||
|
optional<double> base_col_width;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default row height
|
||||||
|
/// </summary>
|
||||||
|
optional<double> default_row_height;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// x14ac extension, dyDescent property
|
||||||
|
/// </summary>
|
||||||
|
optional<double> dy_descent;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
|
@ -54,6 +54,7 @@ class range_iterator;
|
||||||
class range_reference;
|
class range_reference;
|
||||||
class relationship;
|
class relationship;
|
||||||
class row_properties;
|
class row_properties;
|
||||||
|
class sheet_format_properties;
|
||||||
class workbook;
|
class workbook;
|
||||||
|
|
||||||
struct date;
|
struct date;
|
||||||
|
@ -708,6 +709,26 @@ public:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
xlnt::conditional_format conditional_format(const range_reference &ref, const condition &when);
|
xlnt::conditional_format conditional_format(const range_reference &ref, const condition &when);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the path of this worksheet in the containing package.
|
||||||
|
/// </summary>
|
||||||
|
path path() const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the relationship from the parent workbook to this worksheet.
|
||||||
|
/// </summary>
|
||||||
|
relationship referring_relationship() const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the current formatting properties.
|
||||||
|
/// </summary>
|
||||||
|
sheet_format_properties format_properties() const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the format properties to the given properties.
|
||||||
|
/// </summary>
|
||||||
|
void format_properties(const sheet_format_properties &properties);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class cell;
|
friend class cell;
|
||||||
friend class const_range_iterator;
|
friend class const_range_iterator;
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <xlnt/cell/cell_reference.hpp>
|
#include <xlnt/cell/cell_reference.hpp>
|
||||||
#include <xlnt/cell/comment.hpp>
|
#include <xlnt/cell/comment.hpp>
|
||||||
#include <xlnt/cell/rich_text.hpp>
|
#include <xlnt/cell/rich_text.hpp>
|
||||||
|
#include <xlnt/packaging/manifest.hpp>
|
||||||
#include <xlnt/packaging/relationship.hpp>
|
#include <xlnt/packaging/relationship.hpp>
|
||||||
#include <xlnt/styles/alignment.hpp>
|
#include <xlnt/styles/alignment.hpp>
|
||||||
#include <xlnt/styles/border.hpp>
|
#include <xlnt/styles/border.hpp>
|
||||||
|
@ -372,6 +373,23 @@ void cell::hyperlink(const std::string &hyperlink)
|
||||||
throw invalid_parameter();
|
throw invalid_parameter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto ws = worksheet();
|
||||||
|
auto &manifest = ws.workbook().manifest();
|
||||||
|
bool existing = false;
|
||||||
|
|
||||||
|
for (const auto &rel : manifest.relationships(ws.path(), relationship_type::hyperlink))
|
||||||
|
{
|
||||||
|
if (rel.target().path().string() == hyperlink)
|
||||||
|
{
|
||||||
|
existing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!existing) {
|
||||||
|
manifest.register_relationship(uri(ws.path().string()), relationship_type::hyperlink,
|
||||||
|
uri(hyperlink), target_mode::external);
|
||||||
|
}
|
||||||
|
|
||||||
d_->hyperlink_ = hyperlink;
|
d_->hyperlink_ = hyperlink;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,12 +29,13 @@
|
||||||
|
|
||||||
#include <detail/implementations/cell_impl.hpp>
|
#include <detail/implementations/cell_impl.hpp>
|
||||||
#include <xlnt/workbook/named_range.hpp>
|
#include <xlnt/workbook/named_range.hpp>
|
||||||
#include <xlnt/worksheet/range.hpp>
|
|
||||||
#include <xlnt/worksheet/range_reference.hpp>
|
|
||||||
#include <xlnt/worksheet/sheet_view.hpp>
|
|
||||||
#include <xlnt/worksheet/column_properties.hpp>
|
#include <xlnt/worksheet/column_properties.hpp>
|
||||||
#include <xlnt/worksheet/header_footer.hpp>
|
#include <xlnt/worksheet/header_footer.hpp>
|
||||||
|
#include <xlnt/worksheet/range.hpp>
|
||||||
|
#include <xlnt/worksheet/range_reference.hpp>
|
||||||
#include <xlnt/worksheet/row_properties.hpp>
|
#include <xlnt/worksheet/row_properties.hpp>
|
||||||
|
#include <xlnt/worksheet/sheet_format_properties.hpp>
|
||||||
|
#include <xlnt/worksheet/sheet_view.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
|
@ -62,18 +63,10 @@ struct worksheet_impl
|
||||||
|
|
||||||
id_ = other.id_;
|
id_ = other.id_;
|
||||||
title_ = other.title_;
|
title_ = other.title_;
|
||||||
|
format_properties_ = other.format_properties_;
|
||||||
column_properties_ = other.column_properties_;
|
column_properties_ = other.column_properties_;
|
||||||
row_properties_ = other.row_properties_;
|
row_properties_ = other.row_properties_;
|
||||||
cell_map_ = other.cell_map_;
|
cell_map_ = other.cell_map_;
|
||||||
|
|
||||||
for (auto &row : cell_map_)
|
|
||||||
{
|
|
||||||
for (auto &cell : row.second)
|
|
||||||
{
|
|
||||||
cell.second.parent_ = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
page_setup_ = other.page_setup_;
|
page_setup_ = other.page_setup_;
|
||||||
auto_filter_ = other.auto_filter_;
|
auto_filter_ = other.auto_filter_;
|
||||||
page_margins_ = other.page_margins_;
|
page_margins_ = other.page_margins_;
|
||||||
|
@ -86,6 +79,14 @@ struct worksheet_impl
|
||||||
views_ = other.views_;
|
views_ = other.views_;
|
||||||
column_breaks_ = other.column_breaks_;
|
column_breaks_ = other.column_breaks_;
|
||||||
row_breaks_ = other.row_breaks_;
|
row_breaks_ = other.row_breaks_;
|
||||||
|
|
||||||
|
for (auto &row : cell_map_)
|
||||||
|
{
|
||||||
|
for (auto &cell : row.second)
|
||||||
|
{
|
||||||
|
cell.second.parent_ = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
workbook *parent_;
|
workbook *parent_;
|
||||||
|
@ -93,6 +94,8 @@ struct worksheet_impl
|
||||||
std::size_t id_;
|
std::size_t id_;
|
||||||
std::string title_;
|
std::string title_;
|
||||||
|
|
||||||
|
sheet_format_properties format_properties_;
|
||||||
|
|
||||||
std::unordered_map<column_t, column_properties> column_properties_;
|
std::unordered_map<column_t, column_properties> column_properties_;
|
||||||
std::unordered_map<row_t, row_properties> row_properties_;
|
std::unordered_map<row_t, row_properties> row_properties_;
|
||||||
|
|
||||||
|
|
|
@ -518,7 +518,25 @@ std::string xlsx_consumer::read_worksheet_begin(const std::string &rel_id)
|
||||||
}
|
}
|
||||||
else if (current_worksheet_element == qn("spreadsheetml", "sheetFormatPr")) // CT_SheetFormatPr 0-1
|
else if (current_worksheet_element == qn("spreadsheetml", "sheetFormatPr")) // CT_SheetFormatPr 0-1
|
||||||
{
|
{
|
||||||
skip_remaining_content(current_worksheet_element);
|
if (parser().attribute_present("baseColWidth"))
|
||||||
|
{
|
||||||
|
ws.d_->format_properties_.base_col_width =
|
||||||
|
parser().attribute<double>("baseColWidth");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser().attribute_present("defaultRowHeight"))
|
||||||
|
{
|
||||||
|
ws.d_->format_properties_.default_row_height =
|
||||||
|
parser().attribute<double>("defaultRowHeight");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser().attribute_present(qn("x14ac", "dyDescent")))
|
||||||
|
{
|
||||||
|
ws.d_->format_properties_.dy_descent =
|
||||||
|
parser().attribute<double>(qn("x14ac", "dyDescent"));
|
||||||
|
}
|
||||||
|
|
||||||
|
skip_attributes();
|
||||||
}
|
}
|
||||||
else if (current_worksheet_element == qn("spreadsheetml", "cols")) // CT_Cols 0+
|
else if (current_worksheet_element == qn("spreadsheetml", "cols")) // CT_Cols 0+
|
||||||
{
|
{
|
||||||
|
|
|
@ -1990,6 +1990,7 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
||||||
{
|
{
|
||||||
static const auto &xmlns = constants::ns("spreadsheetml");
|
static const auto &xmlns = constants::ns("spreadsheetml");
|
||||||
static const auto &xmlns_r = constants::ns("r");
|
static const auto &xmlns_r = constants::ns("r");
|
||||||
|
static const auto &xmlns_x14ac = constants::ns("x14ac");
|
||||||
|
|
||||||
auto worksheet_part = rel.source().path().parent().append(rel.target().path());
|
auto worksheet_part = rel.source().path().parent().append(rel.target().path());
|
||||||
auto worksheet_rels = source_.manifest().relationships(worksheet_part);
|
auto worksheet_rels = source_.manifest().relationships(worksheet_part);
|
||||||
|
@ -2005,6 +2006,21 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
||||||
write_namespace(xmlns, "");
|
write_namespace(xmlns, "");
|
||||||
write_namespace(xmlns_r, "r");
|
write_namespace(xmlns_r, "r");
|
||||||
|
|
||||||
|
auto using_namespace = [&ws](const std::string &ns)
|
||||||
|
{
|
||||||
|
if (ns == "x14ac")
|
||||||
|
{
|
||||||
|
return ws.format_properties().dy_descent.is_set();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (using_namespace("x14ac"))
|
||||||
|
{
|
||||||
|
write_namespace(xmlns_x14ac, "x14ac");
|
||||||
|
}
|
||||||
|
|
||||||
if (ws.has_page_setup())
|
if (ws.has_page_setup())
|
||||||
{
|
{
|
||||||
write_start_element(xmlns, "sheetPr");
|
write_start_element(xmlns, "sheetPr");
|
||||||
|
@ -2098,8 +2114,26 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
||||||
}
|
}
|
||||||
|
|
||||||
write_start_element(xmlns, "sheetFormatPr");
|
write_start_element(xmlns, "sheetFormatPr");
|
||||||
write_attribute("baseColWidth", "10");
|
const auto &format_properties = ws.d_->format_properties_;
|
||||||
write_attribute("defaultRowHeight", "16");
|
|
||||||
|
if (format_properties.base_col_width.is_set())
|
||||||
|
{
|
||||||
|
write_attribute("baseColWidth",
|
||||||
|
format_properties.base_col_width.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format_properties.default_row_height.is_set())
|
||||||
|
{
|
||||||
|
write_attribute("defaultRowHeight",
|
||||||
|
format_properties.default_row_height.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format_properties.dy_descent.is_set())
|
||||||
|
{
|
||||||
|
write_attribute(xml::qname(xmlns_x14ac, "dyDescent"),
|
||||||
|
format_properties.dy_descent.get());
|
||||||
|
}
|
||||||
|
|
||||||
write_end_element(xmlns, "sheetFormatPr");
|
write_end_element(xmlns, "sheetFormatPr");
|
||||||
|
|
||||||
bool has_column_properties = false;
|
bool has_column_properties = false;
|
||||||
|
|
|
@ -63,8 +63,16 @@ relationship_type relationship::type() const
|
||||||
|
|
||||||
bool relationship::operator==(const relationship &rhs) const
|
bool relationship::operator==(const relationship &rhs) const
|
||||||
{
|
{
|
||||||
return type_ == rhs.type_ && id_ == rhs.id_ && source_ == rhs.source_ && target_ == rhs.target_
|
return type_ == rhs.type_
|
||||||
|
&& id_ == rhs.id_
|
||||||
|
&& source_ == rhs.source_
|
||||||
|
&& target_ == rhs.target_
|
||||||
&& mode_ == rhs.mode_;
|
&& mode_ == rhs.mode_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool relationship::operator!=(const relationship &rhs) const
|
||||||
|
{
|
||||||
|
return !(*this == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -429,6 +429,10 @@ workbook workbook::empty()
|
||||||
sheet_view view;
|
sheet_view view;
|
||||||
ws.add_view(view);
|
ws.add_view(view);
|
||||||
|
|
||||||
|
auto &format_properties = ws.d_->format_properties_;
|
||||||
|
format_properties.base_col_width = 10.0;
|
||||||
|
format_properties.default_row_height = 16.0;
|
||||||
|
|
||||||
wb.theme(xlnt::theme());
|
wb.theme(xlnt::theme());
|
||||||
|
|
||||||
wb.d_->stylesheet_ = detail::stylesheet();
|
wb.d_->stylesheet_ = detail::stylesheet();
|
||||||
|
@ -719,6 +723,7 @@ worksheet workbook::create_sheet()
|
||||||
d_->sheet_title_rel_id_map_[title] = ws_rel;
|
d_->sheet_title_rel_id_map_[title] = ws_rel;
|
||||||
|
|
||||||
update_sheet_properties();
|
update_sheet_properties();
|
||||||
|
reorder_relationships();
|
||||||
|
|
||||||
return worksheet(&d_->worksheets_.back());
|
return worksheet(&d_->worksheets_.back());
|
||||||
}
|
}
|
||||||
|
@ -1496,4 +1501,70 @@ void workbook::update_sheet_properties()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void workbook::reorder_relationships()
|
||||||
|
{
|
||||||
|
const auto wb_rel = manifest().relationship(path("/"), relationship_type::office_document);
|
||||||
|
const auto wb_path = wb_rel.target().path();
|
||||||
|
const auto relationships = manifest().relationships(wb_path);
|
||||||
|
std::unordered_map<std::string, relationship> rel_map;
|
||||||
|
const auto titles = sheet_titles();
|
||||||
|
const auto title_rel_id_map = d_->sheet_title_rel_id_map_;
|
||||||
|
bool needs_reorder = false;
|
||||||
|
|
||||||
|
for (const auto &rel : relationships)
|
||||||
|
{
|
||||||
|
rel_map[rel.id()] = rel;
|
||||||
|
|
||||||
|
if (rel.type() == relationship_type::worksheet)
|
||||||
|
{
|
||||||
|
for (auto title_index = std::size_t(0); title_index < titles.size(); ++title_index)
|
||||||
|
{
|
||||||
|
const auto title = titles[title_index];
|
||||||
|
|
||||||
|
if (title_rel_id_map.at(title) == rel.id())
|
||||||
|
{
|
||||||
|
const auto expected_rel_id = "rId" + std::to_string(title_index + 1);
|
||||||
|
|
||||||
|
if (expected_rel_id != rel.id())
|
||||||
|
{
|
||||||
|
needs_reorder = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!needs_reorder)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &rel : relationships)
|
||||||
|
{
|
||||||
|
manifest().unregister_relationship(uri(wb_path.string()), rel.id());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto index = std::size_t(0); index < rel_map.size(); ++index)
|
||||||
|
{
|
||||||
|
auto rel_id = "rId" + std::to_string(index + 1);
|
||||||
|
auto old_rel_id = std::string();
|
||||||
|
|
||||||
|
if (index < titles.size())
|
||||||
|
{
|
||||||
|
auto title = titles[index];
|
||||||
|
old_rel_id = title_rel_id_map.at(title);
|
||||||
|
d_->sheet_title_rel_id_map_[title] = rel_id;
|
||||||
|
} else {
|
||||||
|
old_rel_id = "rId" + std::to_string(index - titles.size() + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto old_rel = rel_map[old_rel_id];
|
||||||
|
auto new_rel = relationship(rel_id, old_rel.type(),
|
||||||
|
old_rel.source(), old_rel.target(), old_rel.target_mode());
|
||||||
|
manifest().register_relationship(new_rel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -1110,4 +1110,30 @@ conditional_format worksheet::conditional_format(const range_reference &ref, con
|
||||||
return workbook().d_->stylesheet_.get().add_conditional_format_rule(d_, ref, when);
|
return workbook().d_->stylesheet_.get().add_conditional_format_rule(d_, ref, when);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
path worksheet::path() const
|
||||||
|
{
|
||||||
|
auto rel = referring_relationship();
|
||||||
|
return xlnt::path(rel.source().path().parent().append(rel.target().path()));
|
||||||
|
}
|
||||||
|
|
||||||
|
relationship worksheet::referring_relationship() const
|
||||||
|
{
|
||||||
|
auto &manifest = workbook().manifest();
|
||||||
|
auto wb_rel = manifest.relationship(xlnt::path("/"),
|
||||||
|
relationship_type::office_document);
|
||||||
|
auto ws_rel = manifest.relationship(wb_rel.target().path(),
|
||||||
|
workbook().d_->sheet_title_rel_id_map_.at(title()));
|
||||||
|
return ws_rel;
|
||||||
|
}
|
||||||
|
|
||||||
|
sheet_format_properties worksheet::format_properties() const
|
||||||
|
{
|
||||||
|
return d_->format_properties_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void worksheet::format_properties(const sheet_format_properties &properties)
|
||||||
|
{
|
||||||
|
d_->format_properties_ = properties;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include <detail/external/include_libstudxml.hpp>
|
#include <detail/external/include_libstudxml.hpp>
|
||||||
#include <detail/serialization/vector_streambuf.hpp>
|
#include <detail/serialization/vector_streambuf.hpp>
|
||||||
|
@ -15,9 +16,22 @@ public:
|
||||||
const std::string &right, const std::string &content_type)
|
const std::string &right, const std::string &content_type)
|
||||||
{
|
{
|
||||||
// content types are stored in unordered maps, too complicated to compare
|
// content types are stored in unordered maps, too complicated to compare
|
||||||
if (content_type == "[Content_Types].xml") return true;
|
if (content_type == "[Content_Types].xml")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// calcChain is optional
|
// calcChain is optional
|
||||||
if (content_type == "application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml") return true;
|
if (content_type == "application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compared already
|
||||||
|
if (content_type == "application/vnd.openxmlformats-package.relationships+xml")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
auto is_xml = (content_type.substr(0, 12) == "application/"
|
auto is_xml = (content_type.substr(0, 12) == "application/"
|
||||||
&& content_type.substr(content_type.size() - 4) == "+xml")
|
&& content_type.substr(content_type.size() - 4) == "+xml")
|
||||||
|
@ -206,6 +220,57 @@ public:
|
||||||
return !difference;
|
return !difference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool compare_relationships(const xlnt::manifest &left,
|
||||||
|
const xlnt::manifest &right)
|
||||||
|
{
|
||||||
|
std::unordered_set<std::string> parts;
|
||||||
|
|
||||||
|
for (const auto &part : left.parts())
|
||||||
|
{
|
||||||
|
parts.insert(part.string());
|
||||||
|
|
||||||
|
auto left_rels = left.relationships(part);
|
||||||
|
auto right_rels = right.relationships(part);
|
||||||
|
|
||||||
|
if (left_rels.size() != right_rels.size())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<std::string, xlnt::relationship> left_rels_map;
|
||||||
|
|
||||||
|
for (const auto &rel : left_rels)
|
||||||
|
{
|
||||||
|
left_rels_map[rel.id()] = rel;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &right_rel : right_rels)
|
||||||
|
{
|
||||||
|
if (left_rels_map.count(right_rel.id()) != 1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &left_rel = left_rels_map.at(right_rel.id());
|
||||||
|
|
||||||
|
if (left_rel != right_rel)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &part : right.parts())
|
||||||
|
{
|
||||||
|
if (parts.count(part.string()) != 1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool xlsx_archives_match(const std::vector<std::uint8_t> &left,
|
static bool xlsx_archives_match(const std::vector<std::uint8_t> &left,
|
||||||
const std::vector<std::uint8_t> &right)
|
const std::vector<std::uint8_t> &right)
|
||||||
{
|
{
|
||||||
|
@ -271,6 +336,11 @@ public:
|
||||||
auto &left_manifest = left_workbook.manifest();
|
auto &left_manifest = left_workbook.manifest();
|
||||||
auto &right_manifest = right_workbook.manifest();
|
auto &right_manifest = right_workbook.manifest();
|
||||||
|
|
||||||
|
if (!compare_relationships(left_manifest, right_manifest))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto left_member : left_info)
|
for (auto left_member : left_info)
|
||||||
{
|
{
|
||||||
if (!right_archive.has_file(left_member))
|
if (!right_archive.has_file(left_member))
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2014-2018 Thomas Fussell
|
// Copyright (c) 2014-2018 Thomas Fussell
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -31,6 +31,7 @@
|
||||||
#include <helpers/test_suite.hpp>
|
#include <helpers/test_suite.hpp>
|
||||||
#include <helpers/path_helper.hpp>
|
#include <helpers/path_helper.hpp>
|
||||||
#include <helpers/xml_helper.hpp>
|
#include <helpers/xml_helper.hpp>
|
||||||
|
#include <xlnt/worksheet/sheet_format_properties.hpp>
|
||||||
#include <xlnt/workbook/streaming_workbook_reader.hpp>
|
#include <xlnt/workbook/streaming_workbook_reader.hpp>
|
||||||
#include <xlnt/workbook/streaming_workbook_writer.hpp>
|
#include <xlnt/workbook/streaming_workbook_writer.hpp>
|
||||||
#include <xlnt/workbook/workbook.hpp>
|
#include <xlnt/workbook/workbook.hpp>
|
||||||
|
@ -78,6 +79,7 @@ public:
|
||||||
{
|
{
|
||||||
std::vector<std::uint8_t> wb_data;
|
std::vector<std::uint8_t> wb_data;
|
||||||
wb.save(wb_data);
|
wb.save(wb_data);
|
||||||
|
wb.save("temp.xlsx");
|
||||||
|
|
||||||
std::ifstream file_stream(file.string(), std::ios::binary);
|
std::ifstream file_stream(file.string(), std::ios::binary);
|
||||||
auto file_data = xlnt::detail::to_vector(file_stream);
|
auto file_data = xlnt::detail::to_vector(file_stream);
|
||||||
|
@ -178,8 +180,25 @@ public:
|
||||||
void test_write_comments_hyperlinks_formulae()
|
void test_write_comments_hyperlinks_formulae()
|
||||||
{
|
{
|
||||||
xlnt::workbook wb;
|
xlnt::workbook wb;
|
||||||
|
|
||||||
|
xlnt::sheet_format_properties format_properties;
|
||||||
|
format_properties.base_col_width = 10.0;
|
||||||
|
format_properties.default_row_height = 16.0;
|
||||||
|
format_properties.dy_descent = 0.2;
|
||||||
|
|
||||||
auto sheet1 = wb.active_sheet();
|
auto sheet1 = wb.active_sheet();
|
||||||
auto comment_font = xlnt::font().bold(true).size(10).color(xlnt::indexed_color(81)).name("Calibri");
|
sheet1.format_properties(format_properties);
|
||||||
|
|
||||||
|
auto comment_font = xlnt::font()
|
||||||
|
.bold(true)
|
||||||
|
.size(10)
|
||||||
|
.color(xlnt::indexed_color(81))
|
||||||
|
.name("Calibri");
|
||||||
|
|
||||||
|
sheet1.cell("A4").hyperlink("https://microsoft.com/", "hyperlink1");
|
||||||
|
sheet1.cell("A5").hyperlink("https://google.com/");
|
||||||
|
sheet1.cell("A6").hyperlink(sheet1.cell("A1"));
|
||||||
|
sheet1.cell("A7").hyperlink("mailto:invalid@example.com?subject=important");
|
||||||
|
|
||||||
sheet1.cell("A1").value("Sheet1!A1");
|
sheet1.cell("A1").value("Sheet1!A1");
|
||||||
sheet1.cell("A1").comment("Sheet1 comment", comment_font, "Microsoft Office User");
|
sheet1.cell("A1").comment("Sheet1 comment", comment_font, "Microsoft Office User");
|
||||||
|
@ -187,24 +206,21 @@ public:
|
||||||
sheet1.cell("A2").value("Sheet1!A2");
|
sheet1.cell("A2").value("Sheet1!A2");
|
||||||
sheet1.cell("A2").comment("Sheet1 comment2", comment_font, "Microsoft Office User");
|
sheet1.cell("A2").comment("Sheet1 comment2", comment_font, "Microsoft Office User");
|
||||||
|
|
||||||
sheet1.cell("A4").hyperlink("https://microsoft.com", "hyperlink1");
|
|
||||||
sheet1.cell("A5").hyperlink("https://google.com");
|
|
||||||
sheet1.cell("A6").hyperlink(sheet1.cell("A1"));
|
|
||||||
sheet1.cell("A7").hyperlink("mailto:invalid@example.com?subject=important");
|
|
||||||
|
|
||||||
sheet1.cell("C1").formula("=CONCATENATE(C2,C3)");
|
sheet1.cell("C1").formula("=CONCATENATE(C2,C3)");
|
||||||
sheet1.cell("C2").value("a");
|
sheet1.cell("C2").value("a");
|
||||||
sheet1.cell("C3").value("b");
|
sheet1.cell("C3").value("b");
|
||||||
|
|
||||||
auto sheet2 = wb.create_sheet();
|
auto sheet2 = wb.create_sheet();
|
||||||
|
sheet2.format_properties(format_properties);
|
||||||
|
|
||||||
|
sheet2.cell("A4").hyperlink("https://apple.com/", "hyperlink2");
|
||||||
|
|
||||||
sheet2.cell("A1").value("Sheet2!A1");
|
sheet2.cell("A1").value("Sheet2!A1");
|
||||||
sheet2.cell("A2").comment("Sheet2 comment", comment_font, "Microsoft Office User");
|
sheet2.cell("A2").comment("Sheet2 comment", comment_font, "Microsoft Office User");
|
||||||
|
|
||||||
sheet2.cell("A2").value("Sheet2!A2");
|
sheet2.cell("A2").value("Sheet2!A2");
|
||||||
sheet2.cell("A2").comment("Sheet2 comment2", comment_font, "Microsoft Office User");
|
sheet2.cell("A2").comment("Sheet2 comment2", comment_font, "Microsoft Office User");
|
||||||
|
|
||||||
sheet2.cell("A4").hyperlink("https://apple.com", "hyperlink2");
|
|
||||||
|
|
||||||
sheet2.cell("C1").formula("=C2*C3");
|
sheet2.cell("C1").formula("=C2*C3");
|
||||||
sheet2.cell("C2").value(2);
|
sheet2.cell("C2").value(2);
|
||||||
sheet2.cell("C3").value(3);
|
sheet2.cell("C3").value(3);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user