[gnumeric] Read and write cell comments from/to OpenXML. [#630627]
- From: Jean Bréfort <jbrefort src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric] Read and write cell comments from/to OpenXML. [#630627]
- Date: Fri, 1 Oct 2010 12:16:01 +0000 (UTC)
commit f4b3de799a2e22ed37a0f939410b62c05050ace4
Author: Jean Brefort <jean brefort normalesup org>
Date: Fri Oct 1 14:17:26 2010 +0200
Read and write cell comments from/to OpenXML. [#630627]
NEWS | 1 +
plugins/excel/ChangeLog | 12 ++
plugins/excel/xlsx-read.c | 287 +++++++++++++++++++++++++++++++++++++++++++-
plugins/excel/xlsx-write.c | 154 +++++++++++++++++++++++-
4 files changed, 451 insertions(+), 3 deletions(-)
---
diff --git a/NEWS b/NEWS
index e06ab0c..3ab9015 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,7 @@ Andreas:
Jean:
* Export/import tick label rotation angle. [#629675]
+ * Read and write cell comments from/to OpenXML. [#630627]
J.H.M. Dassen (Ray):
* Revised ssconvert man page.
diff --git a/plugins/excel/ChangeLog b/plugins/excel/ChangeLog
index 047ce1e..ab442d3 100644
--- a/plugins/excel/ChangeLog
+++ b/plugins/excel/ChangeLog
@@ -1,3 +1,15 @@
+2010-10-01 Jean Brefort <jean brefort normalesup org>
+ * xlsx-read.c (elem_color), (xlsx_run_weight), (xlsx_run_style),
+ (xlsx_run_family), (xlsx_run_size), (xlsx_run_strikethrough),
+ (xlsx_run_underline), (xlsx_run_color), (xlsx_comments_start),
+ (xlsx_comments_end), (xlsx_comment_author_end),
+ (xlsx_comment_start), (xlsx_comment_end), (xlsx_comment_text),
+ (xlsx_comment_rich_text), (xlsx_wb_end), (xlsx_file_open): read cell
+ comments. [#630627]
+ * xlsx-write.c (xlsx_write_rich_text), (write_comment_author),
+ (xlsx_write_comments), (xlsx_write_sheet), (xlsx_file_save): write cell
+ comments.
+
2010-09-15 Jean Brefort <jean brefort normalesup org>
* ms-chart.c (tick), (chart_write_axis): export/import tick label rotation
diff --git a/plugins/excel/xlsx-read.c b/plugins/excel/xlsx-read.c
index 1c478ee..23976a5 100644
--- a/plugins/excel/xlsx-read.c
+++ b/plugins/excel/xlsx-read.c
@@ -48,6 +48,7 @@
#include "gutils.h"
#include "graph.h"
#include "sheet-object-graph.h"
+#include "sheet-object-cell-comment.h"
#include "gnm-sheet-slicer.h"
#include <goffice/goffice.h>
@@ -124,6 +125,7 @@ typedef struct {
GArray *sst;
PangoAttrList *rich_attrs;
+ PangoAttrList *run_attrs;
GHashTable *num_fmts;
GOFormat *date_fmt;
@@ -212,6 +214,11 @@ typedef struct {
unsigned int field_count, record_count;
char *cache_record_part_id;
} pivot;
+
+ /* Comment state */
+ GPtrArray *authors;
+ GObject *comment;
+ GString *comment_text;
} XLSXReadState;
typedef struct {
GOString *str;
@@ -2461,7 +2468,7 @@ elem_color (GsfXMLIn *xin, xmlChar const **attrs)
{
XLSXReadState *state = (XLSXReadState *)xin->user_state;
int indx;
- GOColor c;
+ GOColor c = GO_COLOR_BLACK;
gnm_float tint = 0.;
gboolean has_color = FALSE;
@@ -4262,12 +4269,272 @@ xlsx_wb_external_ref (GsfXMLIn *xin, xmlChar const **attrs)
/**************************************************************************************************/
static void
+xlsx_run_weight (GsfXMLIn *xin, xmlChar const **attrs)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+ if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "val")) {
+ PangoAttribute *attr = pango_attr_weight_new (strcmp (attrs[1], "true")? PANGO_WEIGHT_NORMAL: PANGO_WEIGHT_BOLD);
+ if (state->run_attrs == NULL)
+ state->run_attrs = pango_attr_list_new ();
+ pango_attr_list_insert (state->run_attrs, attr);
+
+ }
+}
+
+static void
+xlsx_run_style (GsfXMLIn *xin, xmlChar const **attrs)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+ if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "val")) {
+ PangoAttribute *attr = pango_attr_style_new (strcmp (attrs[1], "true")? PANGO_STYLE_NORMAL: PANGO_STYLE_ITALIC);
+ if (state->run_attrs == NULL)
+ state->run_attrs = pango_attr_list_new ();
+ pango_attr_list_insert (state->run_attrs, attr);
+
+ }
+}
+
+static void
+xlsx_run_family (GsfXMLIn *xin, xmlChar const **attrs)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+ if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "val")) {
+ PangoAttribute *attr = pango_attr_family_new (attrs[1]);
+ if (state->run_attrs == NULL)
+ state->run_attrs = pango_attr_list_new ();
+ pango_attr_list_insert (state->run_attrs, attr);
+
+ }
+}
+
+static void
+xlsx_run_size (GsfXMLIn *xin, xmlChar const **attrs)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+ if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "val")) {
+ PangoAttribute *attr = pango_attr_size_new (atoi (attrs[1]) * PANGO_SCALE);
+ if (state->run_attrs == NULL)
+ state->run_attrs = pango_attr_list_new ();
+ pango_attr_list_insert (state->run_attrs, attr);
+
+ }
+}
+
+static void
+xlsx_run_strikethrough (GsfXMLIn *xin, xmlChar const **attrs)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+ if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "val")) {
+ PangoAttribute *attr = pango_attr_strikethrough_new (!strcmp (attrs[1], "true"));
+ if (state->run_attrs == NULL)
+ state->run_attrs = pango_attr_list_new ();
+ pango_attr_list_insert (state->run_attrs, attr);
+
+ }
+}
+
+static void
+xlsx_run_underline (GsfXMLIn *xin, xmlChar const **attrs)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+ if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "val")) {
+ PangoAttribute *attr;
+ if (!strcmp (attrs[1], "single"))
+ attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
+ else if (!strcmp (attrs[1], "singleAccounting"))
+ attr = pango_attr_underline_new (PANGO_UNDERLINE_LOW);
+ else if (!strcmp (attrs[1], "double") || !strcmp (attrs[1], "doubleAccounting"))
+ attr = pango_attr_underline_new (PANGO_UNDERLINE_DOUBLE);
+ else
+ attr = pango_attr_underline_new (PANGO_UNDERLINE_NONE);
+ if (state->run_attrs == NULL)
+ state->run_attrs = pango_attr_list_new ();
+ pango_attr_list_insert (state->run_attrs, attr);
+
+ }
+}
+
+static void
+xlsx_run_color (GsfXMLIn *xin, xmlChar const **attrs)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+ if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "rgb")) {
+ PangoAttribute *attr;
+ unsigned a, r = 0, g = 0, b = 0;
+ if (4 != sscanf (attrs[1], "%02x%02x%02x%02x", &a, &r, &g, &b)) {
+ xlsx_warning (xin,
+ _("Invalid color '%s' for attribute rgb"),
+ attrs[1]);
+ }
+ attr = pango_attr_foreground_new (r, g, b);
+ if (state->run_attrs == NULL)
+ state->run_attrs = pango_attr_list_new ();
+ pango_attr_list_insert (state->run_attrs, attr);
+
+ }
+}
+
+static void
+xlsx_comments_start (GsfXMLIn *xin, G_GNUC_UNUSED xmlChar const **attrs)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ state->authors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
+}
+
+static void
+xlsx_comments_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ g_ptr_array_unref (state->authors);
+ state->authors = NULL;
+}
+
+static void
+xlsx_comment_author_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ int i = strlen (xin->content->str);
+ char *name = xin->content->str;
+ /* remove any trailing white space */
+ /* not sure this is correct, we might be careful about encoding */
+ while (i > 0 && g_ascii_isspace (name[i-1]))
+ i--;
+ name = g_new (char, i + 1);
+ memcpy (name, xin->content->str, i);
+ name[i] = 0;
+ g_ptr_array_add (state->authors, name);
+}
+
+static void
+xlsx_comment_start (GsfXMLIn *xin, xmlChar const **attrs)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ SheetObject *so;
+ GnmRange anchor_r;
+ SheetObjectAnchor anchor;
+
+ state->comment = g_object_new (cell_comment_get_type (), NULL);
+ so = SHEET_OBJECT (state->comment);
+ anchor_r = sheet_object_get_anchor (so)->cell_bound;
+
+ for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+ if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "ref"))
+ range_parse (&anchor_r, attrs[1], gnm_sheet_get_size (state->sheet));
+ else if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_SS, "authorId")) {
+ unsigned id = atoi (attrs[1]);
+ char const *name;
+ if (id < state->authors->len) {
+ name = g_ptr_array_index (state->authors, id);
+ if (*name) /* do not set an empty name */
+ g_object_set (state->comment, "author", name, NULL);
+ }
+ }
+
+ sheet_object_anchor_init (&anchor, &anchor_r, NULL, GOD_ANCHOR_DIR_UNKNOWN);
+ sheet_object_set_anchor (so, &anchor);
+ state->comment_text = g_string_new ("");
+}
+
+static void
+xlsx_comment_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ char *text = g_string_free (state->comment_text, FALSE);
+ state->comment_text = NULL;
+ g_object_set (state->comment, "text", text, NULL);
+ g_free (text);
+ if (state->rich_attrs) {
+ g_object_set (state->comment, "markup", state->rich_attrs, NULL);
+ pango_attr_list_unref (state->rich_attrs);
+ state->rich_attrs = NULL;
+ }
+ sheet_object_set_sheet (SHEET_OBJECT (state->comment), state->sheet);
+ state->comment = NULL;
+
+}
+
+static void
+xlsx_comment_text (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ g_string_append (state->comment_text, xin->content->str);
+}
+
+static void
+xlsx_comment_rich_text (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ if (state->run_attrs) {
+ unsigned start, end;
+ start = state->comment_text->len;
+ end = start + strlen (xin->content->str);
+ if (state->rich_attrs == NULL)
+ state->rich_attrs = pango_attr_list_new ();
+ pango_attr_list_splice (state->rich_attrs, state->run_attrs, start, end);
+ pango_attr_list_unref (state->run_attrs);
+ state->run_attrs = NULL;
+ }
+ g_string_append (state->comment_text, xin->content->str);
+}
+
+static GsfXMLInNode const xlsx_comments_dtd[] = {
+GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
+GSF_XML_IN_NODE_FULL (START, COMMENTS, XL_NS_SS, "comments", GSF_XML_NO_CONTENT, TRUE, TRUE, xlsx_comments_start, xlsx_comments_end, 0),
+ GSF_XML_IN_NODE (COMMENTS, AUTHORS, XL_NS_SS, "authors", GSF_XML_NO_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (AUTHORS, AUTHOR, XL_NS_SS, "author", GSF_XML_CONTENT, NULL, xlsx_comment_author_end),
+ GSF_XML_IN_NODE (COMMENTS, COMMENTLIST, XL_NS_SS, "commentList", GSF_XML_NO_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (COMMENTLIST, COMMENT, XL_NS_SS, "comment", GSF_XML_NO_CONTENT, xlsx_comment_start, xlsx_comment_end),
+ GSF_XML_IN_NODE (COMMENT, TEXTITEM, XL_NS_SS, "text", GSF_XML_NO_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (TEXTITEM, TEXT, XL_NS_SS, "t", GSF_XML_CONTENT, NULL, xlsx_comment_text),
+ GSF_XML_IN_NODE (TEXTITEM, RICH, XL_NS_SS, "r", GSF_XML_NO_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (RICH, RICH_TEXT, XL_NS_SS, "t", GSF_XML_CONTENT, NULL, xlsx_comment_rich_text),
+ GSF_XML_IN_NODE (RICH, RICH_PROPS, XL_NS_SS, "rPr", GSF_XML_NO_CONTENT, NULL, NULL),
+#if 0
+ GSF_XML_IN_NODE (RICH_PROPS, RICH_FONT, XL_NS_SS, "font", GSF_XML_NO_CONTENT, NULL, NULL),
+ /* docs say 'font' xl is generating rFont */
+#endif
+ GSF_XML_IN_NODE (RICH_PROPS, RICH_FONT, XL_NS_SS, "rFont", GSF_XML_NO_CONTENT, NULL, NULL),
+/* Are all these really used by excel? */
+ GSF_XML_IN_NODE (RICH_PROPS, RICH_CHARSET, XL_NS_SS, "charset", GSF_XML_NO_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (RICH_PROPS, RICH_FAMILY, XL_NS_SS, "family", GSF_XML_NO_CONTENT, xlsx_run_family, NULL),
+ GSF_XML_IN_NODE (RICH_PROPS, RICH_BOLD, XL_NS_SS, "b", GSF_XML_NO_CONTENT, xlsx_run_weight, NULL),
+ GSF_XML_IN_NODE (RICH_PROPS, RICH_ITALIC, XL_NS_SS, "i", GSF_XML_NO_CONTENT, xlsx_run_style, NULL),
+ GSF_XML_IN_NODE (RICH_PROPS, RICH_STRIKE, XL_NS_SS, "strike", GSF_XML_NO_CONTENT, xlsx_run_strikethrough, NULL),
+ GSF_XML_IN_NODE (RICH_PROPS, RICH_OUTLINE, XL_NS_SS, "outline", GSF_XML_NO_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (RICH_PROPS, RICH_SHADOW, XL_NS_SS, "shadow", GSF_XML_NO_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (RICH_PROPS, RICH_CONDENSE, XL_NS_SS, "condense", GSF_XML_NO_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (RICH_PROPS, RICH_EXTEND, XL_NS_SS, "extend", GSF_XML_NO_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (RICH_PROPS, RICH_COLOR, XL_NS_SS, "color", GSF_XML_NO_CONTENT, xlsx_run_color, NULL),
+ GSF_XML_IN_NODE (RICH_PROPS, RICH_SZ, XL_NS_SS, "sz", GSF_XML_NO_CONTENT, xlsx_run_size, NULL),
+ GSF_XML_IN_NODE (RICH_PROPS, RICH_ULINE, XL_NS_SS, "u", GSF_XML_NO_CONTENT, xlsx_run_underline, NULL),
+ GSF_XML_IN_NODE (RICH_PROPS, RICH_VALIGN, XL_NS_SS, "vertAlign", GSF_XML_NO_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (RICH_PROPS, RICH_SCHEME, XL_NS_SS, "scheme", GSF_XML_NO_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (RICH, RICH_PROPS, XL_NS_SS, "rPr", GSF_XML_NO_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (TEXTITEM, ITEM_PHONETIC_RUN, XL_NS_SS, "rPh", GSF_XML_NO_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (ITEM_PHONETIC_RUN, PHONETIC_TEXT, XL_NS_SS, "t", GSF_XML_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (TEXTITEM, ITEM_PHONETIC, XL_NS_SS, "phoneticPr", GSF_XML_NO_CONTENT, NULL, NULL),
+
+GSF_XML_IN_NODE_END
+};
+
+/**************************************************************************************************/
+
+static void
xlsx_wb_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
{
XLSXReadState *state = (XLSXReadState *)xin->user_state;
int i, n = workbook_sheet_count (state->wb);
char const *part_id;
GnmStyle *style;
+ GsfInput *sin, *cin;
+ GError *err = NULL;
/* Load sheets after setting up the workbooks to give us time to create
* all of them and parse names */
@@ -4288,7 +4555,21 @@ xlsx_wb_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
sheet_style_set_range (state->sheet, &r, style);
}
- xlsx_parse_rel_by_id (xin, part_id, xlsx_sheet_dtd, xlsx_ns);
+ sin = gsf_open_pkg_open_rel_by_id (gsf_xml_in_get_input (xin), part_id, &err);
+ if (NULL != err) {
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ go_io_warning (state->context, "%s", err->message);
+ g_error_free (err);
+ err = NULL;
+ continue;
+ }
+ /* load comments */
+
+ cin = gsf_open_pkg_open_rel_by_type (sin,
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments", NULL);
+ xlsx_parse_stream (state, sin, xlsx_sheet_dtd);
+ if (cin != NULL)
+ xlsx_parse_stream (state, cin, xlsx_comments_dtd);
/* Flag a respan here in case nothing else does */
sheet_flag_recompute_spans (state->sheet);
@@ -5169,6 +5450,8 @@ xlsx_file_open (GOFileOpener const *fo, GOIOContext *context,
state.wb_view = wb_view;
state.wb = wb_view_get_workbook (wb_view);
state.sheet = NULL;
+ state.run_attrs = NULL;
+ state.rich_attrs = NULL;
state.sst = g_array_new (FALSE, TRUE, sizeof (XLSXStr));
state.shared_exprs = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free, (GDestroyNotify) gnm_expr_top_unref);
diff --git a/plugins/excel/xlsx-write.c b/plugins/excel/xlsx-write.c
index f6b371c..1b566dc 100644
--- a/plugins/excel/xlsx-write.c
+++ b/plugins/excel/xlsx-write.c
@@ -46,6 +46,7 @@
#include "print-info.h"
#include "gutils.h"
#include "sheet-object.h"
+#include "sheet-object-cell-comment.h"
#include "sheet-object-graph.h"
#include "graph.h"
@@ -71,6 +72,7 @@ static char const *ns_rel = "http://schemas.openxmlformats.org/officeDocument/2
static char const *ns_rel_hlink = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
static char const *ns_rel_draw = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing";
static char const *ns_rel_chart = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
+static char const *ns_rel_com = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
typedef struct {
XLExportBase base;
@@ -86,6 +88,7 @@ typedef struct {
unsigned int count;
GsfOutfile *dir;
} chart, drawing, pivotCache, pivotTable;
+ unsigned comment;
GOFormat *date_fmt;
} XLSXWriteState;
@@ -1242,6 +1245,145 @@ xlsx_write_objects (XLSXWriteState *state, GsfOutput *sheet_part, GSList *object
return rId;
}
+static void
+xlsx_write_rich_text (GsfXMLOut *xml, char const *text, PangoAttrList *attrs)
+{
+ PangoAttrIterator *iter = pango_attr_list_get_iterator (attrs);
+ PangoAttribute *attr;
+ int start, end, max = strlen (text);
+ char *buf;
+ do {
+ gsf_xml_out_start_element (xml, "r");
+ gsf_xml_out_start_element (xml, "rPr");
+ gsf_xml_out_start_element (xml, "rFont");
+ attr = pango_attr_iterator_get (iter, PANGO_ATTR_FAMILY);
+ gsf_xml_out_add_cstr_unchecked (xml, "val", (attr)? ((PangoAttrString *) attr)->value: "Calibri");
+ gsf_xml_out_end_element (xml); /* </rFont> */
+ gsf_xml_out_start_element (xml, "b");
+ attr = pango_attr_iterator_get (iter, PANGO_ATTR_WEIGHT);
+ gsf_xml_out_add_cstr_unchecked (xml, "val", (attr && ((PangoAttrInt *) attr)->value > PANGO_WEIGHT_NORMAL)? "true": "false");
+ gsf_xml_out_end_element (xml); /* </b> */
+ gsf_xml_out_start_element (xml, "i");
+ attr = pango_attr_iterator_get (iter, PANGO_ATTR_STYLE);
+ gsf_xml_out_add_cstr_unchecked (xml, "val", (attr && ((PangoAttrInt *) attr)->value != PANGO_STYLE_NORMAL)? "true": "false");
+ gsf_xml_out_end_element (xml); /* </i> */
+ gsf_xml_out_start_element (xml, "strike");
+ attr = pango_attr_iterator_get (iter, PANGO_ATTR_STRIKETHROUGH);
+ gsf_xml_out_add_cstr_unchecked (xml, "val", (attr && ((PangoAttrInt *) attr)->value)? "true": "false");
+ gsf_xml_out_end_element (xml); /* </strike> */
+ gsf_xml_out_start_element (xml, "color");
+ attr = pango_attr_iterator_get (iter, PANGO_ATTR_FOREGROUND);
+ if (attr) {
+ PangoColor *color = &((PangoAttrColor *) attr)->color;
+ g_strdup_printf("FF%2x%2x%2x", color->red >> 8, color->green >> 8, color->blue >> 8);
+ gsf_xml_out_add_cstr_unchecked (xml, "rgb", buf);
+ g_free (buf);
+ } else
+ gsf_xml_out_add_cstr_unchecked (xml, "rgb", "FF000000");
+ gsf_xml_out_end_element (xml); /* </color> */
+ gsf_xml_out_start_element (xml, "sz");
+ attr = pango_attr_iterator_get (iter, PANGO_ATTR_SIZE);
+ gsf_xml_out_add_uint (xml, "val", (attr)? ((PangoAttrInt *) attr)->value / PANGO_SCALE: 8);
+ gsf_xml_out_end_element (xml); /* </sz> */
+ gsf_xml_out_start_element (xml, "u");
+ attr = pango_attr_iterator_get (iter, PANGO_ATTR_UNDERLINE);
+ if (attr) {
+ PangoUnderline u = ((PangoAttrInt *) attr)->value;
+ switch (u) {
+ case PANGO_UNDERLINE_NONE:
+ default:
+ gsf_xml_out_add_cstr_unchecked (xml, "val", "none");
+ break;
+ case PANGO_UNDERLINE_ERROR: /* not supported by OpenXML */
+ case PANGO_UNDERLINE_SINGLE:
+ gsf_xml_out_add_cstr_unchecked (xml, "val", "single");
+ case PANGO_UNDERLINE_DOUBLE:
+ gsf_xml_out_add_cstr_unchecked (xml, "val", "double");
+ case PANGO_UNDERLINE_LOW:
+ gsf_xml_out_add_cstr_unchecked (xml, "val", "singleAccounting");
+ }
+ } else
+ gsf_xml_out_add_cstr_unchecked (xml, "val", "none");
+ gsf_xml_out_end_element (xml); /* </u> */
+ gsf_xml_out_end_element (xml); /* </rPr> */
+ gsf_xml_out_start_element (xml, "t");
+ gsf_xml_out_add_cstr_unchecked (xml, "xml:space", "preserve");
+ pango_attr_iterator_range (iter, &start, &end);
+ if (end > max)
+ end = max;
+ buf = g_strndup (text + start, end - start);
+ gsf_xml_out_add_cstr_unchecked (xml, NULL, buf);
+ g_free (buf);
+ gsf_xml_out_end_element (xml); /* </t> */
+ gsf_xml_out_end_element (xml); /* </r> */
+ } while (pango_attr_iterator_next (iter));
+ pango_attr_iterator_destroy (iter);
+}
+
+static void
+write_comment_author (gpointer key, G_GNUC_UNUSED gpointer value, GsfXMLOut *xml)
+{
+ gsf_xml_out_start_element (xml, "author");
+ gsf_xml_out_add_cstr_unchecked (xml, NULL, (char const *) key);
+ gsf_xml_out_end_element (xml);
+}
+
+static void
+xlsx_write_comments (XLSXWriteState *state, GsfOutput *sheet_part, GSList *objects)
+{
+ GsfXMLOut *xml;
+ GHashTable *authors;
+ unsigned author = 0;
+ char const *authorname;
+ GSList *ptr;
+ SheetObjectAnchor const *anchor;
+ PangoAttrList *attrs;
+ char *name = g_strdup_printf ("comments%u.xml", ++state->comment);
+ GsfOutput *comments_part = gsf_outfile_new_child_full (state->xl_dir, name, FALSE,
+ "content-type", "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
+ NULL);
+ g_free (name);
+ gsf_outfile_open_pkg_relate (GSF_OUTFILE_OPEN_PKG (comments_part),
+ GSF_OUTFILE_OPEN_PKG (sheet_part), ns_rel_com);
+ xml = gsf_xml_out_new (comments_part);
+ gsf_xml_out_start_element (xml, "comments");
+ gsf_xml_out_add_cstr_unchecked (xml, "xmlns", ns_ss);
+ /* search for comments authors */
+ authors = g_hash_table_new (g_str_hash, g_str_equal);
+ for (ptr = objects; ptr; ptr = ptr->next) {
+ authorname = cell_comment_author_get (CELL_COMMENT (ptr->data));
+ if (!g_hash_table_lookup_extended (authors, authorname, NULL, NULL))
+ g_hash_table_insert (authors, (gpointer) authorname, GUINT_TO_POINTER (author++));
+ }
+ /* save authors */
+ gsf_xml_out_start_element (xml, "authors");
+ g_hash_table_foreach (authors, (GHFunc) write_comment_author, xml);
+ gsf_xml_out_end_element (xml); /* </authors> */
+ /* save comments */
+ gsf_xml_out_start_element (xml, "commentList");
+ for (ptr = objects; ptr; ptr = ptr->next) {
+ gsf_xml_out_start_element (xml, "comment");
+ anchor = sheet_object_get_anchor (ptr->data);
+ gsf_xml_out_add_cstr_unchecked (xml, "ref", range_as_string (&anchor->cell_bound));
+ gsf_xml_out_add_uint (xml, "authorId", GPOINTER_TO_UINT (g_hash_table_lookup (authors, cell_comment_author_get (CELL_COMMENT (ptr->data)))));
+ gsf_xml_out_start_element (xml, "text");
+ /* Save text as rich text */
+ g_object_get (ptr->data, "text", &name, "markup", &attrs, NULL);
+ if (name && *name)
+ xlsx_write_rich_text (xml, name, attrs);
+ g_free (name);
+ pango_attr_list_unref (attrs);
+ gsf_xml_out_end_element (xml); /* </text> */
+ gsf_xml_out_end_element (xml); /* </comment> */
+ }
+ gsf_xml_out_end_element (xml); /* </commentList> */
+ g_hash_table_destroy (authors);
+ gsf_xml_out_end_element (xml); /* </comments> */
+ g_object_unref (xml);
+ gsf_output_close (comments_part);
+ g_object_unref (comments_part);
+}
+
static char const *
xlsx_write_sheet (XLSXWriteState *state, GsfOutfile *dir, GsfOutfile *wb_part, unsigned i)
{
@@ -1265,6 +1407,14 @@ xlsx_write_sheet (XLSXWriteState *state, GsfOutfile *dir, GsfOutfile *wb_part, u
MIN (XLSX_MAX_COLS, gnm_sheet_get_max_cols (state->sheet)),
MIN (XLSX_MAX_ROWS, gnm_sheet_get_max_rows (state->sheet)), state->io_context);
+/* comments */
+ charts = sheet_objects_get (state->sheet, NULL, CELL_COMMENT_TYPE);
+ if (NULL != charts) {
+ xlsx_write_comments (state, sheet_part, charts);
+ g_slist_free (charts);
+ }
+
+/* charts */
charts = sheet_objects_get (state->sheet, NULL, SHEET_OBJECT_GRAPH_TYPE);
if (NULL != charts) {
chart_drawing_rel_id = xlsx_write_objects (state, sheet_part, charts);
@@ -1357,13 +1507,14 @@ xlsx_write_sheet (XLSXWriteState *state, GsfOutfile *dir, GsfOutfile *wb_part, u
/* element extLst { CT_ExtensionList }? */
gsf_xml_out_end_element (xml); /* </worksheet> */
- state->sheet = NULL;
g_object_unref (xml);
gsf_output_close (sheet_part);
g_object_unref (sheet_part);
g_free (name);
g_free (col_styles);
+ state->sheet = NULL;
+
return rId;
}
@@ -1508,6 +1659,7 @@ xlsx_file_save (GOFileSaver const *fs, GOIOContext *io_context,
state.io_context = io_context;
state.base.wb = wb_view_get_workbook (wb_view);
+ state.comment = 0;
root_part = gsf_outfile_open_pkg_new (
gsf_outfile_zip_new (output, NULL));
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]