mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
work on hyperlinks, x14 extentions, other round tripping silliness
This commit is contained in:
parent
2426215801
commit
410e73d594
|
@ -47,6 +47,8 @@ class font;
|
|||
class format;
|
||||
class number_format;
|
||||
class protection;
|
||||
class range;
|
||||
class relationship;
|
||||
class style;
|
||||
class workbook;
|
||||
class worksheet;
|
||||
|
@ -251,9 +253,9 @@ public:
|
|||
// hyperlink
|
||||
|
||||
/// <summary>
|
||||
/// Returns the URL of this cell's hyperlink.
|
||||
/// Returns the relationship of this cell's hyperlink.
|
||||
/// </summary>
|
||||
std::string hyperlink() const;
|
||||
class hyperlink hyperlink() const;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a hyperlink to this cell pointing to the URL of the given value.
|
||||
|
@ -271,6 +273,11 @@ public:
|
|||
/// </summary>
|
||||
void hyperlink(xlnt::cell target);
|
||||
|
||||
/// <summary>
|
||||
/// Adds an internal hyperlink to this cell pointing to the given range.
|
||||
/// </summary>
|
||||
void hyperlink(xlnt::range target);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this cell has a hyperlink set.
|
||||
/// </summary>
|
||||
|
|
61
include/xlnt/cell/hyperlink.hpp
Normal file
61
include/xlnt/cell/hyperlink.hpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
// 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 <string>
|
||||
#include <xlnt/xlnt_config.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
namespace detail {
|
||||
struct hyperlink_impl;
|
||||
}
|
||||
|
||||
class cell;
|
||||
class range;
|
||||
class relationship;
|
||||
|
||||
/// <summary>
|
||||
/// Describes a hyperlink pointing from a cell to another cell or a URL.
|
||||
/// </summary>
|
||||
class XLNT_API hyperlink
|
||||
{
|
||||
public:
|
||||
bool external() const;
|
||||
class relationship relationship() const;
|
||||
std::string url() const;
|
||||
std::string target_range() const;
|
||||
void display(const std::string &value);
|
||||
std::string display() const;
|
||||
void tooltip(const std::string &value);
|
||||
std::string tooltip() const;
|
||||
|
||||
private:
|
||||
friend class cell;
|
||||
hyperlink(detail::hyperlink_impl *d);
|
||||
detail::hyperlink_impl *d_;
|
||||
};
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
@ -682,6 +682,31 @@ public:
|
|||
/// </summary>
|
||||
void clear_styles();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the default slicer style to the given value.
|
||||
/// </summary>
|
||||
void default_slicer_style(const std::string &value);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default slicer style.
|
||||
/// </summary>
|
||||
std::string default_slicer_style() const;
|
||||
|
||||
/// <summary>
|
||||
/// Enables knownFonts in stylesheet.
|
||||
/// </summary>
|
||||
void enable_known_fonts();
|
||||
|
||||
/// <summary>
|
||||
/// Disables knownFonts in stylesheet.
|
||||
/// </summary>
|
||||
void disable_known_fonts();
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if knownFonts are enabled in the stylesheet.
|
||||
/// </summary>
|
||||
bool known_fonts_enabled() const;
|
||||
|
||||
// Manifest
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -35,10 +35,15 @@ class XLNT_API row_properties
|
|||
{
|
||||
public:
|
||||
/// <summary>
|
||||
/// Optional height
|
||||
/// Row height
|
||||
/// </summary>
|
||||
optional<double> height;
|
||||
|
||||
/// <summary>
|
||||
/// Distance in pixels from the bottom of the cell to the baseline of the cell content
|
||||
/// </summary>
|
||||
optional<double> dy_descent;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the height is different from the default
|
||||
/// </summary>
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <xlnt/cell/cell_reference.hpp>
|
||||
#include <xlnt/cell/cell_type.hpp>
|
||||
#include <xlnt/cell/comment.hpp>
|
||||
#include <xlnt/cell/hyperlink.hpp>
|
||||
#include <xlnt/cell/rich_text.hpp>
|
||||
#include <xlnt/cell/index_types.hpp>
|
||||
#include <xlnt/cell/rich_text_run.hpp>
|
||||
|
|
|
@ -28,11 +28,13 @@
|
|||
|
||||
#include <detail/implementations/cell_impl.hpp>
|
||||
#include <detail/implementations/format_impl.hpp>
|
||||
#include <detail/implementations/hyperlink_impl.hpp>
|
||||
#include <detail/implementations/stylesheet.hpp>
|
||||
#include <detail/implementations/worksheet_impl.hpp>
|
||||
#include <xlnt/cell/cell.hpp>
|
||||
#include <xlnt/cell/cell_reference.hpp>
|
||||
#include <xlnt/cell/comment.hpp>
|
||||
#include <xlnt/cell/hyperlink.hpp>
|
||||
#include <xlnt/cell/rich_text.hpp>
|
||||
#include <xlnt/packaging/manifest.hpp>
|
||||
#include <xlnt/packaging/relationship.hpp>
|
||||
|
@ -196,7 +198,7 @@ cell::cell(detail::cell_impl *d)
|
|||
|
||||
bool cell::garbage_collectible() const
|
||||
{
|
||||
return !(has_value() || is_merged() || has_formula() || has_format());
|
||||
return !(has_value() || is_merged() || has_formula() || has_format() || has_hyperlink());
|
||||
}
|
||||
|
||||
void cell::value(std::nullptr_t)
|
||||
|
@ -360,9 +362,9 @@ cell &cell::operator=(const cell &rhs)
|
|||
return *this;
|
||||
}
|
||||
|
||||
std::string cell::hyperlink() const
|
||||
hyperlink cell::hyperlink() const
|
||||
{
|
||||
return d_->hyperlink_.get();
|
||||
return xlnt::hyperlink(&d_->hyperlink_.get());
|
||||
}
|
||||
|
||||
void cell::hyperlink(const std::string &hyperlink)
|
||||
|
@ -377,31 +379,50 @@ void cell::hyperlink(const std::string &hyperlink)
|
|||
auto &manifest = ws.workbook().manifest();
|
||||
bool existing = false;
|
||||
|
||||
d_->hyperlink_ = detail::hyperlink_impl();
|
||||
|
||||
// check for existing relationships
|
||||
for (const auto &rel : manifest.relationships(ws.path(), relationship_type::hyperlink))
|
||||
{
|
||||
if (rel.target().path().string() == hyperlink)
|
||||
{
|
||||
d_->hyperlink_.get().relationship = rel;
|
||||
existing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// register a new relationship
|
||||
if (!existing) {
|
||||
manifest.register_relationship(uri(ws.path().string()), relationship_type::hyperlink,
|
||||
uri(hyperlink), target_mode::external);
|
||||
auto rel_id = manifest.register_relationship(
|
||||
uri(ws.path().string()),
|
||||
relationship_type::hyperlink,
|
||||
uri(hyperlink),
|
||||
target_mode::external);
|
||||
// TODO: make manifest::register_relationship return the created relationship instead of rel id
|
||||
d_->hyperlink_.get().relationship = manifest.relationship(ws.path(), rel_id);
|
||||
}
|
||||
|
||||
d_->hyperlink_ = hyperlink;
|
||||
value(hyperlink);
|
||||
}
|
||||
|
||||
void cell::hyperlink(const std::string &url, const std::string &display)
|
||||
{
|
||||
hyperlink(url);
|
||||
d_->hyperlink_.get().display = display;
|
||||
value(display);
|
||||
}
|
||||
|
||||
void cell::hyperlink(xlnt::cell /*target*/)
|
||||
void cell::hyperlink(xlnt::cell target)
|
||||
{
|
||||
//todo: implement
|
||||
// TODO: should this computed value be a method on a cell?
|
||||
const auto cell_address = target.worksheet().title() + "!" + target.reference().to_string();
|
||||
|
||||
d_->hyperlink_ = detail::hyperlink_impl();
|
||||
d_->hyperlink_.get().relationship = xlnt::relationship("", relationship_type::hyperlink,
|
||||
uri(""), uri(cell_address), target_mode::internal);
|
||||
d_->hyperlink_.get().display = cell_address;
|
||||
value(cell_address);
|
||||
}
|
||||
|
||||
void cell::formula(const std::string &formula)
|
||||
|
@ -420,8 +441,6 @@ void cell::formula(const std::string &formula)
|
|||
d_->formula_ = formula;
|
||||
}
|
||||
|
||||
data_type(type::number);
|
||||
|
||||
worksheet().register_calc_chain_in_manifest();
|
||||
}
|
||||
|
||||
|
|
91
source/cell/hyperlink.cpp
Normal file
91
source/cell/hyperlink.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Copyright (c) 2014-2018 Thomas Fussell
|
||||
// Copyright (c) 2010-2015 openpyxl
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE
|
||||
//
|
||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
||||
// @author: see AUTHORS file
|
||||
|
||||
#include <detail/implementations/hyperlink_impl.hpp>
|
||||
#include <xlnt/cell/hyperlink.hpp>
|
||||
#include <xlnt/utils/exceptions.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
hyperlink::hyperlink(detail::hyperlink_impl *d) : d_(d)
|
||||
{
|
||||
}
|
||||
|
||||
relationship hyperlink::relationship() const
|
||||
{
|
||||
if (!external())
|
||||
{
|
||||
throw xlnt::exception("only external hyperlinks have associated relationships");
|
||||
}
|
||||
|
||||
return d_->relationship;
|
||||
}
|
||||
|
||||
std::string hyperlink::url() const
|
||||
{
|
||||
if (!external())
|
||||
{
|
||||
throw xlnt::exception("only external hyperlinks have associated urls");
|
||||
}
|
||||
|
||||
return d_->relationship.target().to_string();
|
||||
}
|
||||
|
||||
std::string hyperlink::target_range() const
|
||||
{
|
||||
if (external())
|
||||
{
|
||||
throw xlnt::exception("only internal hyperlinks have a target range");
|
||||
}
|
||||
|
||||
return d_->relationship.target().to_string();
|
||||
}
|
||||
|
||||
bool hyperlink::external() const
|
||||
{
|
||||
return d_->relationship.target_mode() == target_mode::external;
|
||||
}
|
||||
|
||||
void hyperlink::display(const std::string &value)
|
||||
{
|
||||
d_->display = value;
|
||||
}
|
||||
|
||||
std::string hyperlink::display() const
|
||||
{
|
||||
return d_->display;
|
||||
}
|
||||
|
||||
void hyperlink::tooltip(const std::string &value)
|
||||
{
|
||||
d_->tooltip = value;
|
||||
}
|
||||
|
||||
std::string hyperlink::tooltip() const
|
||||
{
|
||||
return d_->tooltip;
|
||||
}
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
@ -21,9 +21,10 @@
|
|||
//
|
||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
||||
// @author: see AUTHORS file
|
||||
|
||||
#include <xlnt/worksheet/worksheet.hpp>
|
||||
|
||||
#include "cell_impl.hpp"
|
||||
#include <detail/implementations/cell_impl.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
namespace detail {
|
||||
|
|
|
@ -29,7 +29,9 @@
|
|||
#include <xlnt/cell/comment.hpp>
|
||||
#include <xlnt/cell/rich_text.hpp>
|
||||
#include <xlnt/cell/index_types.hpp>
|
||||
#include <xlnt/packaging/relationship.hpp>
|
||||
#include <xlnt/utils/optional.hpp>
|
||||
#include <detail/implementations/hyperlink_impl.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
namespace detail {
|
||||
|
@ -54,7 +56,7 @@ struct cell_impl
|
|||
double value_numeric_;
|
||||
|
||||
optional<std::string> formula_;
|
||||
optional<std::string> hyperlink_;
|
||||
optional<hyperlink_impl> hyperlink_;
|
||||
optional<format_impl *> format_;
|
||||
optional<comment *> comment_;
|
||||
};
|
||||
|
|
41
source/detail/implementations/hyperlink_impl.hpp
Normal file
41
source/detail/implementations/hyperlink_impl.hpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
// 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 <string>
|
||||
|
||||
#include <xlnt/packaging/relationship.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
namespace detail {
|
||||
|
||||
struct hyperlink_impl
|
||||
{
|
||||
relationship relationship;
|
||||
std::string tooltip;
|
||||
std::string display;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace xlnt
|
|
@ -531,11 +531,13 @@ struct stylesheet
|
|||
workbook *parent;
|
||||
|
||||
bool garbage_collection_enabled = true;
|
||||
bool known_fonts_enabled = false;
|
||||
|
||||
std::list<conditional_format_impl> conditional_format_impls;
|
||||
std::list<format_impl> format_impls;
|
||||
std::unordered_map<std::string, style_impl> style_impls;
|
||||
std::vector<std::string> style_names;
|
||||
optional<std::string> default_slicer_style;
|
||||
|
||||
std::vector<alignment> alignments;
|
||||
std::vector<border> borders;
|
||||
|
|
|
@ -198,22 +198,28 @@ cell xlsx_consumer::read_cell()
|
|||
{
|
||||
expect_start_element(qn("spreadsheetml", "row"), xml::content::complex); // CT_Row
|
||||
auto row_index = static_cast<row_t>(std::stoul(parser().attribute("r")));
|
||||
auto &row_properties = ws.row_properties(row_index);
|
||||
|
||||
if (parser().attribute_present("ht"))
|
||||
{
|
||||
ws.row_properties(row_index).height = parser().attribute<double>("ht");
|
||||
row_properties.height = parser().attribute<double>("ht");
|
||||
}
|
||||
|
||||
if (parser().attribute_present("customHeight"))
|
||||
{
|
||||
ws.row_properties(row_index).custom_height = is_true(parser().attribute("customHeight"));
|
||||
row_properties.custom_height = is_true(parser().attribute("customHeight"));
|
||||
}
|
||||
|
||||
if (parser().attribute_present("hidden") && is_true(parser().attribute("hidden")))
|
||||
{
|
||||
ws.row_properties(row_index).hidden = true;
|
||||
row_properties.hidden = true;
|
||||
}
|
||||
skip_attributes({ qn("x14ac", "dyDescent") });
|
||||
|
||||
if (parser().attribute_present(qn("x14ac", "dyDescent")))
|
||||
{
|
||||
row_properties.dy_descent = parser().attribute<double>(qn("x14ac", "dyDescent"));
|
||||
}
|
||||
|
||||
skip_attributes({ "customFormat", "s", "customFont",
|
||||
"outlineLevel", "collapsed", "thickTop", "thickBot",
|
||||
"ph", "spans" });
|
||||
|
@ -226,7 +232,8 @@ cell xlsx_consumer::read_cell()
|
|||
|
||||
expect_start_element(qn("spreadsheetml", "c"), xml::content::complex);
|
||||
|
||||
auto cell = streaming_ ? xlnt::cell(streaming_cell_.get())
|
||||
auto cell = streaming_
|
||||
? xlnt::cell(streaming_cell_.get())
|
||||
: ws.cell(cell_reference(parser().attribute("r")));
|
||||
auto reference = cell_reference(parser().attribute("r"));
|
||||
cell.d_->parent_ = current_worksheet_;
|
||||
|
@ -238,7 +245,7 @@ cell xlsx_consumer::read_cell()
|
|||
|
||||
if (parser().attribute_present("s"))
|
||||
{
|
||||
cell.format(target_.format(std::stoull(parser().attribute("s"))));
|
||||
cell.format(target_.format(std::stoull(parser().attribute("s"))));
|
||||
}
|
||||
|
||||
auto has_value = false;
|
||||
|
@ -622,23 +629,28 @@ void xlsx_consumer::read_worksheet_sheetdata()
|
|||
{
|
||||
expect_start_element(qn("spreadsheetml", "row"), xml::content::complex); // CT_Row
|
||||
auto row_index = parser().attribute<row_t>("r");
|
||||
auto &row_properties = ws.row_properties(row_index);
|
||||
|
||||
if (parser().attribute_present("ht"))
|
||||
{
|
||||
ws.row_properties(row_index).height = parser().attribute<double>("ht");
|
||||
row_properties.height = parser().attribute<double>("ht");
|
||||
}
|
||||
|
||||
if (parser().attribute_present("customHeight"))
|
||||
{
|
||||
ws.row_properties(row_index).custom_height = is_true(parser().attribute("customHeight"));
|
||||
row_properties.custom_height = is_true(parser().attribute("customHeight"));
|
||||
}
|
||||
|
||||
if (parser().attribute_present("hidden") && is_true(parser().attribute("hidden")))
|
||||
{
|
||||
ws.row_properties(row_index).hidden = true;
|
||||
row_properties.hidden = true;
|
||||
}
|
||||
|
||||
if (parser().attribute_present(qn("x14ac", "dyDescent")))
|
||||
{
|
||||
row_properties.dy_descent = parser().attribute<double>(qn("x14ac", "dyDescent"));
|
||||
}
|
||||
|
||||
skip_attributes({ qn("x14ac", "dyDescent") });
|
||||
skip_attributes({ "customFormat", "s", "customFont",
|
||||
"outlineLevel", "collapsed", "thickTop", "thickBot",
|
||||
"ph", "spans" });
|
||||
|
@ -2268,7 +2280,25 @@ void xlsx_consumer::read_stylesheet()
|
|||
}
|
||||
else if (current_style_element == qn("spreadsheetml", "extLst"))
|
||||
{
|
||||
skip_remaining_content(current_style_element);
|
||||
while (in_element(qn("spreadsheetml", "extLst")))
|
||||
{
|
||||
expect_start_element(qn("spreadsheetml", "ext"), xml::content::complex);
|
||||
|
||||
const auto uri = parser().attribute("uri");
|
||||
|
||||
if (uri == "{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}") // slicerStyles
|
||||
{
|
||||
expect_start_element(qn("x14", "slicerStyles"), xml::content::simple);
|
||||
stylesheet.default_slicer_style = parser().attribute("defaultSlicerStyle");
|
||||
expect_end_element(qn("x14", "slicerStyles"));
|
||||
}
|
||||
else
|
||||
{
|
||||
skip_remaining_content(qn("spreadsheetml", "ext"));
|
||||
}
|
||||
|
||||
expect_end_element(qn("spreadsheetml", "ext"));
|
||||
}
|
||||
}
|
||||
else if (current_style_element == qn("spreadsheetml", "colors")) // CT_Colors 0-1
|
||||
{
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <detail/serialization/xlsx_producer.hpp>
|
||||
#include <detail/serialization/zstream.hpp>
|
||||
#include <xlnt/cell/cell.hpp>
|
||||
#include <xlnt/cell/hyperlink.hpp>
|
||||
#include <xlnt/packaging/manifest.hpp>
|
||||
#include <xlnt/utils/path.hpp>
|
||||
#include <xlnt/utils/scoped_enum_hash.hpp>
|
||||
|
@ -1113,13 +1114,33 @@ void xlsx_producer::write_border(const border ¤t_border)
|
|||
|
||||
void xlsx_producer::write_styles(const relationship & /*rel*/)
|
||||
{
|
||||
static const auto &xmlns = constants::ns("spreadsheetml");
|
||||
static const auto &xmlns = constants::ns("spreadsheetml");
|
||||
static const auto &xmlns_mc = constants::ns("mc");
|
||||
static const auto &xmlns_x14 = constants::ns("x14");
|
||||
static const auto &xmlns_x14ac = constants::ns("x14ac");
|
||||
|
||||
write_start_element(xmlns, "styleSheet");
|
||||
write_namespace(xmlns, "");
|
||||
|
||||
const auto &stylesheet = source_.impl().stylesheet_.get();
|
||||
|
||||
auto using_namespace = [&stylesheet](const std::string &ns)
|
||||
{
|
||||
if (ns == "x14ac")
|
||||
{
|
||||
return stylesheet.known_fonts_enabled;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
if (using_namespace("x14ac"))
|
||||
{
|
||||
write_namespace(xmlns_mc, "mc");
|
||||
write_namespace(xmlns_x14ac, "x14ac");
|
||||
write_attribute(xml::qname(xmlns_mc, "Ignorable"), "x14ac");
|
||||
}
|
||||
|
||||
// Number Formats
|
||||
|
||||
if (!stylesheet.number_formats.empty())
|
||||
|
@ -1156,6 +1177,31 @@ void xlsx_producer::write_styles(const relationship & /*rel*/)
|
|||
write_start_element(xmlns, "fonts");
|
||||
write_attribute("count", fonts.size());
|
||||
|
||||
if (stylesheet.known_fonts_enabled)
|
||||
{
|
||||
auto is_known_font = [](const font &f)
|
||||
{
|
||||
const auto &known_fonts = *new std::vector<font>
|
||||
{
|
||||
font().name("Calibri").family(2).size(12).color(theme_color(1)).scheme("minor")
|
||||
};
|
||||
|
||||
return std::find(known_fonts.begin(), known_fonts.end(), f) != known_fonts.end();
|
||||
};
|
||||
|
||||
std::size_t num_known_fonts = 0;
|
||||
|
||||
for (const auto ¤t_font : fonts)
|
||||
{
|
||||
if (is_known_font(current_font))
|
||||
{
|
||||
num_known_fonts += 1;
|
||||
}
|
||||
}
|
||||
|
||||
write_attribute(xml::qname(xmlns_x14ac, "knownFonts"), num_known_fonts);
|
||||
}
|
||||
|
||||
for (const auto ¤t_font : fonts)
|
||||
{
|
||||
write_font(current_font);
|
||||
|
@ -1514,6 +1560,26 @@ void xlsx_producer::write_styles(const relationship & /*rel*/)
|
|||
write_end_element(xmlns, "colors");
|
||||
}
|
||||
|
||||
auto using_extensions = stylesheet.default_slicer_style.is_set();
|
||||
|
||||
if (using_extensions)
|
||||
{
|
||||
write_start_element(xmlns, "extLst");
|
||||
|
||||
if (stylesheet.default_slicer_style.is_set())
|
||||
{
|
||||
write_start_element(xmlns, "ext");
|
||||
write_namespace(xmlns_x14, "x14");
|
||||
write_attribute("uri", "{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}"); // slicerStyles URI
|
||||
write_start_element(xmlns_x14, "slicerStyles");
|
||||
write_attribute("defaultSlicerStyle", stylesheet.default_slicer_style.get());
|
||||
write_end_element(xmlns_x14, "slicerStyles");
|
||||
write_end_element(xmlns, "ext");
|
||||
}
|
||||
|
||||
write_end_element(xmlns, "extLst");
|
||||
}
|
||||
|
||||
write_end_element(xmlns, "styleSheet");
|
||||
}
|
||||
|
||||
|
@ -1990,6 +2056,7 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
{
|
||||
static const auto &xmlns = constants::ns("spreadsheetml");
|
||||
static const auto &xmlns_r = constants::ns("r");
|
||||
static const auto &xmlns_mc = constants::ns("mc");
|
||||
static const auto &xmlns_x14ac = constants::ns("x14ac");
|
||||
|
||||
auto worksheet_part = rel.source().path().parent().append(rel.target().path());
|
||||
|
@ -2010,7 +2077,18 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
{
|
||||
if (ns == "x14ac")
|
||||
{
|
||||
return ws.format_properties().dy_descent.is_set();
|
||||
if (ws.format_properties().dy_descent.is_set())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for (auto row = ws.lowest_row(); row <= ws.highest_row(); ++row)
|
||||
{
|
||||
if (ws.has_row_properties(row) && ws.row_properties(row).dy_descent.is_set())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -2018,7 +2096,9 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
|
||||
if (using_namespace("x14ac"))
|
||||
{
|
||||
write_namespace(xmlns_mc, "mc");
|
||||
write_namespace(xmlns_x14ac, "x14ac");
|
||||
write_attribute(xml::qname(xmlns_mc, "Ignorable"), "x14ac");
|
||||
}
|
||||
|
||||
if (ws.has_page_setup())
|
||||
|
@ -2056,8 +2136,8 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
|
||||
if (view.type() != sheet_view_type::normal)
|
||||
{
|
||||
write_attribute(
|
||||
"view", view.type() == sheet_view_type::page_break_preview ? "pageBreakPreview" : "pageLayout");
|
||||
write_attribute("view", view.type() == sheet_view_type::page_break_preview
|
||||
? "pageBreakPreview" : "pageLayout");
|
||||
}
|
||||
|
||||
if (view.has_pane())
|
||||
|
@ -2097,7 +2177,10 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
|
||||
if (current_selection.has_sqref())
|
||||
{
|
||||
write_attribute("sqref", current_selection.sqref().to_string());
|
||||
const auto sqref = current_selection.sqref();
|
||||
write_attribute("sqref", sqref.is_single_cell()
|
||||
? sqref.top_left().to_string()
|
||||
: sqref.to_string());
|
||||
}
|
||||
|
||||
if (current_selection.pane() != pane_corner::top_left)
|
||||
|
@ -2183,16 +2266,7 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
write_end_element(xmlns, "cols");
|
||||
}
|
||||
|
||||
const auto hyperlink_rels = source_.manifest()
|
||||
.relationships(worksheet_part, relationship_type::hyperlink);
|
||||
std::unordered_map<std::string, std::string> reverse_hyperlink_references;
|
||||
|
||||
for (auto hyperlink_rel : hyperlink_rels)
|
||||
{
|
||||
reverse_hyperlink_references[hyperlink_rel.target().path().string()] = rel.id();
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> hyperlink_references;
|
||||
std::vector<std::pair<std::string, hyperlink>> hyperlinks;
|
||||
std::vector<cell_reference> cells_with_comments;
|
||||
|
||||
write_start_element(xmlns, "sheetData");
|
||||
|
@ -2241,6 +2315,11 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
write_attribute("customHeight", write_bool(true));
|
||||
}
|
||||
|
||||
if (props.dy_descent.is_set())
|
||||
{
|
||||
write_attribute(xml::qname(xmlns_x14ac, "dyDescent"), props.dy_descent.get());
|
||||
}
|
||||
|
||||
if (props.height.is_set())
|
||||
{
|
||||
auto height = props.height.get();
|
||||
|
@ -2280,7 +2359,7 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
|
||||
if (cell.has_hyperlink())
|
||||
{
|
||||
hyperlink_references[cell.reference().to_string()] = reverse_hyperlink_references[cell.hyperlink()];
|
||||
hyperlinks.push_back(std::make_pair(cell.reference().to_string(), cell.hyperlink()));
|
||||
}
|
||||
|
||||
write_start_element(xmlns, "c");
|
||||
|
@ -2464,15 +2543,24 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
}
|
||||
}
|
||||
|
||||
if (!hyperlink_rels.empty())
|
||||
if (!hyperlinks.empty())
|
||||
{
|
||||
write_start_element(xmlns, "hyperlinks");
|
||||
|
||||
for (const auto &hyperlink : hyperlink_references)
|
||||
for (const auto &hyperlink : hyperlinks)
|
||||
{
|
||||
write_start_element(xmlns, "hyperlink");
|
||||
write_attribute("ref", hyperlink.first);
|
||||
write_attribute(xml::qname(xmlns_r, "id"), hyperlink.second);
|
||||
if (hyperlink.second.external())
|
||||
{
|
||||
write_attribute(xml::qname(xmlns_r, "id"),
|
||||
hyperlink.second.relationship().id());
|
||||
}
|
||||
else
|
||||
{
|
||||
write_attribute("location", hyperlink.second.target_range());
|
||||
write_attribute("display", hyperlink.second.display());
|
||||
}
|
||||
write_end_element(xmlns, "hyperlink");
|
||||
}
|
||||
|
||||
|
|
|
@ -1214,6 +1214,31 @@ void workbook::clear_styles()
|
|||
apply_to_cells([](cell c) { c.clear_style(); });
|
||||
}
|
||||
|
||||
void workbook::default_slicer_style(const std::string &value)
|
||||
{
|
||||
d_->stylesheet_.get().default_slicer_style = value;
|
||||
}
|
||||
|
||||
std::string workbook::default_slicer_style() const
|
||||
{
|
||||
return d_->stylesheet_.get().default_slicer_style.get();
|
||||
}
|
||||
|
||||
void workbook::enable_known_fonts()
|
||||
{
|
||||
d_->stylesheet_.get().known_fonts_enabled = true;
|
||||
}
|
||||
|
||||
void workbook::disable_known_fonts()
|
||||
{
|
||||
d_->stylesheet_.get().known_fonts_enabled = false;
|
||||
}
|
||||
|
||||
bool workbook::known_fonts_enabled() const
|
||||
{
|
||||
return d_->stylesheet_.get().known_fonts_enabled;
|
||||
}
|
||||
|
||||
void workbook::clear_formats()
|
||||
{
|
||||
apply_to_cells([](cell c) { c.clear_format(); });
|
||||
|
|
|
@ -1085,7 +1085,7 @@ double worksheet::row_height(row_t row) const
|
|||
{
|
||||
static const auto DefaultRowHeight = 15.0;
|
||||
|
||||
if (has_row_properties(row))
|
||||
if (has_row_properties(row) && row_properties(row).height.is_set())
|
||||
{
|
||||
return row_properties(row).height.get();
|
||||
}
|
||||
|
|
|
@ -177,7 +177,7 @@ private:
|
|||
auto cell = ws.cell(xlnt::cell_reference(1, 1));
|
||||
|
||||
cell.value("=42", true);
|
||||
xlnt_assert(cell.data_type() == xlnt::cell::type::number);
|
||||
//xlnt_assert(cell.data_type() == xlnt::cell::type::number);
|
||||
xlnt_assert(cell.has_formula());
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@ private:
|
|||
auto cell = ws.cell(xlnt::cell_reference(1, 1));
|
||||
|
||||
cell.value("=if(A1<4;-1;1)", true);
|
||||
xlnt_assert(cell.data_type() == xlnt::cell::type::number);
|
||||
//xlnt_assert(cell.data_type() == xlnt::cell::type::number);
|
||||
xlnt_assert(cell.has_formula());
|
||||
}
|
||||
|
||||
|
@ -659,7 +659,7 @@ private:
|
|||
xlnt_assert_throws(cell.hyperlink(""), xlnt::invalid_parameter);
|
||||
cell.hyperlink("http://example.com");
|
||||
xlnt_assert(cell.has_hyperlink());
|
||||
xlnt_assert_equals(cell.hyperlink(), "http://example.com");
|
||||
xlnt_assert_equals(cell.hyperlink().relationship().target().to_string(), "http://example.com");
|
||||
}
|
||||
|
||||
void test_comment()
|
||||
|
|
|
@ -200,11 +200,20 @@ public:
|
|||
.size(10)
|
||||
.color(xlnt::indexed_color(81))
|
||||
.name("Calibri");
|
||||
auto hyperlink_font = xlnt::font()
|
||||
.size(12)
|
||||
.color(xlnt::theme_color(10))
|
||||
.name("Calibri")
|
||||
.underline(xlnt::font::underline_style::single);
|
||||
|
||||
sheet1.cell("A4").hyperlink("https://microsoft.com/", "hyperlink1");
|
||||
sheet1.cell("A4").font(hyperlink_font);
|
||||
sheet1.cell("A5").hyperlink("https://google.com/");
|
||||
sheet1.cell("A5").font(hyperlink_font);
|
||||
sheet1.cell("A6").hyperlink(sheet1.cell("A1"));
|
||||
sheet1.cell("A6").font(hyperlink_font);
|
||||
sheet1.cell("A7").hyperlink("mailto:invalid@example.com?subject=important");
|
||||
sheet1.cell("A7").font(hyperlink_font);
|
||||
|
||||
sheet1.cell("A1").value("Sheet1!A1");
|
||||
sheet1.cell("A1").comment("Sheet1 comment", comment_font, "Microsoft Office User");
|
||||
|
@ -216,13 +225,19 @@ public:
|
|||
sheet1.cell("C2").value("a");
|
||||
sheet1.cell("C3").value("b");
|
||||
|
||||
for (auto i = 1; i <= 7; ++i)
|
||||
{
|
||||
sheet1.row_properties(i).dy_descent = 0.2;
|
||||
}
|
||||
|
||||
auto sheet2 = wb.create_sheet();
|
||||
sheet2.format_properties(format_properties);
|
||||
|
||||
sheet2.cell("A4").hyperlink("https://apple.com/", "hyperlink2");
|
||||
sheet2.cell("A4").font(hyperlink_font);
|
||||
|
||||
sheet2.cell("A1").value("Sheet2!A1");
|
||||
sheet2.cell("A2").comment("Sheet2 comment", comment_font, "Microsoft Office User");
|
||||
sheet2.cell("A1").comment("Sheet2 comment", comment_font, "Microsoft Office User");
|
||||
|
||||
sheet2.cell("A2").value("Sheet2!A2");
|
||||
sheet2.cell("A2").comment("Sheet2 comment2", comment_font, "Microsoft Office User");
|
||||
|
@ -337,16 +352,16 @@ public:
|
|||
xlnt_assert_equals(ws1.title(), "Sheet1");
|
||||
xlnt_assert(ws1.cell("A4").has_hyperlink());
|
||||
xlnt_assert_equals(ws1.cell("A4").value<std::string>(), "hyperlink1");
|
||||
xlnt_assert_equals(ws1.cell("A4").hyperlink(), "https://microsoft.com/");
|
||||
xlnt_assert_equals(ws1.cell("A4").hyperlink().url(), "https://microsoft.com/");
|
||||
xlnt_assert(ws1.cell("A5").has_hyperlink());
|
||||
xlnt_assert_equals(ws1.cell("A5").value<std::string>(), "https://google.com/");
|
||||
xlnt_assert_equals(ws1.cell("A5").hyperlink(), "https://google.com/");
|
||||
//xlnt_assert(ws1.cell("A6").has_hyperlink());
|
||||
xlnt_assert_equals(ws1.cell("A5").hyperlink().url(), "https://google.com/");
|
||||
xlnt_assert(ws1.cell("A6").has_hyperlink());
|
||||
xlnt_assert_equals(ws1.cell("A6").value<std::string>(), "Sheet1!A1");
|
||||
//xlnt_assert_equals(ws1.cell("A6").hyperlink(), "Sheet1!A1");
|
||||
xlnt_assert_equals(ws1.cell("A6").hyperlink().target_range(), "Sheet1!A1");
|
||||
xlnt_assert(ws1.cell("A7").has_hyperlink());
|
||||
xlnt_assert_equals(ws1.cell("A7").value<std::string>(), "mailto:invalid@example.com?subject=important");
|
||||
xlnt_assert_equals(ws1.cell("A7").hyperlink(), "mailto:invalid@example.com?subject=important");
|
||||
xlnt_assert_equals(ws1.cell("A7").hyperlink().url(), "mailto:invalid@example.com?subject=important");
|
||||
|
||||
}
|
||||
|
||||
|
@ -472,8 +487,10 @@ public:
|
|||
|
||||
ws.column_properties("E").width = 15.949776785714286;
|
||||
ws.column_properties("E").custom_width = true;
|
||||
|
||||
wb.save("temp.xlsx");
|
||||
|
||||
wb.default_slicer_style("SlicerStyleLight1");
|
||||
wb.enable_known_fonts();
|
||||
|
||||
xlnt_assert(workbook_matches_file(wb, path_helper::test_file("13_custom_heights_widths.xlsx")));
|
||||
}
|
||||
|
||||
|
|
|
@ -225,11 +225,11 @@ public:
|
|||
xlnt::workbook wb;
|
||||
auto ws = wb.active_sheet();
|
||||
ws.cell("A1").hyperlink("http://test.com");
|
||||
xlnt_assert_equals(ws.cell("A1").hyperlink(), "http://test.com");
|
||||
xlnt_assert_equals(ws.cell("A1").hyperlink().url(), "http://test.com");
|
||||
xlnt_assert_equals(ws.cell("A1").value<std::string>(), "");
|
||||
ws.cell("A1").value("test");
|
||||
xlnt_assert_equals("test", ws.cell("A1").value<std::string>());
|
||||
xlnt_assert_equals(ws.cell("A1").hyperlink(), "http://test.com");
|
||||
xlnt_assert_equals(ws.cell("A1").hyperlink().url(), "http://test.com");
|
||||
}
|
||||
|
||||
void test_rows()
|
||||
|
|
Loading…
Reference in New Issue
Block a user