mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
finish implementing comment positioning, closes #68
This commit is contained in:
parent
b06f3901f6
commit
cee933a1b8
|
@ -446,7 +446,12 @@ public:
|
||||||
class comment comment();
|
class comment comment();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Apply the comment provided as the ony argument to the cell.
|
/// Create a new comment with the given text and optional author and apply it to the cell.
|
||||||
|
/// </summary>
|
||||||
|
void comment(const std::string &text, const std::string &author = "Microsoft Office User");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Apply the comment provided as the only argument to the cell.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void comment(const class comment &new_comment);
|
void comment(const class comment &new_comment);
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,24 @@ public:
|
||||||
/// </summary>
|
/// </summary>
|
||||||
std::string author() const;
|
std::string author() const;
|
||||||
|
|
||||||
|
void hide();
|
||||||
|
|
||||||
|
void show();
|
||||||
|
|
||||||
|
bool visible() const;
|
||||||
|
|
||||||
|
void position(int left, int top);
|
||||||
|
|
||||||
|
int left() const;
|
||||||
|
|
||||||
|
int top() const;
|
||||||
|
|
||||||
|
void size(int width, int height);
|
||||||
|
|
||||||
|
int width() const;
|
||||||
|
|
||||||
|
int height() const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Return true if both comments are equivalent.
|
/// Return true if both comments are equivalent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -73,6 +91,15 @@ public:
|
||||||
private:
|
private:
|
||||||
formatted_text text_;
|
formatted_text text_;
|
||||||
std::string author_;
|
std::string author_;
|
||||||
|
|
||||||
|
bool visible_ = false;
|
||||||
|
std::string fill_;
|
||||||
|
|
||||||
|
int left_ = 0;
|
||||||
|
int top_ = 0;
|
||||||
|
|
||||||
|
int width_ = 0;
|
||||||
|
int height_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -1020,9 +1020,41 @@ class comment cell::comment()
|
||||||
return d_->comment_.get();
|
return d_->comment_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cell::comment(const std::string &text, const std::string &author)
|
||||||
|
{
|
||||||
|
comment(xlnt::comment(text, author));
|
||||||
|
}
|
||||||
|
|
||||||
void cell::comment(const class comment &new_comment)
|
void cell::comment(const class comment &new_comment)
|
||||||
{
|
{
|
||||||
d_->comment_.set(new_comment);
|
d_->comment_.set(new_comment);
|
||||||
|
|
||||||
|
// offset comment 5 pixels down and 5 pixels right of the top right corner of the cell
|
||||||
|
auto cell_position = get_anchor();
|
||||||
|
|
||||||
|
// todo: make this cell_position.first += get_width() instead
|
||||||
|
if (get_worksheet().has_column_properties(get_column()))
|
||||||
|
{
|
||||||
|
cell_position.first += get_worksheet().get_column_properties(get_column()).width;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static const auto DefaultColumnWidth = 51.85L;
|
||||||
|
|
||||||
|
auto points_to_pixels = [](long double value, long double dpi)
|
||||||
|
{
|
||||||
|
return static_cast<int>(std::ceil(value * dpi / 72));
|
||||||
|
};
|
||||||
|
|
||||||
|
cell_position.first += points_to_pixels(DefaultColumnWidth, 96.0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_position.first += 5;
|
||||||
|
cell_position.second += 5;
|
||||||
|
|
||||||
|
d_->comment_.get().position(cell_position.first, cell_position.second);
|
||||||
|
d_->comment_.get().size(200, 100);
|
||||||
|
|
||||||
get_worksheet().register_comments_in_manifest();
|
get_worksheet().register_comments_in_manifest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,53 @@ std::string comment::author() const
|
||||||
return author_;
|
return author_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void comment::hide()
|
||||||
|
{
|
||||||
|
visible_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void comment::show()
|
||||||
|
{
|
||||||
|
visible_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void comment::position(int left, int top)
|
||||||
|
{
|
||||||
|
left_ = left;
|
||||||
|
top_ = top;
|
||||||
|
}
|
||||||
|
|
||||||
|
void comment::size(int width, int height)
|
||||||
|
{
|
||||||
|
width_ = width;
|
||||||
|
height_ = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool comment::visible() const
|
||||||
|
{
|
||||||
|
return visible_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int comment::left() const
|
||||||
|
{
|
||||||
|
return left_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int comment::top() const
|
||||||
|
{
|
||||||
|
return top_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int comment::width() const
|
||||||
|
{
|
||||||
|
return width_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int comment::height() const
|
||||||
|
{
|
||||||
|
return height_;
|
||||||
|
}
|
||||||
|
|
||||||
XLNT_API bool operator==(const comment &left, const comment &right)
|
XLNT_API bool operator==(const comment &left, const comment &right)
|
||||||
{
|
{
|
||||||
return left.text_ == right.text_ && left.author_ == right.author_;
|
return left.text_ == right.text_ && left.author_ == right.author_;
|
||||||
|
|
|
@ -2513,118 +2513,138 @@ void xlsx_producer::write_comments(const relationship &/*rel*/, worksheet ws,
|
||||||
void xlsx_producer::write_vml_drawings(const relationship &rel, worksheet ws,
|
void xlsx_producer::write_vml_drawings(const relationship &rel, worksheet ws,
|
||||||
const std::vector<cell_reference> &cells)
|
const std::vector<cell_reference> &cells)
|
||||||
{
|
{
|
||||||
static const auto &xmlns_mv = std::string("http://macVmlSchemaUri");
|
static const auto &xmlns_mv = std::string("http://macVmlSchemaUri");
|
||||||
static const auto &xmlns_o = std::string("urn:schemas-microsoft-com:office:office");
|
static const auto &xmlns_o = std::string("urn:schemas-microsoft-com:office:office");
|
||||||
static const auto &xmlns_v = std::string("urn:schemas-microsoft-com:vml");
|
static const auto &xmlns_v = std::string("urn:schemas-microsoft-com:vml");
|
||||||
static const auto &xmlns_x = std::string("urn:schemas-microsoft-com:office:excel");
|
static const auto &xmlns_x = std::string("urn:schemas-microsoft-com:office:excel");
|
||||||
|
|
||||||
serializer().start_element("xml");
|
serializer().start_element("xml");
|
||||||
serializer().namespace_decl(xmlns_v, "v");
|
serializer().namespace_decl(xmlns_v, "v");
|
||||||
serializer().namespace_decl(xmlns_o, "o");
|
serializer().namespace_decl(xmlns_o, "o");
|
||||||
serializer().namespace_decl(xmlns_x, "x");
|
serializer().namespace_decl(xmlns_x, "x");
|
||||||
serializer().namespace_decl(xmlns_mv, "mv");
|
serializer().namespace_decl(xmlns_mv, "mv");
|
||||||
|
|
||||||
|
serializer().start_element(xmlns_o, "shapelayout");
|
||||||
|
serializer().attribute(xml::qname(xmlns_v, "ext"), "edit");
|
||||||
|
serializer().start_element(xmlns_o, "idmap");
|
||||||
|
serializer().attribute(xml::qname(xmlns_v, "ext"), "edit");
|
||||||
|
|
||||||
serializer().start_element(xmlns_o, "shapelayout");
|
auto filename = rel.get_target().get_path().split_extension().first;
|
||||||
serializer().attribute(xml::qname(xmlns_v, "ext"), "edit");
|
auto index_pos = filename.size() - 1;
|
||||||
serializer().start_element(xmlns_o, "idmap");
|
|
||||||
serializer().attribute(xml::qname(xmlns_v, "ext"), "edit");
|
|
||||||
auto filename = rel.get_target().get_path().split_extension().first;
|
|
||||||
auto index_pos = filename.size() - 1;
|
|
||||||
while (filename[index_pos] >= '0' && filename[index_pos] <= '9')
|
|
||||||
{
|
|
||||||
index_pos--;
|
|
||||||
}
|
|
||||||
auto file_index = std::stoull(filename.substr(index_pos + 1));
|
|
||||||
serializer().attribute("data", file_index);
|
|
||||||
serializer().end_element(xmlns_o, "idmap");
|
|
||||||
serializer().end_element(xmlns_o, "shapelayout");
|
|
||||||
|
|
||||||
serializer().start_element(xmlns_v, "shapetype");
|
while (filename[index_pos] >= '0' && filename[index_pos] <= '9')
|
||||||
serializer().attribute("id", "_x0000_t202");
|
{
|
||||||
serializer().attribute("coordsize", "21600,21600");
|
index_pos--;
|
||||||
serializer().attribute(xml::qname(xmlns_o, "spt"), "202");
|
}
|
||||||
serializer().attribute("path", "m0,0l0,21600,21600,21600,21600,0xe");
|
|
||||||
serializer().start_element(xmlns_v, "stroke");
|
|
||||||
serializer().attribute("joinstyle", "miter");
|
|
||||||
serializer().end_element(xmlns_v, "stroke");
|
|
||||||
serializer().start_element(xmlns_v, "path");
|
|
||||||
serializer().attribute("gradientshapeok", "t");
|
|
||||||
serializer().attribute(xml::qname(xmlns_o, "connecttype"), "rect");
|
|
||||||
serializer().end_element(xmlns_v, "path");
|
|
||||||
serializer().end_element(xmlns_v, "shapetype");
|
|
||||||
|
|
||||||
std::size_t comment_index = 0;
|
auto file_index = std::stoull(filename.substr(index_pos + 1));
|
||||||
|
|
||||||
for (const auto &cell_ref : cells)
|
serializer().attribute("data", file_index);
|
||||||
{
|
serializer().end_element(xmlns_o, "idmap");
|
||||||
|
serializer().end_element(xmlns_o, "shapelayout");
|
||||||
|
|
||||||
|
serializer().start_element(xmlns_v, "shapetype");
|
||||||
|
serializer().attribute("id", "_x0000_t202");
|
||||||
|
serializer().attribute("coordsize", "21600,21600");
|
||||||
|
serializer().attribute(xml::qname(xmlns_o, "spt"), "202");
|
||||||
|
serializer().attribute("path", "m0,0l0,21600,21600,21600,21600,0xe");
|
||||||
|
serializer().start_element(xmlns_v, "stroke");
|
||||||
|
serializer().attribute("joinstyle", "miter");
|
||||||
|
serializer().end_element(xmlns_v, "stroke");
|
||||||
|
serializer().start_element(xmlns_v, "path");
|
||||||
|
serializer().attribute("gradientshapeok", "t");
|
||||||
|
serializer().attribute(xml::qname(xmlns_o, "connecttype"), "rect");
|
||||||
|
serializer().end_element(xmlns_v, "path");
|
||||||
|
serializer().end_element(xmlns_v, "shapetype");
|
||||||
|
|
||||||
|
std::size_t comment_index = 0;
|
||||||
|
|
||||||
|
for (const auto &cell_ref : cells)
|
||||||
|
{
|
||||||
auto comment = ws.get_cell(cell_ref).comment();
|
auto comment = ws.get_cell(cell_ref).comment();
|
||||||
auto shape_id = 1024 * file_index + 1 + comment_index * 2;
|
auto shape_id = 1024 * file_index + 1 + comment_index * 2;
|
||||||
|
|
||||||
serializer().start_element(xmlns_v, "shape");
|
serializer().start_element(xmlns_v, "shape");
|
||||||
serializer().attribute("id", "_x0000_s" + std::to_string(shape_id));
|
serializer().attribute("id", "_x0000_s" + std::to_string(shape_id));
|
||||||
serializer().attribute("type", "#_x0000_t202");
|
serializer().attribute("type", "#_x0000_t202");
|
||||||
std::string style("position:absolute;margin-left:80pt;margin-top:");
|
|
||||||
style.append(std::to_string(2 + comment_index * 4));
|
|
||||||
style.append("pt;width:104pt;height:76pt;z-index:");
|
|
||||||
style.append(std::to_string(comment_index + 1));
|
|
||||||
style.append(";visibility:hidden");
|
|
||||||
serializer().attribute("style", style);
|
|
||||||
serializer().attribute("fillcolor", "#fbf6d6");
|
|
||||||
serializer().attribute("strokecolor", "#edeaa1");
|
|
||||||
|
|
||||||
serializer().start_element(xmlns_v, "fill");
|
std::vector<std::pair<std::string, std::string>> style;
|
||||||
serializer().attribute("color2", "#fbfe82");
|
|
||||||
serializer().attribute("angle", -180);
|
|
||||||
serializer().attribute("type", "gradient");
|
|
||||||
serializer().start_element(xmlns_o, "fill");
|
|
||||||
serializer().attribute(xml::qname(xmlns_v, "ext"), "view");
|
|
||||||
serializer().attribute("type", "gradientUnscaled");
|
|
||||||
serializer().end_element(xmlns_o, "fill");
|
|
||||||
serializer().end_element(xmlns_v, "fill");
|
|
||||||
|
|
||||||
serializer().start_element(xmlns_v, "shadow");
|
style.push_back({"position", "absolute"});
|
||||||
serializer().attribute("on", "t");
|
style.push_back({"margin-left", std::to_string(comment.left())});
|
||||||
serializer().attribute("obscured", "t");
|
style.push_back({"margin-top", std::to_string(comment.top())});
|
||||||
serializer().end_element(xmlns_v, "shadow");
|
style.push_back({"width", std::to_string(comment.width())});
|
||||||
|
style.push_back({"height", std::to_string(comment.height())});
|
||||||
|
style.push_back({"z-index", std::to_string(comment_index + 1)});
|
||||||
|
style.push_back({"visibility", comment.visible() ? "visible" : "hidden"});
|
||||||
|
|
||||||
serializer().start_element(xmlns_v, "path");
|
std::string style_string;
|
||||||
serializer().attribute(xml::qname(xmlns_o, "connecttype"), "none");
|
|
||||||
serializer().end_element(xmlns_v, "path");
|
|
||||||
|
|
||||||
serializer().start_element(xmlns_v, "textbox");
|
for (auto part : style)
|
||||||
serializer().attribute("style", "mso-direction-alt:auto");
|
{
|
||||||
serializer().start_element("div");
|
style_string.append(part.first);
|
||||||
serializer().attribute("style", "text-align:left");
|
style_string.append(":");
|
||||||
serializer().characters("");
|
style_string.append(part.second);
|
||||||
serializer().end_element("div");
|
style_string.append(":");
|
||||||
serializer().end_element(xmlns_v, "textbox");
|
}
|
||||||
|
|
||||||
serializer().start_element(xmlns_x, "ClientData");
|
serializer().attribute("style", style_string);
|
||||||
serializer().attribute("ObjectType", "Note");
|
serializer().attribute("fillcolor", "#fbf6d6");
|
||||||
serializer().start_element(xmlns_x, "MoveWithCells");
|
serializer().attribute("strokecolor", "#edeaa1");
|
||||||
serializer().end_element(xmlns_x, "MoveWithCells");
|
|
||||||
serializer().start_element(xmlns_x, "SizeWithCells");
|
|
||||||
serializer().end_element(xmlns_x, "SizeWithCells");
|
|
||||||
serializer().start_element(xmlns_x, "Anchor");
|
|
||||||
serializer().characters("1, 15, 0, " + std::to_string(2 + comment_index * 4) + ", 2, 54, 4, 14");
|
|
||||||
serializer().end_element(xmlns_x, "Anchor");
|
|
||||||
serializer().start_element(xmlns_x, "AutoFill");
|
|
||||||
serializer().characters("False");
|
|
||||||
serializer().end_element(xmlns_x, "AutoFill");
|
|
||||||
serializer().start_element(xmlns_x, "Row");
|
|
||||||
serializer().characters(cell_ref.get_row() - 1);
|
|
||||||
serializer().end_element(xmlns_x, "Row");
|
|
||||||
serializer().start_element(xmlns_x, "Column");
|
|
||||||
serializer().characters(cell_ref.get_column_index().index - 1);
|
|
||||||
serializer().end_element(xmlns_x, "Column");
|
|
||||||
serializer().end_element(xmlns_x, "ClientData");
|
|
||||||
|
|
||||||
serializer().end_element(xmlns_v, "shape");
|
serializer().start_element(xmlns_v, "fill");
|
||||||
|
serializer().attribute("color2", "#fbfe82");
|
||||||
|
serializer().attribute("angle", -180);
|
||||||
|
serializer().attribute("type", "gradient");
|
||||||
|
serializer().start_element(xmlns_o, "fill");
|
||||||
|
serializer().attribute(xml::qname(xmlns_v, "ext"), "view");
|
||||||
|
serializer().attribute("type", "gradientUnscaled");
|
||||||
|
serializer().end_element(xmlns_o, "fill");
|
||||||
|
serializer().end_element(xmlns_v, "fill");
|
||||||
|
|
||||||
++comment_index;
|
serializer().start_element(xmlns_v, "shadow");
|
||||||
}
|
serializer().attribute("on", "t");
|
||||||
|
serializer().attribute("obscured", "t");
|
||||||
|
serializer().end_element(xmlns_v, "shadow");
|
||||||
|
|
||||||
serializer().end_element("xml");
|
serializer().start_element(xmlns_v, "path");
|
||||||
|
serializer().attribute(xml::qname(xmlns_o, "connecttype"), "none");
|
||||||
|
serializer().end_element(xmlns_v, "path");
|
||||||
|
|
||||||
|
serializer().start_element(xmlns_v, "textbox");
|
||||||
|
serializer().attribute("style", "mso-direction-alt:auto");
|
||||||
|
serializer().start_element("div");
|
||||||
|
serializer().attribute("style", "text-align:left");
|
||||||
|
serializer().characters("");
|
||||||
|
serializer().end_element("div");
|
||||||
|
serializer().end_element(xmlns_v, "textbox");
|
||||||
|
|
||||||
|
serializer().start_element(xmlns_x, "ClientData");
|
||||||
|
serializer().attribute("ObjectType", "Note");
|
||||||
|
serializer().start_element(xmlns_x, "MoveWithCells");
|
||||||
|
serializer().end_element(xmlns_x, "MoveWithCells");
|
||||||
|
serializer().start_element(xmlns_x, "SizeWithCells");
|
||||||
|
serializer().end_element(xmlns_x, "SizeWithCells");
|
||||||
|
serializer().start_element(xmlns_x, "Anchor");
|
||||||
|
serializer().characters("1, 15, 0, " + std::to_string(2 + comment_index * 4) + ", 2, 54, 4, 14");
|
||||||
|
serializer().end_element(xmlns_x, "Anchor");
|
||||||
|
serializer().start_element(xmlns_x, "AutoFill");
|
||||||
|
serializer().characters("False");
|
||||||
|
serializer().end_element(xmlns_x, "AutoFill");
|
||||||
|
serializer().start_element(xmlns_x, "Row");
|
||||||
|
serializer().characters(cell_ref.get_row() - 1);
|
||||||
|
serializer().end_element(xmlns_x, "Row");
|
||||||
|
serializer().start_element(xmlns_x, "Column");
|
||||||
|
serializer().characters(cell_ref.get_column_index().index - 1);
|
||||||
|
serializer().end_element(xmlns_x, "Column");
|
||||||
|
serializer().end_element(xmlns_x, "ClientData");
|
||||||
|
|
||||||
|
serializer().end_element(xmlns_v, "shape");
|
||||||
|
|
||||||
|
++comment_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
serializer().end_element("xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Other Parts
|
// Other Parts
|
||||||
|
|
2
third-party/botan
vendored
2
third-party/botan
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit e6bf87b6b0d4d9c3877b79de53de58dc34a3acca
|
Subproject commit 923a95d546df5b6d31f39b0af900d0361fb2e6a6
|
2
third-party/pugixml
vendored
2
third-party/pugixml
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit e4c43a0aa2d5cbc158dd279cb2bf6d21f2d27c83
|
Subproject commit a832e8a5eff11f58a00ca41ec51ff3895b0da165
|
2
third-party/utfcpp
vendored
2
third-party/utfcpp
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 0232ab8188b16ae6f2293a5817f1d9b0030879a3
|
Subproject commit a5ad5ec9d936d63e9c010d1054f8b11fed0fabbc
|
Loading…
Reference in New Issue
Block a user