improve hyperlinks and style round tripping

This commit is contained in:
Thomas Fussell 2018-03-21 09:03:37 -04:00
parent 410e73d594
commit 617f7a2525
11 changed files with 379 additions and 223 deletions

View File

@ -68,12 +68,22 @@ public:
bool bold() const;
/// <summary>
/// Sets the bold state of the font to bold and returns a reference to the font.
/// Sets the vertical alignment of the font to subscript and returns a reference to the font.
/// </summary>
font &superscript(bool superscript);
font &subscript(bool value);
/// <summary>
/// Returns true if this font has a superscript applied.
/// Returns true if this font has a vertical alignment of subscript.
/// </summary>
bool subscript() const;
/// <summary>
/// Sets the vertical alignment of the font to superscript and returns a reference to the font.
/// </summary>
font &superscript(bool value);
/// <summary>
/// Returns true if this font has a vertical alignment of superscript.
/// </summary>
bool superscript() const;

View File

@ -367,10 +367,14 @@ hyperlink cell::hyperlink() const
return xlnt::hyperlink(&d_->hyperlink_.get());
}
void cell::hyperlink(const std::string &hyperlink)
void cell::hyperlink(const std::string &url)
{
if (hyperlink.length() == 0
|| std::find(hyperlink.begin(), hyperlink.end(), ':') == hyperlink.end())
hyperlink(url, url);
}
void cell::hyperlink(const std::string &url, const std::string &display)
{
if (url.empty() || std::find(url.begin(), url.end(), ':') == url.end() || display.empty())
{
throw invalid_parameter();
}
@ -384,7 +388,7 @@ void cell::hyperlink(const std::string &hyperlink)
// check for existing relationships
for (const auto &rel : manifest.relationships(ws.path(), relationship_type::hyperlink))
{
if (rel.target().path().string() == hyperlink)
if (rel.target().path().string() == url)
{
d_->hyperlink_.get().relationship = rel;
existing = true;
@ -397,20 +401,14 @@ void cell::hyperlink(const std::string &hyperlink)
auto rel_id = manifest.register_relationship(
uri(ws.path().string()),
relationship_type::hyperlink,
uri(hyperlink),
uri(url),
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);
}
value(hyperlink);
}
void cell::hyperlink(const std::string &url, const std::string &display)
{
hyperlink(url);
d_->hyperlink_.get().display = display;
value(display);
d_->hyperlink_.get().display = display;
}
void cell::hyperlink(xlnt::cell target)

View File

@ -401,23 +401,21 @@ struct stylesheet
{
auto iter = format_impls.begin();
bool added = false;
pattern.references = 0;
auto id = find_or_add(format_impls, pattern, &added);
std::advance(iter, static_cast<std::list<format_impl>::difference_type>(id));
auto &result = *iter;
if (added)
{
result.references = 0;
}
result.parent = this;
result.id = id;
result.references++;
if (id != pattern.id)
{
pattern.references -= pattern.references > 0 ? 1 : 0;
iter = format_impls.begin();
std::advance(iter, static_cast<std::list<format_impl>::difference_type>(pattern.id));
iter->references -= iter->references > 0 ? 1 : 0;
garbage_collect();
}

View File

@ -35,6 +35,7 @@
#include <detail/serialization/zstream.hpp>
#include <xlnt/cell/cell.hpp>
#include <xlnt/cell/comment.hpp>
#include <xlnt/cell/hyperlink.hpp>
#include <xlnt/packaging/manifest.hpp>
#include <xlnt/utils/optional.hpp>
#include <xlnt/utils/path.hpp>
@ -273,8 +274,8 @@ cell xlsx_consumer::read_cell()
has_shared_formula = parser().attribute("t") == "shared";
}
skip_attributes(
{ "aca", "ref", "dt2D", "dtr", "del1", "del2", "r1", "r2", "ca", "si", "bx" });
skip_attributes({ "aca", "ref", "dt2D", "dtr", "del1",
"del2", "r1", "r2", "ca", "si", "bx" });
formula_value_string = read_text();
}
@ -441,14 +442,21 @@ std::string xlsx_consumer::read_worksheet_begin(const std::string &rel_id)
new_view.default_grid_color(is_true(parser().attribute("defaultGridColor")));
}
if (parser().attribute_present("view") && parser().attribute("view") != "normal")
if (parser().attribute_present("view")
&& parser().attribute("view") != "normal")
{
new_view.type(parser().attribute("view") == "pageBreakPreview"
? sheet_view_type::page_break_preview
: sheet_view_type::page_layout);
}
skip_attributes({ "windowProtection", "showFormulas", "showRowColHeaders", "showZeros", "rightToLeft", "tabSelected", "showRuler", "showOutlineSymbols", "showWhiteSpace",
if (parser().attribute_present("tabSelected")
&& is_true(parser().attribute("tabSelected")))
{
target_.d_->view_.get().active_tab = ws.id() - 1;
}
skip_attributes({ "windowProtection", "showFormulas", "showRowColHeaders", "showZeros", "rightToLeft", "showRuler", "showOutlineSymbols", "showWhiteSpace",
"view", "topLeftCell", "colorId", "zoomScale", "zoomScaleNormal", "zoomScaleSheetLayoutView",
"zoomScalePageLayoutView" });
@ -841,6 +849,7 @@ worksheet xlsx_consumer::read_worksheet_end(const std::string &rel_id)
{
while (in_element(qn("spreadsheetml", "hyperlinks")))
{
// CT_Hyperlink
expect_start_element(qn("spreadsheetml", "hyperlink"), xml::content::simple);
auto cell = ws.cell(parser().attribute("ref"));
@ -853,11 +862,39 @@ worksheet xlsx_consumer::read_worksheet_end(const std::string &rel_id)
if (hyperlink_rel != hyperlinks.end())
{
cell.hyperlink(hyperlink_rel->target().path().string());
auto url = hyperlink_rel->target().path().string();
if (cell.has_value())
{
cell.hyperlink(url, cell.value<std::string>());
}
else
{
cell.hyperlink(url);
}
}
}
else if (parser().attribute_present("location"))
{
auto hyperlink = hyperlink_impl();
auto location = parser().attribute("location");
hyperlink.relationship = relationship("", relationship_type::hyperlink,
uri(""), uri(location), target_mode::internal);
if (parser().attribute_present("display"))
{
hyperlink.display = parser().attribute("display");
}
if (parser().attribute_present("tooltip"))
{
hyperlink.tooltip = parser().attribute("tooltip");
}
cell.d_->hyperlink_ = hyperlink;
}
skip_attributes({ "location", "tooltip", "display" });
expect_end_element(qn("spreadsheetml", "hyperlink"));
}
}
@ -1500,8 +1537,8 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_
while (in_element(qn("workbook", "bookViews")))
{
expect_start_element(qn("workbook", "workbookView"), xml::content::simple);
skip_attributes({"activeTab", "firstSheet",
"showHorizontalScroll", "showSheetTabs", "showVerticalScroll"});
skip_attributes({"firstSheet", "showHorizontalScroll",
"showSheetTabs", "showVerticalScroll"});
workbook_view view;
@ -1530,6 +1567,11 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_
view.tab_ratio = parser().attribute<std::size_t>("tabRatio");
}
if (parser().attribute_present("activeTab"))
{
view.active_tab = parser().attribute<std::size_t>("activeTab");
}
target_.view(view);
skip_attributes();
@ -1923,7 +1965,11 @@ void xlsx_consumer::read_stylesheet()
{
auto &fonts = stylesheet.fonts;
auto count = parser().attribute<std::size_t>("count");
skip_attributes({qn("x14ac", "knownFonts")});
if (parser().attribute_present(qn("x14ac", "knownFonts")))
{
target_.enable_known_fonts();
}
while (in_element(qn("spreadsheetml", "fonts")))
{
@ -1969,7 +2015,16 @@ void xlsx_consumer::read_stylesheet()
}
else if (font_property_element == qn("spreadsheetml", "vertAlign"))
{
new_font.superscript(parser().attribute("val") == "superscript");
auto vert_align = parser().attribute("val");
if (vert_align == "superscript")
{
new_font.superscript(true);
}
else if (vert_align == "subscript")
{
new_font.subscript(true);
}
}
else if (font_property_element == qn("spreadsheetml", "strike"))
{
@ -2130,33 +2185,33 @@ void xlsx_consumer::read_stylesheet()
? format_records.emplace(format_records.end())
: style_records.emplace(style_records.end()));
record.first.border_applied = parser().attribute_present("applyBorder")
&& is_true(parser().attribute("applyBorder"));
record.first.border_applied = !parser().attribute_present("applyBorder")
|| is_true(parser().attribute("applyBorder"));
record.first.border_id = parser().attribute_present("borderId")
? parser().attribute<std::size_t>("borderId") : 0;
record.first.fill_applied = parser().attribute_present("applyFill")
&& is_true(parser().attribute("applyFill"));
record.first.fill_applied = !parser().attribute_present("applyFill")
|| is_true(parser().attribute("applyFill"));
record.first.fill_id = parser().attribute_present("fillId")
? parser().attribute<std::size_t>("fillId") : 0;
record.first.font_applied = parser().attribute_present("applyFont")
&& is_true(parser().attribute("applyFont"));
record.first.font_applied = !parser().attribute_present("applyFont")
|| is_true(parser().attribute("applyFont"));
record.first.font_id = parser().attribute_present("fontId")
? parser().attribute<std::size_t>("fontId") : 0;
record.first.number_format_applied = parser().attribute_present("applyNumberFormat")
&& is_true(parser().attribute("applyNumberFormat"));
record.first.number_format_applied = !parser().attribute_present("applyNumberFormat")
|| is_true(parser().attribute("applyNumberFormat"));
record.first.number_format_id = parser().attribute_present("numFmtId")
? parser().attribute<std::size_t>("numFmtId") : 0;
auto apply_alignment_present = parser().attribute_present("applyAlignment");
record.first.alignment_applied = apply_alignment_present
&& is_true(parser().attribute("applyAlignment"));
record.first.alignment_applied = !apply_alignment_present
|| is_true(parser().attribute("applyAlignment"));
auto apply_protection_present = parser().attribute_present("applyProtection");
record.first.protection_applied = apply_protection_present
&& is_true(parser().attribute("applyProtection"));
record.first.protection_applied = !apply_protection_present
|| is_true(parser().attribute("applyProtection"));
record.first.pivot_button_ = parser().attribute_present("pivotButton")
&& is_true(parser().attribute("pivotButton"));

View File

@ -500,7 +500,7 @@ void xlsx_producer::write_workbook(const relationship &rel)
const auto &view = source_.view();
if (view.active_tab.is_set())
if (view.active_tab.is_set() && view.active_tab.get() != std::size_t(0))
{
write_attribute("activeTab", view.active_tab.get());
}
@ -932,34 +932,50 @@ void xlsx_producer::write_font(const font &f)
if (f.bold())
{
write_start_element(xmlns, "b");
write_attribute("val", write_bool(true));
write_end_element(xmlns, "b");
}
if (f.italic())
{
write_start_element(xmlns, "i");
write_attribute("val", write_bool(true));
write_end_element(xmlns, "i");
}
if (f.underlined())
{
write_start_element(xmlns, "u");
if (f.underline() != font::underline_style::single)
{
write_attribute("val", f.underline());
}
write_end_element(xmlns, "u");
}
if (f.strikethrough())
{
write_start_element(xmlns, "strike");
write_attribute("val", write_bool(true));
write_end_element(xmlns, "strike");
}
if (f.superscript())
{
write_start_element(xmlns, "vertAlign");
write_attribute("val", "superscript");
write_end_element(xmlns, "vertAlign");
}
else if (f.subscript())
{
write_start_element(xmlns, "vertAlign");
write_attribute("val", "subscript");
write_end_element(xmlns, "vertAlign");
}
if (f.has_size())
{
write_start_element(xmlns, "sz");
write_attribute("val", f.size());
write_end_element(xmlns, "sz");
}
if (f.has_color())
{
@ -968,9 +984,12 @@ void xlsx_producer::write_font(const font &f)
write_end_element(xmlns, "color");
}
if (f.has_name())
{
write_start_element(xmlns, "name");
write_attribute("val", f.name());
write_end_element(xmlns, "name");
}
if (f.has_family())
{
@ -1255,39 +1274,61 @@ void xlsx_producer::write_styles(const relationship & /*rel*/)
const auto &current_style_impl = stylesheet.style_impls.at(current_style_name);
write_start_element(xmlns, "xf");
if (current_style_impl.number_format_id.is_set())
{
write_attribute("numFmtId", current_style_impl.number_format_id.get());
}
if (current_style_impl.font_id.is_set())
{
write_attribute("fontId", current_style_impl.font_id.get());
}
if (current_style_impl.fill_id.is_set())
{
write_attribute("fillId", current_style_impl.fill_id.get());
}
if (current_style_impl.border_id.is_set())
{
write_attribute("borderId", current_style_impl.border_id.get());
if (current_style_impl.number_format_applied)
{
write_attribute("applyNumberFormat", write_bool(true));
}
if (current_style_impl.fill_applied)
if (current_style_impl.number_format_id.is_set()
&& !current_style_impl.number_format_applied)
{
write_attribute("applyFill", write_bool(true));
write_attribute("applyNumberFormat", write_bool(false));
}
if (current_style_impl.font_applied)
if (current_style_impl.fill_id.is_set()
&& !current_style_impl.fill_applied)
{
write_attribute("applyFont", write_bool(true));
write_attribute("applyFill", write_bool(false));
}
if (current_style_impl.border_applied)
if (current_style_impl.font_id.is_set()
&& !current_style_impl.font_applied)
{
write_attribute("applyBorder", write_bool(true));
write_attribute("applyFont", write_bool(false));
}
if (current_style_impl.alignment_applied)
if (current_style_impl.border_id.is_set()
&& !current_style_impl.border_applied)
{
write_attribute("applyAlignment", write_bool(true));
write_attribute("applyBorder", write_bool(false));
}
if (current_style_impl.protection_applied)
if (current_style_impl.alignment_id.is_set()
&& !current_style_impl.alignment_applied)
{
write_attribute("applyProtection", write_bool(true));
write_attribute("applyAlignment", write_bool(false));
}
if (current_style_impl.protection_id.is_set()
&& !current_style_impl.protection_applied)
{
write_attribute("applyProtection", write_bool(false));
}
if (current_style_impl.pivot_button_)
@ -1371,34 +1412,40 @@ void xlsx_producer::write_styles(const relationship & /*rel*/)
write_attribute("borderId", current_format_impl.border_id.get());
if (current_format_impl.number_format_applied)
if (current_format_impl.number_format_id.is_set()
&& !current_format_impl.number_format_applied)
{
write_attribute("applyNumberFormat", write_bool(true));
write_attribute("applyNumberFormat", write_bool(false));
}
if (current_format_impl.fill_applied)
if (current_format_impl.fill_id.is_set()
&& !current_format_impl.fill_applied)
{
write_attribute("applyFill", write_bool(true));
write_attribute("applyFill", write_bool(false));
}
if (current_format_impl.font_applied)
if (current_format_impl.font_id.is_set()
&& !current_format_impl.font_applied)
{
write_attribute("applyFont", write_bool(true));
write_attribute("applyFont", write_bool(false));
}
if (current_format_impl.border_applied)
if (current_format_impl.border_id.is_set()
&& !current_format_impl.border_applied)
{
write_attribute("applyBorder", write_bool(true));
write_attribute("applyBorder", write_bool(false));
}
if (current_format_impl.alignment_applied)
if (current_format_impl.alignment_id.is_set()
&& !current_format_impl.alignment_applied)
{
write_attribute("applyAlignment", write_bool(true));
write_attribute("applyAlignment", write_bool(false));
}
if (current_format_impl.protection_applied)
if (current_format_impl.protection_id.is_set()
&& !current_format_impl.protection_applied)
{
write_attribute("applyProtection", write_bool(true));
write_attribute("applyProtection", write_bool(false));
}
if (current_format_impl.pivot_button_)
@ -2129,9 +2176,15 @@ void xlsx_producer::write_worksheet(const relationship &rel)
write_start_element(xmlns, "sheetViews");
write_start_element(xmlns, "sheetView");
const auto wb_view = source_.view();
const auto view = ws.view();
write_attribute("tabSelected", write_bool(view.id() == 0));
if ((wb_view.active_tab.is_set() && (ws.id() - 1) == wb_view.active_tab.get())
|| (!wb_view.active_tab.is_set() && ws.id() == 1))
{
write_attribute("tabSelected", write_bool(true));
}
write_attribute("workbookViewId", view.id());
if (view.type() != sheet_view_type::normal)
@ -2272,54 +2325,55 @@ void xlsx_producer::write_worksheet(const relationship &rel)
write_start_element(xmlns, "sheetData");
auto first_row = ws.lowest_row_or_props();
auto last_row = ws.highest_row_or_props();
auto first_block_column = constants::max_column();
auto last_block_column = constants::min_column();
for (auto row = first_row; row <= last_row; ++row)
{
auto first_column = constants::max_column();
auto last_column = constants::min_column();
bool any_non_null = false;
auto first_check_row = row;
auto last_check_row = row;
auto first_row_in_block = row == first_row || row % 16 == 1;
// See note for CT_Row, span attribute about block optimization
if (first_row_in_block)
{
first_check_row = first_row;
// round up to the next multiple of 16
last_check_row = (((first_row - 1) / 16) + 1) * 16;
}
for (auto check_row = first_check_row; check_row <= last_check_row; ++check_row)
{
for (auto column = dimension.top_left().column(); column <= dimension.bottom_right().column(); ++column)
{
if (!ws.has_cell(cell_reference(column, row))) continue;
auto cell = ws.cell(cell_reference(column, row));
if (cell.garbage_collectible()) continue;
first_column = std::min(first_column, cell.column());
last_column = std::max(last_column, cell.column());
first_block_column = std::min(first_block_column, cell.column());
last_block_column = std::max(last_block_column, cell.column());
if (!cell.garbage_collectible())
if (row == check_row)
{
any_non_null = true;
}
}
}
if (!any_non_null && !ws.has_row_properties(row)) continue;
write_start_element(xmlns, "row");
write_attribute("r", row);
if (any_non_null)
{
auto span_string = std::to_string(first_column.index) + ":" + std::to_string(last_column.index);
auto span_string = std::to_string(first_block_column.index) + ":"
+ std::to_string(last_block_column.index);
write_attribute("spans", span_string);
}
if (ws.has_row_properties(row))
{
const auto &props = ws.row_properties(row);
if (props.custom_height)
{
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();
@ -2338,6 +2392,16 @@ void xlsx_producer::write_worksheet(const relationship &rel)
{
write_attribute("hidden", write_bool(true));
}
if (props.custom_height)
{
write_attribute("customHeight", write_bool(true));
}
if (props.dy_descent.is_set())
{
write_attribute(xml::qname(xmlns_x14ac, "dyDescent"), props.dy_descent.get());
}
}
if (any_non_null)
@ -2394,8 +2458,8 @@ void xlsx_producer::write_worksheet(const relationship &rel)
write_attribute("t", "inlineStr");
break;
case cell::type::number:
write_attribute("t", "n");
case cell::type::number: // default, don't write it
//write_attribute("t", "n");
break;
case cell::type::shared_string:

View File

@ -45,9 +45,9 @@ bool font::bold() const
return bold_;
}
font &font::superscript(bool superscript)
font &font::superscript(bool value)
{
superscript_ = superscript;
superscript_ = value;
return *this;
}
@ -56,6 +56,17 @@ bool font::superscript() const
return superscript_;
}
font &font::subscript(bool value)
{
subscript_ = value;
return *this;
}
bool font::subscript() const
{
return subscript_;
}
font &font::italic(bool italic)
{
italic_ = italic;
@ -181,6 +192,11 @@ font &font::charset(std::size_t charset)
return *this;
}
std::size_t font::charset() const
{
return charset_.get();
}
bool font::has_scheme() const
{
return scheme_.is_set();
@ -209,79 +225,32 @@ std::string font::scheme() const
bool font::operator==(const font &other) const
{
if (bold() != other.bold())
{
return false;
}
if (has_color() != other.has_color())
{
return false;
}
if (has_color())
{
if (color() != other.color())
{
return false;
}
}
if (has_family() != other.has_family())
{
return false;
}
if (has_family())
{
if (family() != other.family())
{
return false;
}
}
if (italic() != other.italic())
{
return false;
}
if (name() != other.name())
{
return false;
}
if (has_scheme() != other.has_scheme())
{
return false;
}
if (has_scheme())
{
if (scheme() != other.scheme())
{
return false;
}
}
if (std::fabs(size() - other.size()) != 0.0)
{
return false;
}
if (strikethrough() != other.strikethrough())
{
return false;
}
if (superscript() != other.superscript())
{
return false;
}
if (underline() != other.underline())
{
return false;
}
// name
if (has_name() != other.has_name()) return false;
if (has_name() && name() != other.name()) return false;
// size
if (has_size() != other.has_size()) return false;
if (has_size() && std::fabs(size() - other.size()) != 0.0) return false;
// family
if (has_family() != other.has_family()) return false;
if (has_family() && family() != other.family()) return false;
// scheme
if (has_scheme() != other.has_scheme()) return false;
if (has_scheme() && scheme() != other.scheme()) return false;
// color
if (has_color() != other.has_color()) return false;
if (has_color() && color() != other.color()) return false;
// charset
if (has_charset()!= other.has_charset()) return false;
if (has_charset() && charset()!= other.charset()) return false;
// modifiers
if (bold() != other.bold()) return false;
if (italic() != other.italic()) return false;
if (strikethrough() != other.strikethrough()) return false;
if (superscript() != other.superscript()) return false;
if (subscript() != other.subscript()) return false;
if (underline() != other.underline()) return false;
if (shadow() != other.shadow()) return false;
return true;
}

View File

@ -408,6 +408,7 @@ workbook workbook::empty()
wb.d_->file_version_ = file_version;
xlnt::workbook_view wb_view;
wb_view.active_tab = 0;
wb_view.x_window = 0;
wb_view.y_window = 460;
wb_view.window_width = 28800;
@ -462,13 +463,17 @@ workbook workbook::empty()
.color(theme_color(1));
stylesheet.fonts.push_back(default_font);
wb.create_builtin_style(0);
wb.create_builtin_style(0)
.border(default_border, true)
.fill(default_fill, true)
.font(default_font, true)
.number_format(xlnt::number_format::general(), true);
wb.create_format(true)
.border(default_border, false)
.fill(default_fill, false)
.font(default_font, false)
.number_format(xlnt::number_format::general(), false)
.border(default_border, true)
.fill(default_fill, true)
.font(default_font, true)
.number_format(xlnt::number_format::general(), true)
.style("Normal");
xlnt::calculation_properties calc_props;

View File

@ -608,7 +608,8 @@ column_t worksheet::highest_column_or_props() const
range_reference worksheet::calculate_dimension() const
{
return range_reference(lowest_column(), lowest_row(), highest_column(), highest_row());
return range_reference(lowest_column(), lowest_row(),
highest_column(), highest_row_or_props());
}
range worksheet::range(const std::string &reference_string)

View File

@ -189,38 +189,56 @@ public:
auto sheet1 = wb.active_sheet();
sheet1.format_properties(format_properties);
auto &view = sheet1.view();
auto selection = xlnt::selection();
selection.active_cell("C1");
selection.sqref("C1");
view.add_selection(selection);
sheet1.view().add_selection(selection);
// comments
auto comment_font = xlnt::font()
.bold(true)
.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");
sheet1.cell("A2").value("Sheet1!A2");
sheet1.cell("A2").comment("Sheet1 comment2", comment_font, "Microsoft Office User");
// hyperlinks
auto hyperlink_font = xlnt::font()
.size(12)
.color(xlnt::theme_color(10))
.name("Calibri")
.family(2)
.scheme("minor")
.underline(xlnt::font::underline_style::single);
auto hyperlink_style = wb.create_builtin_style(8);
hyperlink_style.font(hyperlink_font, true);
hyperlink_style.number_format(hyperlink_style.number_format(), false);
hyperlink_style.fill(hyperlink_style.fill(), false);
hyperlink_style.border(hyperlink_style.border(), false);
auto hyperlink_format = wb.create_format();
hyperlink_format.font(hyperlink_font, true);
hyperlink_format.number_format(hyperlink_format.number_format(), true);
hyperlink_format.fill(hyperlink_format.fill(), true);
hyperlink_format.border(hyperlink_format.border(), true);
hyperlink_format.style(hyperlink_style);
sheet1.cell("A4").hyperlink("https://microsoft.com/", "hyperlink1");
sheet1.cell("A4").format(hyperlink_format);
sheet1.cell("A5").hyperlink("https://google.com/");
sheet1.cell("A5").format(hyperlink_format);
sheet1.cell("A6").hyperlink(sheet1.cell("A1"));
sheet1.cell("A6").format(hyperlink_format);
sheet1.cell("A7").hyperlink("mailto:invalid@example.com?subject=important");
sheet1.cell("A7").format(hyperlink_format);
// formulae
sheet1.cell("C1").formula("=CONCATENATE(C2,C3)");
sheet1.cell("C2").value("a");
sheet1.cell("C3").value("b");
@ -232,20 +250,36 @@ public:
auto sheet2 = wb.create_sheet();
sheet2.format_properties(format_properties);
sheet2.add_view(xlnt::sheet_view());
sheet2.view().add_selection(selection);
sheet2.cell("A4").hyperlink("https://apple.com/", "hyperlink2");
sheet2.cell("A4").font(hyperlink_font);
// comments
sheet2.cell("A1").value("Sheet2!A1");
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");
// hyperlinks
sheet2.cell("A4").hyperlink("https://apple.com/", "hyperlink2");
sheet2.cell("A4").format(hyperlink_format);
// formulae
sheet2.cell("C1").formula("=C2*C3");
sheet2.cell("C2").value(2);
sheet2.cell("C3").value(3);
for (auto i = 1; i <= 4; ++i)
{
sheet2.row_properties(i).dy_descent = 0.2;
}
wb.default_slicer_style("SlicerStyleLight1");
wb.enable_known_fonts();
wb.core_property(xlnt::core_property::created, "2018-03-18T20:53:30Z");
wb.core_property(xlnt::core_property::modified, "2018-03-18T20:59:53Z");
const auto path = path_helper::test_file("10_comments_hyperlinks_formulae.xlsx");
xlnt_assert(workbook_matches_file(wb, path));
}
@ -372,14 +406,12 @@ public:
wb.load(path);
auto ws1 = wb.sheet_by_index(0);
xlnt_assert_equals(ws1.cell("C1").value<std::string>(), "ab");
xlnt_assert(ws1.cell("C1").has_formula());
xlnt_assert_equals(ws1.cell("C1").formula(), "CONCATENATE(C2,C3)");
xlnt_assert_equals(ws1.cell("C2").value<std::string>(), "a");
xlnt_assert_equals(ws1.cell("C3").value<std::string>(), "b");
auto ws2 = wb.sheet_by_index(1);
xlnt_assert_equals(ws2.cell("C1").value<int>(), 6);
xlnt_assert(ws2.cell("C1").has_formula());
xlnt_assert_equals(ws2.cell("C1").formula(), "C2*C3");
xlnt_assert_equals(ws2.cell("C2").value<int>(), 2);
@ -448,28 +480,49 @@ public:
xlnt_assert(!ws.row_properties(4).height.is_set());
xlnt_assert_equals(ws.row_properties(5).height.get(), 100);
xlnt_assert_delta(ws.column_properties("A").width.get(), 15.949776785714286, 1.0E-9);
auto width = ((16.0 * 7) - 5) / 7;
xlnt_assert_delta(ws.column_properties("A").width.get(), width, 1.0E-9);
xlnt_assert(!ws.column_properties("B").width.is_set());
xlnt_assert_delta(ws.column_properties("C").width.get(), 15.949776785714286, 1.0E-9);
xlnt_assert_delta(ws.column_properties("C").width.get(), width, 1.0E-9);
xlnt_assert(!ws.column_properties("D").width.is_set());
xlnt_assert_delta(ws.column_properties("E").width.get(), 15.949776785714286, 1.0E-9);
xlnt_assert_delta(ws.column_properties("E").width.get(), width, 1.0E-9);
}
void test_write_custom_heights_widths()
{
xlnt::workbook wb;
wb.core_property(xlnt::core_property::creator, "Microsoft Office User");
wb.core_property(xlnt::core_property::last_modified_by, "Microsoft Office User");
wb.core_property(xlnt::core_property::created, "2017-10-30T23:03:54Z");
wb.core_property(xlnt::core_property::modified, "2017-10-30T23:08:31Z");
wb.default_slicer_style("SlicerStyleLight1");
wb.enable_known_fonts();
auto ws = wb.active_sheet();
auto sheet_format_properties = xlnt::sheet_format_properties();
sheet_format_properties.base_col_width = 10.0;
sheet_format_properties.default_row_height = 16.0;
sheet_format_properties.dy_descent = 0.2;
ws.format_properties(sheet_format_properties);
ws.cell("A1").value("A1");
ws.cell("B1").value("B1");
ws.cell("D1").value("D1");
ws.cell("A2").value("A2");
ws.cell("B2").value("B2");
ws.cell("D2").value("D2");
ws.cell("A4").value("A4");
ws.cell("B2").value("B2");
ws.cell("B4").value("B4");
ws.cell("D2").value("D2");
ws.cell("D4").value("D4");
for (auto i = 1; i <= 5; ++i)
{
ws.row_properties(i).dy_descent = 0.2;
}
ws.row_properties(1).height = 100;
ws.row_properties(1).custom_height = true;
@ -479,19 +532,22 @@ public:
ws.row_properties(5).height = 100;
ws.row_properties(5).custom_height = true;
ws.column_properties("A").width = 15.949776785714286;
auto width = ((16.0 * 7) - 5) / 7;
ws.column_properties("A").width = width;
ws.column_properties("A").custom_width = true;
ws.column_properties("C").width = 15.949776785714286;
ws.column_properties("C").width = width;
ws.column_properties("C").custom_width = true;
ws.column_properties("E").width = 15.949776785714286;
ws.column_properties("E").width = width;
ws.column_properties("E").custom_width = true;
wb.default_slicer_style("SlicerStyleLight1");
wb.enable_known_fonts();
xlnt_assert(workbook_matches_file(wb, path_helper::test_file("13_custom_heights_widths.xlsx")));
xlnt_assert(workbook_matches_file(wb,
path_helper::test_file("13_custom_heights_widths.xlsx")));
}
/// <summary>