[gnumeric] Import some legacy drwawings from xlsx.



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]