mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
improve hyperlinks and style round tripping
This commit is contained in:
parent
410e73d594
commit
617f7a2525
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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 ¤t_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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue
Block a user