diff --git a/include/xlnt/cell/cell.hpp b/include/xlnt/cell/cell.hpp
index 7ab1dc2a..74a5b6cb 100644
--- a/include/xlnt/cell/cell.hpp
+++ b/include/xlnt/cell/cell.hpp
@@ -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
///
- /// Returns the URL of this cell's hyperlink.
+ /// Returns the relationship of this cell's hyperlink.
///
- std::string hyperlink() const;
+ class hyperlink hyperlink() const;
///
/// Adds a hyperlink to this cell pointing to the URL of the given value.
@@ -271,6 +273,11 @@ public:
///
void hyperlink(xlnt::cell target);
+ ///
+ /// Adds an internal hyperlink to this cell pointing to the given range.
+ ///
+ void hyperlink(xlnt::range target);
+
///
/// Returns true if this cell has a hyperlink set.
///
diff --git a/include/xlnt/cell/hyperlink.hpp b/include/xlnt/cell/hyperlink.hpp
new file mode 100644
index 00000000..8034098b
--- /dev/null
+++ b/include/xlnt/cell/hyperlink.hpp
@@ -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
+#include
+
+namespace xlnt {
+
+namespace detail {
+struct hyperlink_impl;
+}
+
+class cell;
+class range;
+class relationship;
+
+///
+/// Describes a hyperlink pointing from a cell to another cell or a URL.
+///
+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
+
diff --git a/include/xlnt/workbook/workbook.hpp b/include/xlnt/workbook/workbook.hpp
index 604209ab..2ab82728 100644
--- a/include/xlnt/workbook/workbook.hpp
+++ b/include/xlnt/workbook/workbook.hpp
@@ -682,6 +682,31 @@ public:
///
void clear_styles();
+ ///
+ /// Sets the default slicer style to the given value.
+ ///
+ void default_slicer_style(const std::string &value);
+
+ ///
+ /// Returns the default slicer style.
+ ///
+ std::string default_slicer_style() const;
+
+ ///
+ /// Enables knownFonts in stylesheet.
+ ///
+ void enable_known_fonts();
+
+ ///
+ /// Disables knownFonts in stylesheet.
+ ///
+ void disable_known_fonts();
+
+ ///
+ /// Returns true if knownFonts are enabled in the stylesheet.
+ ///
+ bool known_fonts_enabled() const;
+
// Manifest
///
diff --git a/include/xlnt/worksheet/row_properties.hpp b/include/xlnt/worksheet/row_properties.hpp
index c200ad39..4fcb6fa5 100644
--- a/include/xlnt/worksheet/row_properties.hpp
+++ b/include/xlnt/worksheet/row_properties.hpp
@@ -35,10 +35,15 @@ class XLNT_API row_properties
{
public:
///
- /// Optional height
+ /// Row height
///
optional height;
+ ///
+ /// Distance in pixels from the bottom of the cell to the baseline of the cell content
+ ///
+ optional dy_descent;
+
///
/// Whether or not the height is different from the default
///
diff --git a/include/xlnt/xlnt.hpp b/include/xlnt/xlnt.hpp
index 1b53d036..01fe4981 100644
--- a/include/xlnt/xlnt.hpp
+++ b/include/xlnt/xlnt.hpp
@@ -30,6 +30,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/source/cell/cell.cpp b/source/cell/cell.cpp
index 14f5b9a6..13761c0d 100644
--- a/source/cell/cell.cpp
+++ b/source/cell/cell.cpp
@@ -28,11 +28,13 @@
#include
#include
+#include
#include
#include
#include
#include
#include
+#include
#include
#include
#include
@@ -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();
}
diff --git a/source/cell/hyperlink.cpp b/source/cell/hyperlink.cpp
new file mode 100644
index 00000000..8d28d84e
--- /dev/null
+++ b/source/cell/hyperlink.cpp
@@ -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
+#include
+#include
+
+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
+
diff --git a/source/detail/implementations/cell_impl.cpp b/source/detail/implementations/cell_impl.cpp
index 49b20a11..8be6324b 100644
--- a/source/detail/implementations/cell_impl.cpp
+++ b/source/detail/implementations/cell_impl.cpp
@@ -21,9 +21,10 @@
//
// @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file
+
#include
-#include "cell_impl.hpp"
+#include
namespace xlnt {
namespace detail {
diff --git a/source/detail/implementations/cell_impl.hpp b/source/detail/implementations/cell_impl.hpp
index 9cd4fd26..4553d133 100644
--- a/source/detail/implementations/cell_impl.hpp
+++ b/source/detail/implementations/cell_impl.hpp
@@ -29,7 +29,9 @@
#include
#include
#include
+#include
#include
+#include
namespace xlnt {
namespace detail {
@@ -54,7 +56,7 @@ struct cell_impl
double value_numeric_;
optional formula_;
- optional hyperlink_;
+ optional hyperlink_;
optional format_;
optional comment_;
};
diff --git a/source/detail/implementations/hyperlink_impl.hpp b/source/detail/implementations/hyperlink_impl.hpp
new file mode 100644
index 00000000..a71fa1e3
--- /dev/null
+++ b/source/detail/implementations/hyperlink_impl.hpp
@@ -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
+
+#include
+
+namespace xlnt {
+namespace detail {
+
+struct hyperlink_impl
+{
+ relationship relationship;
+ std::string tooltip;
+ std::string display;
+};
+
+} // namespace detail
+} // namespace xlnt
diff --git a/source/detail/implementations/stylesheet.hpp b/source/detail/implementations/stylesheet.hpp
index 9f1d529a..f0b2a48f 100644
--- a/source/detail/implementations/stylesheet.hpp
+++ b/source/detail/implementations/stylesheet.hpp
@@ -531,11 +531,13 @@ struct stylesheet
workbook *parent;
bool garbage_collection_enabled = true;
+ bool known_fonts_enabled = false;
std::list conditional_format_impls;
std::list format_impls;
std::unordered_map style_impls;
std::vector style_names;
+ optional default_slicer_style;
std::vector alignments;
std::vector borders;
diff --git a/source/detail/serialization/xlsx_consumer.cpp b/source/detail/serialization/xlsx_consumer.cpp
index 4086d68f..6288d0de 100644
--- a/source/detail/serialization/xlsx_consumer.cpp
+++ b/source/detail/serialization/xlsx_consumer.cpp
@@ -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(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("ht");
+ row_properties.height = parser().attribute("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(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("r");
+ auto &row_properties = ws.row_properties(row_index);
if (parser().attribute_present("ht"))
{
- ws.row_properties(row_index).height = parser().attribute("ht");
+ row_properties.height = parser().attribute("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(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
{
diff --git a/source/detail/serialization/xlsx_producer.cpp b/source/detail/serialization/xlsx_producer.cpp
index f5611f88..e3c3a242 100644
--- a/source/detail/serialization/xlsx_producer.cpp
+++ b/source/detail/serialization/xlsx_producer.cpp
@@ -34,6 +34,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -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().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 reverse_hyperlink_references;
-
- for (auto hyperlink_rel : hyperlink_rels)
- {
- reverse_hyperlink_references[hyperlink_rel.target().path().string()] = rel.id();
- }
-
- std::unordered_map hyperlink_references;
+ std::vector> hyperlinks;
std::vector 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");
}
diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp
index ac70b1cc..5773d74c 100644
--- a/source/workbook/workbook.cpp
+++ b/source/workbook/workbook.cpp
@@ -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(); });
diff --git a/source/worksheet/worksheet.cpp b/source/worksheet/worksheet.cpp
index f240e895..dea1125b 100644
--- a/source/worksheet/worksheet.cpp
+++ b/source/worksheet/worksheet.cpp
@@ -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();
}
diff --git a/tests/cell/cell_test_suite.hpp b/tests/cell/cell_test_suite.hpp
index 2272c422..04294818 100644
--- a/tests/cell/cell_test_suite.hpp
+++ b/tests/cell/cell_test_suite.hpp
@@ -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()
diff --git a/tests/workbook/serialization_test_suite.hpp b/tests/workbook/serialization_test_suite.hpp
index a4ae2fd2..c2dd48f8 100644
--- a/tests/workbook/serialization_test_suite.hpp
+++ b/tests/workbook/serialization_test_suite.hpp
@@ -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(), "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(), "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(), "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(), "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")));
}
diff --git a/tests/worksheet/worksheet_test_suite.hpp b/tests/worksheet/worksheet_test_suite.hpp
index 5acd1e23..d3ddb649 100644
--- a/tests/worksheet/worksheet_test_suite.hpp
+++ b/tests/worksheet/worksheet_test_suite.hpp
@@ -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(), "");
ws.cell("A1").value("test");
xlnt_assert_equals("test", ws.cell("A1").value());
- xlnt_assert_equals(ws.cell("A1").hyperlink(), "http://test.com");
+ xlnt_assert_equals(ws.cell("A1").hyperlink().url(), "http://test.com");
}
void test_rows()