[gnumeric] Import some legacy drwawings from xlsx.
- From: Jean Bréfort <jbrefort src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric] Import some legacy drwawings from xlsx.
- Date: Fri, 8 Apr 2011 12:38:36 +0000 (UTC)
commit 1724604f85e921beb6feabeee6f5fba25204abb4
Author: Jean Brefort <jean brefort normalesup org>
Date: Fri Apr 8 14:37:26 2011 +0200
Import some legacy drwawings from xlsx.
plugins/excel/ChangeLog | 5 +
plugins/excel/xlsx-read-drawing.c | 273 +++++++++++++++++++++++++++++++++++--
plugins/excel/xlsx-read.c | 5 +
3 files changed, 273 insertions(+), 10 deletions(-)
---
diff --git a/plugins/excel/ChangeLog b/plugins/excel/ChangeLog
index b2a47b9..a9df9dd 100644
--- a/plugins/excel/ChangeLog
+++ b/plugins/excel/ChangeLog
@@ -1,3 +1,8 @@
+2011-04-08 Jean Brefort <jean brefort normalesup org>
+
+ * xlsx-read-drawing.c: import some legacy drwawings.
+ * xlsx-read.c: ditto.
+
2011-04-04 Morten Welinder <terra gnome org>
* ms-obj.c (ms_obj_read_pre_biff8_obj): Improve record length
diff --git a/plugins/excel/xlsx-read-drawing.c b/plugins/excel/xlsx-read-drawing.c
index 307cf20..eaf8ad7 100644
--- a/plugins/excel/xlsx-read-drawing.c
+++ b/plugins/excel/xlsx-read-drawing.c
@@ -20,6 +20,8 @@
* USA
*/
+#include "sheet-object-widget.h"
+
/*****************************************************************************
* Various functions common to at least charts and user shapes *
*****************************************************************************/
@@ -1804,6 +1806,9 @@ xlsx_drawing_twoCellAnchor_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
if ((state->drawing_pos_flags & 0xFF) == 0xFF) {
SheetObjectAnchor anchor;
GnmRange r;
+ double coords[4];
+ double size;
+ int i;
range_init (&r,
state->drawing_pos[COL | FROM],
@@ -1811,10 +1816,21 @@ xlsx_drawing_twoCellAnchor_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
state->drawing_pos[COL | TO],
state->drawing_pos[ROW | TO]);
-#warning implement absolute offsets
- sheet_object_anchor_init (&anchor, &r, NULL, GOD_ANCHOR_DIR_DOWN_RIGHT);
- sheet_object_set_anchor (state->so, &anchor);
- sheet_object_set_sheet (state->so, state->sheet);
+ for (i = 0; i < 8; i+=2) {
+ ColRowInfo const *cri;
+ if (i & 1) {
+ cri = sheet_row_get (state->sheet, state->drawing_pos[i]);
+ size = cri? cri->size_pts: sheet_row_get_default_size_pts (state->sheet);
+ } else {
+ cri = sheet_col_get (state->sheet, state->drawing_pos[i]);
+ /* FIXME: scaling horizontally just like in xlsx_CT_Col */
+ size = cri? cri->size_pts: sheet_col_get_default_size_pts (state->sheet) * 1.16191275167785;
+ }
+ coords[i / 2] = (double) state->drawing_pos[i + 1] / 12700. / size;
+ }
+ sheet_object_anchor_init (&anchor, &r, coords, GOD_ANCHOR_DIR_DOWN_RIGHT);
+ sheet_object_set_anchor (state->so, &anchor);
+ sheet_object_set_sheet (state->so, state->sheet);
} else
xlsx_warning (xin,
_("Dropping object with incomplete anchor %2x"), state->drawing_pos_flags);
@@ -2147,6 +2163,243 @@ xlsx_sheet_drawing (GsfXMLIn *xin, xmlChar const **attrs)
* Legacy drawing, just need to import, but should not be exported *
******************************************************************************/
+/* define an approximate horizontal scale factor to align controls with cells */
+#define XLSX_SHEET_HSCALE 1.165
+
+static void
+xlsx_vml_group (GsfXMLIn *xin, xmlChar const **attrs)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ char **elts, **cur, *key, *value, *end;
+ double coords[4], local_coords[4], *cur_offs, dim;
+ int i;
+ for (i = 0; i < 4; i++)
+ coords[i] = local_coords[i] = 0.;
+ for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+ if (!strcmp (attrs[0], "style")) {
+ elts = g_strsplit (attrs[1], ";", 0);
+ for (cur = elts; *cur; cur++) {
+ value = strchr (*cur, ':');
+ if (!value)
+ continue; /* Hope this does not occur */
+ *value = 0;
+ value++;
+ key = *cur;
+ while (g_ascii_isspace (*key))
+ key++;
+ /* *cur is now the field name and sep is the associated value */
+ /* for now we get only left, top, width and height, assuming they are in pixels */
+ /* FIXME: scaling just like in xlsx_CT_Col */
+ if (!strcmp (key, "margin-left") || !strcmp (key, "left")) {
+ dim = g_ascii_strtod (value, &end);
+ if (!strcmp (end, "pt"))
+ dim *= 4./3.;
+ coords[0] = (double) dim * XLSX_SHEET_HSCALE;
+ } else if (!strcmp (key, "margin-top") || !strcmp (key, "top")) {
+ dim = g_ascii_strtod (value, &end);
+ if (!strcmp (end, "pt"))
+ dim *= 4./3.;
+ coords[1] = dim;
+ } else if (!strcmp (key, "width")) {
+ dim = g_ascii_strtod (value, &end);
+ if (!strcmp (end, "pt"))
+ dim *= 4./3.;
+ coords[2] = (double) dim * XLSX_SHEET_HSCALE;
+ } else if (!strcmp (key, "height")) {
+ dim = g_ascii_strtod (value, &end);
+ if (!strcmp (end, "pt"))
+ dim *= 4./3.;
+ coords[3] = dim;
+ }
+ }
+ g_strfreev (elts);
+ } else if (!strcmp (attrs[0], "coordorigin")) {
+ local_coords[0] = strtol (attrs[1], &end, 10) * XLSX_SHEET_HSCALE;
+ if (*end == ',')
+ local_coords[1] = strtol (end + 1, &end, 10);
+ } else if (!strcmp (attrs[0], "coordsize")) {
+ local_coords[2] = strtol (attrs[1], &end, 10) * XLSX_SHEET_HSCALE;
+ if (*end == ',')
+ local_coords[3] = strtol (end + 1, &end, 10);
+ }
+ /* setting the group local transform */
+ cur_offs = g_new (double, 4);
+ memcpy (cur_offs, state->grp_offset, sizeof (double) * 4);
+ state->grp_stack = g_slist_prepend (state->grp_stack, cur_offs);
+ /* evaluate new tranform */
+ if (cur_offs[2] != 0.) {
+ state->grp_offset[2] = coords[2] / local_coords[2] * cur_offs[2];
+ state->grp_offset[0] = coords[0] - local_coords[0] + cur_offs[0];
+ state->grp_offset[3] = coords[3] / local_coords[3] * cur_offs[3];
+ state->grp_offset[1] = coords[1] - local_coords[1] + cur_offs[1];
+ } else {
+ /* Not sure if the offset should be multiplied by the scale, don't do that, all known sample have unit scales */
+ state->grp_offset[2] = coords[2] / local_coords[2];
+ state->grp_offset[0] = coords[0] - local_coords[0];
+ state->grp_offset[3] = coords[3] / local_coords[3];
+ state->grp_offset[1] = coords[1] - local_coords[1];
+ }
+}
+
+static void
+xlsx_vml_group_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ /* assuming that a group can't be inside another group, otherwise we need a stack */
+ memcpy (state->grp_offset, state->grp_stack->data, sizeof (double) * 4);
+ g_free (state->grp_stack->data);
+ state->grp_stack = g_slist_delete_link (state->grp_stack, state->grp_stack);
+}
+
+static void
+xlsx_vml_shape (GsfXMLIn *xin, xmlChar const **attrs)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+ if (!strcmp (attrs[0], "style")) {
+ char **elts = g_strsplit (attrs[1], ";", 0), **cur, *key, *value, *end;
+ int dim;
+ for (cur = elts; *cur; cur++) {
+ value = strchr (*cur, ':');
+ if (!value)
+ continue; /* Hope this does not occur */
+ *value = 0;
+ value++;
+ key = *cur;
+ while (g_ascii_isspace (*key))
+ key++;
+ /* *cur is now the field name and sep is the associated value */
+ /* for now we get only left, top, width and height, assuming they are in pixels */
+ /* FIXME: scaling just like in xlsx_CT_Col */
+ if (!strcmp (key, "margin-left") || !strcmp (key, "left")) {
+ dim = g_ascii_strtod (value, &end);
+ if (!strcmp (end, "pt"))
+ dim *= 4./3.;
+ state->chart_pos[0] = (double) dim * XLSX_SHEET_HSCALE;
+ } else if (!strcmp (key, "margin-top") || !strcmp (key, "top")) {
+ dim = g_ascii_strtod (value, &end);
+ if (!strcmp (end, "pt"))
+ dim *= 4./3.;
+ state->chart_pos[1] = dim;
+ } else if (!strcmp (key, "width")) {
+ dim = g_ascii_strtod (value, &end);
+ if (!strcmp (end, "pt"))
+ dim *= 4./3.;
+ state->chart_pos[2] = (double) dim * XLSX_SHEET_HSCALE;
+ } else if (!strcmp (key, "height")) {
+ dim = g_ascii_strtod (value, &end);
+ if (!strcmp (end, "pt"))
+ dim *= 4./3.;
+ state->chart_pos[3] = dim;
+ }
+ }
+ g_strfreev (elts);
+ if (state->grp_offset[2] != 0.) {
+ state->chart_pos[0] += state->grp_offset[0];
+ state->chart_pos[1] += state->grp_offset[1];
+ state->chart_pos[2] *= state->grp_offset[2];
+ state->chart_pos[3] *= state->grp_offset[3];
+ }
+ state->chart_pos[2] += state->chart_pos[0];
+ state->chart_pos[3] += state->chart_pos[1];
+ }
+}
+
+static void
+xlsx_vml_drop_style (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ if (!strcmp (xin->content->str, "Combo"))
+ /* adding a combo box */
+ state->so = SHEET_OBJECT (g_object_new (sheet_widget_combo_get_type (), NULL));
+ sheet_object_set_sheet (state->so, state->sheet);
+}
+
+static void
+xlsx_vml_client_data (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ if (state->so) {
+ SheetObjectAnchor anchor;
+ ColRowInfo *cri;
+ GnmRange r;
+ double coords[4];
+ int default_size = sheet_col_get_default_size_pixels (state->sheet);
+ int pos, sum, size;
+ for (pos = 0, sum = 0;;pos++) {
+ cri = sheet_col_get (state->sheet, pos);
+ size = (cri)? cri->size_pixels: default_size;
+ if (sum + size > state->chart_pos[0])
+ break;
+ sum += size;
+ }
+ r.start.col = pos;
+ coords[0] = (state->chart_pos[0] - sum) / size;
+ while (sum < state->chart_pos[2]) {
+ if (sum + size > state->chart_pos[2])
+ break;
+ sum += size;
+ cri = sheet_col_get (state->sheet, pos);
+ size = (cri)? cri->size_pixels: default_size;
+ pos++;
+ }
+ r.end.col = pos;
+ coords[2] = (state->chart_pos[2] - sum) / size;
+ default_size = sheet_row_get_default_size_pixels (state->sheet);
+ for (pos = 0, sum = 0;;pos++) {
+ cri = sheet_row_get (state->sheet, pos);
+ size = (cri)? cri->size_pixels: default_size;
+ if (sum + size > state->chart_pos[1])
+ break;
+ sum += size;
+ }
+ r.start.row = pos;
+ coords[1] = (state->chart_pos[1] - sum) / size;
+ while (sum < state->chart_pos[3]) {
+ if (sum + size > state->chart_pos[3])
+ break;
+ sum += size;
+ cri = sheet_row_get (state->sheet, pos);
+ size = (cri)? cri->size_pixels: default_size;
+ pos++;
+ }
+ r.end.row = pos;
+ coords[3] = (state->chart_pos[3] - sum) / size;
+ sheet_object_anchor_init (&anchor, &r, coords, GOD_ANCHOR_DIR_DOWN_RIGHT);
+ sheet_object_set_anchor (state->so, &anchor);
+ if (GNM_IS_SOW_LIST (state->so) || GNM_IS_SOW_COMBO (state->so))
+ sheet_widget_list_base_set_links (state->so, state->link_texpr, state->texpr);
+ g_object_unref (state->so);
+ state->so = NULL;
+ }
+ if (state->texpr) {
+ gnm_expr_top_unref (state->texpr);
+ state->texpr = NULL;
+ }
+ if (state->link_texpr) {
+ gnm_expr_top_unref (state->link_texpr);
+ state->link_texpr = NULL;
+ }
+}
+
+static void
+xlsx_vml_fmla_link (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ GnmValue *value = value_new_cellrange_str (state->sheet, xin->content->str);
+ if (value)
+ state->link_texpr = gnm_expr_top_new_constant (value);
+}
+
+static void
+xlsx_vml_fmla_range (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
+{
+ XLSXReadState *state = (XLSXReadState *)xin->user_state;
+ GnmValue *value = value_new_cellrange_str (state->sheet, xin->content->str);
+ if (value)
+ state->texpr = gnm_expr_top_new_constant (value);
+}
+
static GsfXMLInNode const xlsx_legacy_drawing_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, SP_LAYOUT, XL_NS_LEG_OFF, "shapelayout", GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
@@ -2157,7 +2410,7 @@ GSF_XML_IN_NODE_FULL (START, SP_TYPE, XL_NS_LEG_VML, "shapetype", GSF_XML_NO_CON
GSF_XML_IN_NODE (SP_TYPE, PATH, XL_NS_LEG_VML, "path", GSF_XML_NO_CONTENT, NULL, NULL),
GSF_XML_IN_NODE (SP_TYPE, STROKE, XL_NS_LEG_VML, "stroke", GSF_XML_NO_CONTENT, NULL, NULL),
GSF_XML_IN_NODE (SP_TYPE, LOCK, XL_NS_LEG_OFF, "lock", GSF_XML_NO_CONTENT, NULL, NULL),
-GSF_XML_IN_NODE_FULL (START, SP, XL_NS_LEG_VML, "shape", GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
+GSF_XML_IN_NODE_FULL (START, SP, XL_NS_LEG_VML, "shape", GSF_XML_NO_CONTENT, FALSE, TRUE, &xlsx_vml_shape, NULL, 0),
GSF_XML_IN_NODE (SP, FILL, XL_NS_LEG_VML, "fill", GSF_XML_NO_CONTENT, NULL, NULL),
GSF_XML_IN_NODE (SP, PATH, XL_NS_LEG_VML, "path", GSF_XML_NO_CONTENT, NULL, NULL), /* already defined */
GSF_XML_IN_NODE (SP, SHADOW, XL_NS_LEG_VML, "shadow", GSF_XML_NO_CONTENT, NULL, NULL),
@@ -2165,16 +2418,16 @@ GSF_XML_IN_NODE_FULL (START, SP, XL_NS_LEG_VML, "shape", GSF_XML_NO_CONTENT, FAL
GSF_XML_IN_NODE (SP, TEXTBOX, XL_NS_LEG_VML, "textbox", GSF_XML_NO_CONTENT, NULL, NULL),
GSF_XML_IN_NODE (TEXTBOX, DIV, -1, "div", GSF_XML_NO_CONTENT, NULL, NULL),
GSF_XML_IN_NODE (SP, LOCK, XL_NS_LEG_OFF, "lock", GSF_XML_NO_CONTENT, NULL, NULL), /* already defined */
- GSF_XML_IN_NODE (SP, CLIENT_DATA, XL_NS_LEG_XL, "ClientData", GSF_XML_NO_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (SP, CLIENT_DATA, XL_NS_LEG_XL, "ClientData", GSF_XML_NO_CONTENT, NULL, &xlsx_vml_client_data),
GSF_XML_IN_NODE (CLIENT_DATA, ANCHOR, XL_NS_LEG_XL, "Anchor", GSF_XML_NO_CONTENT, NULL, NULL),
GSF_XML_IN_NODE (CLIENT_DATA, AUTO_FILL, XL_NS_LEG_XL, "AutoFill", GSF_XML_NO_CONTENT, NULL, NULL),
GSF_XML_IN_NODE (CLIENT_DATA, AUTO_LINE, XL_NS_LEG_XL, "AutoLine", GSF_XML_NO_CONTENT, NULL, NULL),
GSF_XML_IN_NODE (CLIENT_DATA, DROP_LINES, XL_NS_LEG_XL, "DropLines", GSF_XML_NO_CONTENT, NULL, NULL),
GSF_XML_IN_NODE (CLIENT_DATA, COLUMN, XL_NS_LEG_XL, "Column", GSF_XML_NO_CONTENT, NULL, NULL),
- GSF_XML_IN_NODE (CLIENT_DATA, DROP_STYLE, XL_NS_LEG_XL, "DropStyle", GSF_XML_NO_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (CLIENT_DATA, DROP_STYLE, XL_NS_LEG_XL, "DropStyle", GSF_XML_CONTENT, NULL, &xlsx_vml_drop_style),
GSF_XML_IN_NODE (CLIENT_DATA, DX, XL_NS_LEG_XL, "Dx", GSF_XML_NO_CONTENT, NULL, NULL),
- GSF_XML_IN_NODE (CLIENT_DATA, FMLA_LINK, XL_NS_LEG_XL, "FmlaLink", GSF_XML_NO_CONTENT, NULL, NULL),
- GSF_XML_IN_NODE (CLIENT_DATA, FMLA_RANGE, XL_NS_LEG_XL, "FmlaRange", GSF_XML_NO_CONTENT, NULL, NULL),
+ GSF_XML_IN_NODE (CLIENT_DATA, FMLA_LINK, XL_NS_LEG_XL, "FmlaLink", GSF_XML_CONTENT, NULL, &xlsx_vml_fmla_link),
+ GSF_XML_IN_NODE (CLIENT_DATA, FMLA_RANGE, XL_NS_LEG_XL, "FmlaRange", GSF_XML_CONTENT, NULL, &xlsx_vml_fmla_range),
GSF_XML_IN_NODE (CLIENT_DATA, INC, XL_NS_LEG_XL, "Inc", GSF_XML_NO_CONTENT, NULL, NULL),
GSF_XML_IN_NODE (CLIENT_DATA, LCT, XL_NS_LEG_XL, "LCT", GSF_XML_NO_CONTENT, NULL, NULL),
GSF_XML_IN_NODE (CLIENT_DATA, XMIN, XL_NS_LEG_XL, "Min", GSF_XML_NO_CONTENT, NULL, NULL),
@@ -2189,7 +2442,7 @@ GSF_XML_IN_NODE_FULL (START, SP, XL_NS_LEG_VML, "shape", GSF_XML_NO_CONTENT, FAL
GSF_XML_IN_NODE (CLIENT_DATA, SEL_TYPE, XL_NS_LEG_XL, "SelType", GSF_XML_NO_CONTENT, NULL, NULL),
GSF_XML_IN_NODE (CLIENT_DATA, SIZE_WITH_CELLS, XL_NS_LEG_XL, "SizeWithCells", GSF_XML_NO_CONTENT, NULL, NULL),
GSF_XML_IN_NODE (CLIENT_DATA, VAL, XL_NS_LEG_XL, "Val", GSF_XML_NO_CONTENT, NULL, NULL),
-GSF_XML_IN_NODE_FULL (START, GROUP, XL_NS_LEG_VML, "group", GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
+GSF_XML_IN_NODE_FULL (START, GROUP, XL_NS_LEG_VML, "group", GSF_XML_NO_CONTENT, FALSE, TRUE, &xlsx_vml_group, &xlsx_vml_group_end, 0),
GSF_XML_IN_NODE (GROUP, LOCK, XL_NS_LEG_OFF, "lock", GSF_XML_NO_CONTENT, NULL, NULL), /* already defined */
GSF_XML_IN_NODE (LOCK, SP, XL_NS_LEG_VML, "shape", GSF_XML_NO_CONTENT, NULL, NULL), /* already defined */
GSF_XML_IN_NODE (GROUP, GROUP, XL_NS_LEG_VML, "group", GSF_XML_NO_CONTENT, NULL, NULL), /* already defined */
diff --git a/plugins/excel/xlsx-read.c b/plugins/excel/xlsx-read.c
index a929e3c..e3bad14 100644
--- a/plugins/excel/xlsx-read.c
+++ b/plugins/excel/xlsx-read.c
@@ -177,7 +177,12 @@ typedef struct {
SheetObject *so;
gint64 drawing_pos[8];
int drawing_pos_flags;
+ GnmExprTop const *link_texpr;
+ /* Legacy drawing state */
+ double grp_offset[4];
+ GSList *grp_stack;
+
/* Charting state */
GogGraph *graph;
GogChart *chart;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]