--- openoffice-read.c	2006-01-24 22:48:05.000000000 -0300
+++ openoffice-read.c	2006-01-26 10:46:57.103143944 -0300
@@ -56,6 +56,13 @@
 #include <string.h>
 #include <locale.h>
 
+#include <goffice/graph/gog-chart.h>
+#include <goffice/graph/gog-plot-impl.h>
+#include <goffice/data/go-data-simple.h>
+#include <sheet-object-graph.h>
+#include <sheet-object-image.h>
+#include <graph.h>
+
 GNM_PLUGIN_MODULE_HEADER;
 
 /* Filter Type */
@@ -73,6 +80,20 @@ typedef enum {
 #define OD_BORDER_THICK		5
 
 typedef enum {
+	AREA,
+	BAR,
+	LINE,
+	CIRCLE,
+	RADAR,
+	RADARAREA,
+	RING,
+	SCATTER,
+	STOCK,
+	SURF,
+	UNKNOWN
+} ODChartType;
+
+typedef enum {
 	OO_STYLE_UNKNOWN,
 	OO_STYLE_CELL,
 	OO_STYLE_COL,
@@ -80,14 +101,41 @@ typedef enum {
 	OO_STYLE_SHEET,
 	OO_STYLE_GRAPHICS,
 	OO_STYLE_PARAGRAPH,
+	OO_STYLE_CHART,
 	OO_STYLE_TEXT
 } OOStyleType;
 
 typedef struct {
+	char *name;
+	GValue *value;
+} ODProps; //struct to hold the args of g_object_set function
+
+typedef struct {
+	gboolean grid; //graph has grid?
+	gboolean row_src; //orientation of graph data: rows or columns
+	GSList *axis; //axis properties
+	GSList *chart; //chart properties
+} ODGraphProperties;
+
+typedef struct {
+	GogGraph *graph; //current graph
+	ODGraphProperties *cur_graph_style;
+	GHashTable *graph_styles; //contain links to ODGraphProperties GSLists
+	GogChart *chart; //current chart
+	ODChartType chart_type;
+	SheetObjectAnchor anchor; //anchor to draw the frame to images or graphs
+	gboolean has_legend;
+	GogObjectPosition legend;
+	GogAxisType cur_axe;
+} ODFrameProperties;
+
+typedef struct {
 	IOContext 	*context;	/* The IOcontext managing things */
 	WorkbookView	*wb_view;	/* View for the new workbook */
 	OOVer		 ver;
-
+	GsfInfile	*zip;	/* Reference to the open file, to load graphs and images*/
+	GSList	*col_styles[2];
+	ODFrameProperties cur_frame;
 	GnmParsePos 	pos;
 
 	int 		 col_inc, row_inc;
@@ -113,6 +161,10 @@ typedef struct {
 	GnmExprConventions *exprconv;
 } OOParseState;
 
+static GsfXMLInNode const opendoc_content_dtd [];
+void clean_lists(ODGraphProperties *pointer);
+ODProps *dup_prop(ODProps *pointer);
+
 static gboolean oo_warning (GsfXMLIn *xin, char const *fmt, ...)
 	G_GNUC_PRINTF (2, 3);
 
@@ -211,15 +263,19 @@ static GnmColor *
 oo_parse_color (GsfXMLIn *xin, xmlChar const *str, char const *name)
 {
 	guint r, g, b;
+	GnmColor *no_color;
 
 	g_return_val_if_fail (str != NULL, NULL);
 
 	if (3 == sscanf (str, "#%2x%2x%2x", &r, &g, &b))
 		return style_color_new_i8 (r, g, b);
 
-	if (0 == strcmp (str, "transparent"))
-		return NULL;
-
+	if (0 == strcmp (str, "transparent")) {
+		no_color = style_color_auto_back ();
+		no_color->name = g_new (gchar, 1);
+		no_color->name = g_strdup ("transparent");
+		return no_color;
+	}
 	oo_warning (xin, "Invalid attribute '%s', expected color, received '%s'",
 		    name, str);
 	return NULL;
@@ -389,21 +445,16 @@ oo_col_start (GsfXMLIn *xin, xmlChar con
 
 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
 		if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_TABLE, "default-cell-style-name"))
-			style = g_hash_table_lookup (state->cell_styles, attrs[1]);
-		else if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_TABLE, "style-name"))
+		{
+			style = g_hash_table_lookup (state->cell_styles, (const gchar*)attrs[1]);
+			state->col_styles[0] = g_slist_append (state->col_styles[0], g_strdup(attrs[1]));
+		} else if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_TABLE, "style-name"))
 			width_pts = g_hash_table_lookup (state->col_row_styles, attrs[1]);
 		else if (oo_attr_int (xin, attrs, OO_NS_TABLE, "number-columns-repeated", &repeat_count))
 			;
 
-	if (NULL != style) {
-		GnmRange r;
-		r.start.col = state->pos.eval.col;
-		r.end.col   = state->pos.eval.col + repeat_count - 1;
-		r.start.row = 0;
-		r.end.row  = SHEET_MAX_ROWS - 1;
-		gnm_style_ref (style);
-		sheet_style_set_range (state->pos.sheet, &r, style);
-	}
+	state->col_styles[1] = g_slist_append (state->col_styles[1], (int *)repeat_count);
+	
 	while (repeat_count-- > 0) {
 		if (width_pts != NULL)
 			sheet_col_set_size_pts (state->pos.sheet,
@@ -525,11 +576,12 @@ oo_cell_start (GsfXMLIn *xin, xmlChar co
 	GnmExpr const	*expr = NULL;
 	GnmValue		*val = NULL;
 	gboolean	 bool_val;
-	gnm_float	 float_val;
+	gnm_float	 float_val = 0;
 	int array_cols = -1, array_rows = -1;
 	int merge_cols = -1, merge_rows = -1;
 	GnmStyle *style = NULL;
 	char const *expr_string;
+	GList *search_str = NULL;
 
 	state->col_inc = 1;
 	state->error_content = FALSE;
@@ -564,7 +616,7 @@ oo_cell_start (GsfXMLIn *xin, xmlChar co
 				GnmParseError  perr;
 				parse_error_init (&perr);
 				expr = oo_expr_parse_str (expr_string,
-					&state->pos, 0, &perr);
+					&state->pos, GNM_EXPR_PARSE_DEFAULT, &perr);
 				if (expr == NULL) {
 					g_print ("s=[%s]\n", expr_string);
 					g_print ("e=[%s]\n", perr.err->message);
@@ -630,11 +682,49 @@ oo_cell_start (GsfXMLIn *xin, xmlChar co
 				state->pos.eval.col + state->col_inc - 1,
 				state->pos.eval.row + state->row_inc - 1);
 			sheet_style_set_range (state->pos.sheet, &tmp, style);
+		} else if (merge_cols > 0 || merge_rows > 0) {
+			GnmRange tmp;
+			range_init (&tmp,
+				state->pos.eval.col, state->pos.eval.row,
+				state->pos.eval.col + merge_cols - 1,
+				state->pos.eval.row + merge_rows - 1);
+			sheet_style_set_range (state->pos.sheet, &tmp, style);
 		} else
 			sheet_style_set_pos (state->pos.sheet,
 				state->pos.eval.col, state->pos.eval.row,
 				style);
+	} else {
+		int cont_col, sum_cols, cont, cur_col=0;
+		
+		for (cont_col = 0; cont_col < state->col_inc; cont_col++) {
+			cur_col = (state->pos.eval.col)+cont_col;
+			sum_cols = -1;
+			cont = 0;
+			while (sum_cols < cur_col){
+				sum_cols += (int)(g_list_nth((GList *)state->col_styles[1], cont)->data);
+				cont ++;
+			}
+			
+			search_str = g_list_nth((GList *)state->col_styles[0], cont - 1);
+
+			if (NULL != search_str){
+				style = g_hash_table_lookup (state->cell_styles, search_str->data);
+				gnm_style_ref (style);
+				if (state->row_inc > 1){
+					GnmRange style_range;
+					range_init (&style_range,
+						state->pos.eval.col+cont_col, state->pos.eval.row,
+						state->pos.eval.col+cont_col,
+						state->pos.eval.row + state->row_inc - 1);
+					sheet_style_set_range (state->pos.sheet, &style_range, style);
+				} else
+					sheet_style_set_pos (state->pos.sheet,
+						state->pos.eval.col+cont_col, state->pos.eval.row,
+						style);
+			}
+		}
 	}
+	
 	state->simple_content = FALSE;
 	if (expr != NULL) {
 		GnmCell *cell = sheet_cell_fetch (state->pos.sheet,
@@ -768,6 +858,8 @@ oo_style (GsfXMLIn *xin, xmlChar const *
 		{ "graphics",	  OO_STYLE_GRAPHICS },
 		{ "paragraph",	  OO_STYLE_PARAGRAPH },
 		{ "text",	  OO_STYLE_TEXT },
+		{ "chart",	  OO_STYLE_CHART },
+		{ "graphic",	  OO_STYLE_GRAPHICS },
 		{ NULL,	0 },
 	};
 
@@ -777,6 +869,7 @@ oo_style (GsfXMLIn *xin, xmlChar const *
 	GnmStyle *style;
 	GOFormat *fmt = NULL;
 	int tmp;
+	ODGraphProperties *cur_style;
 
 	g_return_if_fail (state->cur_style_type == OO_STYLE_UNKNOWN);
 
@@ -824,7 +917,19 @@ oo_style (GsfXMLIn *xin, xmlChar const *
 					      g_strdup (name),
 					      state->cur_style.col_row);
 		break;
-
+	
+	case OO_STYLE_CHART:
+		if (name != NULL){
+			cur_style = g_new0(ODGraphProperties, 1);
+			cur_style->axis = NULL;
+			cur_style->chart = NULL;
+			state->cur_frame.cur_graph_style = cur_style;
+			state->cur_frame.chart_type = UNKNOWN;
+			g_hash_table_replace (state->cur_frame.graph_styles,
+					      g_strdup (name),
+					      state->cur_frame.cur_graph_style);
+		}
+		break;
 	default:
 		break;
 	}
@@ -841,6 +946,8 @@ oo_style_end (GsfXMLIn *xin, G_GNUC_UNUS
 	case OO_STYLE_COL : 
 	case OO_STYLE_ROW : state->cur_style.col_row = NULL;
 		break;
+	case OO_STYLE_CHART : state->cur_frame.cur_graph_style = NULL;
+		break;
 
 	default :
 		break;
@@ -1089,7 +1196,13 @@ oo_style_prop_cell (GsfXMLIn *xin, xmlCh
 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
 		if ((color = oo_attr_color (xin, attrs, OO_NS_FO, "background-color"))) {
 			gnm_style_set_back_color (style, color);
-			gnm_style_set_pattern (style, 1);
+			if (color->name != NULL){
+				if (!strcmp (color->name, "transparent")) {
+					gnm_style_set_pattern (style, 0);
+					g_free (color->name);
+				}
+			} else
+				gnm_style_set_pattern (style, 1);		
 		} else if ((color = oo_attr_color (xin, attrs, OO_NS_FO, "color")))
 			gnm_style_set_font_color (style, color);
 		else if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_STYLE, "cell-protect"))
@@ -1197,6 +1310,83 @@ oo_style_map (GsfXMLIn *xin, xmlChar con
 			;
 }
 
+ODProps *dup_prop(ODProps *pointer) {
+	ODProps *prop_copy = g_new0(ODProps, 1);
+
+	prop_copy->name = strdup (pointer->name);
+	prop_copy->value = g_new0 (GValue, 1);
+	prop_copy->value = g_value_init (prop_copy->value, G_VALUE_TYPE(pointer->value));
+	g_value_copy (pointer->value, prop_copy->value);
+
+	return prop_copy;
+}
+
+static void
+od_style_prop_chart (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	OOParseState *state = (OOParseState *)xin->user_state;
+	ODGraphProperties *style = state->cur_frame.cur_graph_style;
+	ODProps *prop = NULL;
+
+	g_return_if_fail (style != NULL);
+
+	style->grid = FALSE;
+	style->row_src = FALSE;
+	
+	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
+		prop = g_new0 (ODProps, 1);
+		prop->value = g_new0 (GValue, 1);
+		if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_CHART, "logarithmic")) {
+			if (!strcmp(attrs[1], "true")){
+				prop->name = strdup ("map-name");
+				prop->value = g_value_init (prop->value, G_TYPE_STRING);
+				g_value_set_string (prop->value, "Log");
+				style->axis = g_slist_append (style->axis, dup_prop(prop));
+			}
+		} else if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_CHART, "vertical")) {
+			if (!strcmp(attrs[1], "true")){
+				prop->name = strdup ("horizontal");
+				prop->value = g_value_init (prop->value, G_TYPE_BOOLEAN);
+				g_value_set_boolean (prop->value, TRUE);
+				style->chart = g_slist_append (style->chart, dup_prop(prop));
+			}
+		} else if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_CHART, "stacked")) {
+			if (!strcmp(attrs[1], "true")){
+				prop->name = strdup ("type");
+				prop->value = g_value_init (prop->value, G_TYPE_STRING);
+				g_value_set_string (prop->value, strdup("stacked"));
+				style->chart = g_slist_append (style->chart, dup_prop(prop));
+			}
+		} else if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_CHART, "percentage")) {
+			if (!strcmp(attrs[1], "true")){
+				prop->name = strdup ("type");
+				prop->value = g_value_init (prop->value, G_TYPE_STRING);
+				g_value_set_string (prop->value, strdup("as_percentage"));
+				style->chart = g_slist_append (style->chart, dup_prop(prop));
+			}
+		} else if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_CHART, "overlap")) {
+				prop->name = strdup ("overlap-percentage");
+				prop->value = g_value_init (prop->value, G_TYPE_INT);
+				g_value_set_int (prop->value, g_strtod(attrs[1], NULL));
+				style->chart = g_slist_append (style->chart, dup_prop(prop));
+		} else if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_CHART, "gap-width")) {
+				prop->name = strdup ("gap-percentage");
+				prop->value = g_value_init (prop->value, G_TYPE_INT);
+				g_value_set_int (prop->value, g_strtod(attrs[1], NULL));
+				style->chart = g_slist_append (style->chart, dup_prop(prop));
+		} else if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_CHART, "series-source")) {
+			if (!strcmp(attrs[1], "rows"))
+				style->row_src = TRUE;
+		}
+		if (G_IS_VALUE (prop->value)) {
+			g_value_unset (prop->value);
+			g_free (prop->name);
+		} else
+			g_free (prop->value);
+		g_free (prop);
+	}
+}
+
 static void
 oo_style_prop (GsfXMLIn *xin, xmlChar const **attrs)
 {
@@ -1205,12 +1395,12 @@ oo_style_prop (GsfXMLIn *xin, xmlChar co
 	case OO_STYLE_CELL : oo_style_prop_cell (xin, attrs); break;
 	case OO_STYLE_COL :  oo_style_prop_col (xin, attrs); break;
 	case OO_STYLE_ROW :  oo_style_prop_row (xin, attrs); break;
+	case OO_STYLE_CHART :  od_style_prop_chart (xin, attrs); break;
 
 	default :
 		break;
 	}
 }
-
 static void
 oo_named_expr (GsfXMLIn *xin, xmlChar const **attrs)
 {
@@ -1272,6 +1462,423 @@ oo_named_range (GsfXMLIn *xin, xmlChar c
 	g_warning ("Unimplemented");
 }
 
+static void
+od_draw_frame (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	OOParseState *state = (OOParseState *)xin->user_state;
+	GnmRange cell_base;
+	float frame_offset [4];
+	char const* aux = NULL;
+	double height, width, x, y;
+	ColRowInfo const *col, *row;
+
+	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2){
+		if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_SVG, "width"))
+			aux = oo_parse_distance (xin, attrs[1], "width", &width);
+		if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_SVG, "height"))
+			aux = oo_parse_distance (xin, attrs[1], "height", &height);
+		if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_SVG, "x"))
+			aux = oo_parse_distance (xin, attrs[1], "x", &x);
+		if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_TABLE, "y"))
+			aux = oo_parse_distance (xin, attrs[1], "y", &y);
+	}
+	cell_base.start.col = cell_base.end.col = state->pos.eval.col;
+	cell_base.start.row = cell_base.end.row = state->pos.eval.row;
+
+	col = sheet_col_get_info (state->pos.sheet, state->pos.eval.col);
+	row = sheet_row_get_info (state->pos.sheet, state->pos.eval.row);
+	
+	frame_offset[0] = (x/col->size_pts);
+	frame_offset[1] = (y/row->size_pts);
+	frame_offset[2] = (width/col->size_pts);
+	frame_offset[3] = (height/row->size_pts);
+
+	sheet_object_anchor_init (&state->cur_frame.anchor, &cell_base, frame_offset, NULL, SO_DIR_DOWN_RIGHT);
+}
+
+static void
+od_draw_object (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	OOParseState *state = (OOParseState *)xin->user_state;
+	char *name = NULL;
+	GsfInput	*content = NULL;
+	GsfXMLInDoc	*doc = NULL;
+	SheetObject *sog = sheet_object_graph_new (NULL);
+	
+	state->cur_frame.graph = sheet_object_graph_get_gog (sog);
+	sheet_object_set_anchor (sog, &state->cur_frame.anchor);
+	sheet_object_set_sheet (sog, state->pos.sheet);
+	g_object_unref (sog);
+
+	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+		if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_XLINK, "href"))
+			name = (char *)attrs[1]+2;//removes the "./"
+			
+	content = gsf_infile_child_by_vname (state->zip, name, "content.xml", NULL);
+
+	if (content != NULL) {
+		doc  = gsf_xml_in_doc_new (opendoc_content_dtd, gsf_ooo_ns);
+		gsf_xml_in_doc_parse (doc, content, state);
+	}
+	gsf_xml_in_doc_free (doc);
+	g_object_unref (G_OBJECT (content));
+
+	g_hash_table_destroy (state->cur_frame.graph_styles);
+	state->cur_frame.graph_styles = g_hash_table_new_full (g_str_hash, g_str_equal,
+															(GDestroyNotify) g_free,
+															(GDestroyNotify) clean_lists);
+	state->cur_frame.has_legend = FALSE;
+}
+
+static void
+od_draw_image (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	GsfInput *input;
+
+	OOParseState *state = (OOParseState *)xin->user_state;
+	char *file = NULL;
+
+	SheetObjectImage *soi;
+	SheetObject *so;
+
+	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+		if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_XLINK, "href"))
+			file = (char *)attrs[1]+9;//removes the "Pictures/"
+
+	input = gsf_infile_child_by_vname (state->zip, "Pictures", file, NULL);
+
+	if (input != NULL) {
+		unsigned len = gsf_input_size (input);
+		guint8 const *data = gsf_input_read (input, len, NULL);
+		soi = g_object_new (SHEET_OBJECT_IMAGE_TYPE, NULL);
+		sheet_object_image_set_image (soi, "", (guint8 *)data, len, TRUE);
+
+		so = SHEET_OBJECT (soi);
+		sheet_object_set_anchor (so, &state->cur_frame.anchor);
+		sheet_object_set_sheet (so, state->pos.sheet);
+		g_object_unref (input);
+	}
+}
+
+static void
+od_chart_title (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
+{
+	GogObject *label = NULL;
+	OOParseState *state = (OOParseState *)xin->user_state;
+
+	label = gog_object_add_by_name ((GogObject *)state->cur_frame.chart, "Title", NULL);
+	gog_dataset_set_dim (GOG_DATASET (label), 0, go_data_scalar_str_new (strdup(xin->content->str), FALSE), NULL);
+}
+
+static void
+od_chart_axis (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	char *name = NULL;
+	OOParseState *state = (OOParseState *)xin->user_state;
+	ODGraphProperties *style = NULL;
+	GSList *axis;
+	int cont;
+	ODProps *axis_props;
+	GSList *plots;
+	GogPlot *plot;
+
+	state->cur_frame.cur_axe = GOG_AXIS_UNKNOWN;
+	
+	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2) {
+		if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_CHART, "style-name"))
+			name = (char *)attrs[1];
+		if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_CHART, "dimension")) {
+			if (!strcmp(attrs[1],"x"))
+				state->cur_frame.cur_axe = GOG_AXIS_X;
+			else
+				state->cur_frame.cur_axe = GOG_AXIS_Y;
+		}
+	}
+	style = g_hash_table_lookup (state->cur_frame.graph_styles, name);
+	axis = gog_chart_get_axes (state->cur_frame.chart, state->cur_frame.cur_axe);
+	for (cont = 0; cont < (int)g_slist_length(style->axis); cont ++) {
+		axis_props = g_slist_nth_data(style->axis, cont);
+		g_object_set (axis->data,
+				axis_props->name,
+				g_value_get_string(axis_props->value),
+				NULL);
+	}
+	plots = gog_chart_get_plots (state->cur_frame.chart);
+	plot = g_slist_nth_data (plots, 0);
+	for (cont = 0; cont < (int)g_slist_length(style->chart); cont ++) {
+		axis_props = g_slist_nth_data(style->chart, cont);
+		switch (G_VALUE_TYPE(axis_props->value)) {
+			case G_TYPE_BOOLEAN:
+				g_object_set (plot,
+						strdup(axis_props->name),
+						g_value_get_boolean (axis_props->value),
+						NULL);
+				break;
+			case G_TYPE_STRING:
+				g_object_set (plot,
+						strdup(axis_props->name),
+						strdup(g_value_get_string (axis_props->value)),
+						NULL);
+				break;
+			case G_TYPE_INT:
+				g_object_set (plot,
+						axis_props->name,
+						g_value_get_int (axis_props->value),
+						NULL);
+				break;
+			default: break;
+		}
+	}
+}
+
+static void
+od_plot_area(GsfXMLIn *xin, xmlChar const **attrs){
+	OOParseState *state = (OOParseState *)xin->user_state;
+	char *graph_range = NULL;
+	GnmValue *actual_range;
+	GogSeries *series;
+	GnmRange cell_base;
+	GogPlot   *plot;
+	GnmParseError  perr;
+	GnmExpr const	*expr = NULL;
+	int cur_col, dim, flag=0;
+	int MAX_DIM = 2;
+	int v_offset = 0, h_offset = 0;
+
+	char *name = NULL;
+	ODGraphProperties *style = NULL;
+	int cont;
+	ODProps *chart_props;
+	GogObject *legend;
+
+	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+		if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_CHART, "style-name")) {
+			name = (char *)attrs[1];
+			style = g_hash_table_lookup (state->cur_frame.graph_styles, name);
+		} else if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_TABLE, "cell-range-address"))
+			graph_range = g_strdup_printf("[%s]",attrs[1]);
+		else if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_CHART, "data-source-has-labels")) {
+			if (!strcmp(attrs[1], "both"))
+				v_offset = h_offset = 1;
+			else if (!strcmp(attrs[1], "column"))
+				h_offset = 1;
+			else if (!strcmp(attrs[1], "row"))
+				v_offset = 1;
+		}
+	flag = !(v_offset || h_offset);
+
+	switch (state->cur_frame.chart_type){
+		case AREA:
+				plot = gog_plot_new_by_name ("GogAreaPlot");
+				break;
+		case BAR:
+				plot = gog_plot_new_by_name ("GogBarColPlot");
+				break;
+		case CIRCLE:
+				plot = gog_plot_new_by_name ("GogPiePlot");
+				break;
+		case LINE:
+				plot = gog_plot_new_by_name ("GogLinePlot");
+				break;
+		case RADAR:
+				plot = gog_plot_new_by_name ("GogRadarPlot");
+				flag = 1;
+				break;
+		case RADARAREA:
+				plot = gog_plot_new_by_name ("GogRadarAreaPlot");
+				break;
+		case RING:
+				plot = gog_plot_new_by_name ("GogRingPlot");
+				break;
+		case SCATTER:
+				plot = gog_plot_new_by_name ("GogXYPlot");
+				flag = 0;
+				break;
+		case STOCK:
+				plot = gog_plot_new_by_name ("GogMinMaxPlot");
+				MAX_DIM = 3;
+				break;
+		case SURF:
+				plot = gog_plot_new_by_name ("GogContourPlot");
+				break;
+		default: return;
+	}
+	for (cont = 0; cont < (int)g_slist_length(style->chart); cont ++){
+		chart_props = g_slist_nth_data(style->chart, cont);
+		switch (G_VALUE_TYPE(chart_props->value)) {
+			case G_TYPE_BOOLEAN:
+				g_object_set (plot,
+						strdup(chart_props->name),
+						g_value_get_boolean (chart_props->value),
+						NULL);
+				break;
+			case G_TYPE_STRING:
+				g_object_set (plot,
+						strdup(chart_props->name),
+						strdup(g_value_get_string (chart_props->value)),
+						NULL);
+				break;
+			case G_TYPE_INT:
+				g_object_set (plot,
+						strdup(chart_props->name),
+						g_value_get_int (chart_props->value),
+						NULL);
+				break;
+			default: break;
+		}
+	}
+
+	gog_object_add_by_name ((GogObject *)state->cur_frame.chart, "Plot", GOG_OBJECT (plot));
+	parse_error_init (&perr);
+	expr = oo_expr_parse_str (graph_range, &state->pos, 0, &perr);
+	if (expr == NULL) {
+		oo_warning (xin, _("Unable to parse '%s' because '%s'"),
+				    attrs[1], perr.err->message);
+		parse_error_free (&perr);
+	}
+	actual_range = gnm_expr_get_range (expr);
+	cur_col = actual_range->v_range.cell.a.col;
+
+	cell_base.start.row = actual_range->v_range.cell.a.row + v_offset;
+	cell_base.end.row = actual_range->v_range.cell.b.row;
+	do {
+		series = gog_plot_new_series (plot);
+		dim = flag;
+
+		if (flag) {
+			cell_base.start.col = cur_col;
+			cell_base.end.col = cur_col;
+		} else {
+			cell_base.start.col = actual_range->v_range.cell.a.col;
+			cell_base.end.col = actual_range->v_range.cell.a.col;
+		}
+		while (dim < MAX_DIM){
+			gog_series_set_dim (series, dim,
+							gnm_go_data_vector_new_expr (state->pos.sheet,
+							gnm_expr_new_constant (
+							value_new_cellrange_r (state->pos.sheet, &cell_base))), NULL);
+			cell_base.start.col = cell_base.end.col = cur_col + 1;// + h_offset;
+			dim++;
+		}
+		cur_col++;
+	} while (cur_col < actual_range->v_range.cell.b.col+flag);
+	
+	if (state->cur_frame.has_legend){
+		legend = gog_object_add_by_name ((GogObject *)state->cur_frame.chart, "Legend", NULL);
+		gog_object_set_position_flags (legend, state->cur_frame.legend, GOG_POSITION_COMPASS | GOG_POSITION_ALIGNMENT);
+	}		
+	value_release (actual_range);
+	g_free (graph_range);
+	gnm_expr_unref (expr);
+}
+
+static void
+od_chart (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	OOParseState *state = (OOParseState *)xin->user_state;
+	char *chart_type = NULL;
+
+	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+		if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_CHART, "class"))
+			chart_type = (char *)attrs[1]+6;//removes the "chart:"
+
+	if (!strcmp(chart_type, "area"))
+		state->cur_frame.chart_type = AREA;
+	else if (!strcmp(chart_type, "bar"))
+		state->cur_frame.chart_type = BAR;
+	else if (!strcmp(chart_type, "circle"))
+		state->cur_frame.chart_type = CIRCLE;
+	else if (!strcmp(chart_type, "line"))
+		state->cur_frame.chart_type = LINE;
+	else if (!strcmp(chart_type, "radar"))
+		state->cur_frame.chart_type = RADAR;
+	else if (!strcmp(chart_type, "ring"))
+		state->cur_frame.chart_type = RING;
+	else if (!strcmp(chart_type, "scatter"))
+		state->cur_frame.chart_type = SCATTER;
+	else if (!strcmp(chart_type, "stock"))
+		state->cur_frame.chart_type = STOCK;
+
+	state->cur_frame.chart = GOG_CHART (gog_object_add_by_name ((GogObject *)state->cur_frame.graph, "Chart", NULL));
+}
+
+static void
+od_legend (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	OOParseState *state = (OOParseState *)xin->user_state;
+
+	state->cur_frame.has_legend = TRUE;
+	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+		if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_CHART, "legend-position")) {
+			if (!strcmp (attrs[1], "top"))
+				state->cur_frame.legend = GOG_POSITION_N | GOG_POSITION_ALIGN_CENTER;
+			else if (!strcmp (attrs[1], "bottom"))
+				state->cur_frame.legend = GOG_POSITION_S | GOG_POSITION_ALIGN_CENTER;
+			else if (!strcmp (attrs[1], "end"))
+				state->cur_frame.legend = GOG_POSITION_E | GOG_POSITION_ALIGN_CENTER;
+			else
+				state->cur_frame.legend = GOG_POSITION_W | GOG_POSITION_ALIGN_CENTER;
+		}
+}
+
+static void
+od_chart_grid (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	OOParseState *state = (OOParseState *)xin->user_state;
+	GSList *axis = NULL;
+
+	if ((state->cur_frame.cur_axe != UNKNOWN) &&
+	 	(state->cur_frame.chart_type != RING) && 
+	 	(state->cur_frame.chart_type != CIRCLE) &&
+	 	(state->cur_frame.chart_type != RADAR)) {
+
+		axis = gog_chart_get_axes (state->cur_frame.chart, state->cur_frame.cur_axe);
+		for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+			if (gsf_xml_in_namecmp (xin, attrs[0], OO_NS_CHART, "class"))
+				if (!strcmp(attrs[1], "major"))
+					gog_object_add_by_name ((GogObject *)axis->data, "MajorGrid", NULL);
+				else if (!strcmp(attrs[1], "minor"))
+					gog_object_add_by_name ((GogObject *)axis->data, "MinorGrid", NULL);
+	}
+}
+
+static void
+od_chart_wall (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	OOParseState *state = (OOParseState *)xin->user_state;
+
+	gog_object_add_by_name ((GogObject *)state->cur_frame.chart, "Grid", NULL);
+}
+
+void
+clean_lists(ODGraphProperties *pointer){
+	int cont;
+	ODProps *pointer_props = NULL;
+
+	if ((int)g_slist_length(pointer->axis)) {
+		for (cont = 0; cont < (int)g_slist_length(pointer->axis); cont ++){
+			pointer_props = (ODProps *)g_slist_nth_data (pointer->axis, cont);
+			g_free(pointer_props->name);
+			if (G_IS_VALUE (pointer_props->value))
+				g_value_unset(pointer_props->value);
+			else
+				g_free (pointer_props->value);
+		}
+		g_slist_free (pointer->axis);
+	}
+	if ((int)g_slist_length(pointer->chart)) {
+		for (cont = 0; cont < (int)g_slist_length(pointer->chart); cont ++){
+			pointer_props = (ODProps *)g_slist_nth_data (pointer->chart, cont);
+			g_free(pointer_props->name);
+			if (G_IS_VALUE (pointer_props->value))
+				g_value_unset(pointer_props->value);
+			else
+				g_free (pointer_props->value);
+		}
+		g_slist_free (pointer->chart);
+	}
+}
+
 static GsfXMLInNode const styles_dtd[] = {
 GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
 
@@ -1491,6 +2098,7 @@ static GsfXMLInNode const opendoc_conten
 	      GSF_XML_IN_NODE (STYLE, TABLE_CELL_PROPS, OO_NS_STYLE, "table-cell-properties", GSF_XML_NO_CONTENT, &oo_style_prop, NULL),
 	      GSF_XML_IN_NODE (STYLE, TABLE_COL_PROPS, OO_NS_STYLE, "table-column-properties", GSF_XML_NO_CONTENT, &oo_style_prop, NULL),
 	      GSF_XML_IN_NODE (STYLE, TABLE_ROW_PROPS, OO_NS_STYLE, "table-row-properties", GSF_XML_NO_CONTENT, &oo_style_prop, NULL),
+	      GSF_XML_IN_NODE (STYLE, CHART_PROPS, OO_NS_STYLE, "chart-properties", GSF_XML_NO_CONTENT, &oo_style_prop, NULL),
 	      GSF_XML_IN_NODE (STYLE, TEXT_PROPS, OO_NS_STYLE, "text-properties", GSF_XML_NO_CONTENT, &oo_style_prop, NULL),
 	      GSF_XML_IN_NODE (STYLE, TABLE_PROPS, OO_NS_STYLE, "table-properties", GSF_XML_NO_CONTENT, &oo_style_prop, NULL),
 	      GSF_XML_IN_NODE (STYLE, PARAGRAPH_PROPS, OO_NS_STYLE, "paragraph-properties", GSF_XML_NO_CONTENT, &oo_style_prop, NULL),
@@ -1545,16 +2153,35 @@ static GsfXMLInNode const opendoc_conten
 	GSF_XML_IN_NODE (OFFICE, OFFICE_BODY, OO_NS_OFFICE, "body", GSF_XML_NO_CONTENT, NULL, NULL),
 	  GSF_XML_IN_NODE (OFFICE_BODY, TABLE_SETTINGS, OO_NS_OFFICE, "spreadsheet", GSF_XML_NO_CONTENT, NULL, NULL),
 	    GSF_XML_IN_NODE (TABLE_SETTINGS, CALC_SETTINGS, OO_NS_TABLE, "calculation-settings", GSF_XML_NO_CONTENT, NULL, NULL),
+		GSF_XML_IN_NODE (TABLE_SETTINGS, CHART, OO_NS_CHART, "chart", FALSE, NULL, NULL),			
+
+		GSF_XML_IN_NODE (OFFICE_BODY, OFFICE_CHART, OO_NS_OFFICE, "chart", FALSE, NULL, NULL),
+		GSF_XML_IN_NODE (OFFICE_CHART, CHART_CHART, OO_NS_CHART, "chart", FALSE, &od_chart, NULL),
+		GSF_XML_IN_NODE (CHART_CHART, CHART_TITLE, OO_NS_CHART, "title", FALSE, NULL, NULL),
+		GSF_XML_IN_NODE (CHART_TITLE, TITLE_TEXT, OO_NS_TEXT, "p", TRUE, NULL, &od_chart_title),
+		GSF_XML_IN_NODE (CHART_CHART, CHART_LEGEND, OO_NS_CHART, "legend", TRUE, &od_legend, NULL),
+		GSF_XML_IN_NODE (CHART_CHART, CHART_PLOT_AREA, OO_NS_CHART, "plot-area", TRUE, &od_plot_area, NULL),
+		GSF_XML_IN_NODE (CHART_PLOT_AREA, CHART_AXIS, OO_NS_CHART, "axis", TRUE, &od_chart_axis, NULL),
+		GSF_XML_IN_NODE (CHART_PLOT_AREA, CHART_SERIES, OO_NS_CHART, "series", TRUE, NULL, NULL),
+		GSF_XML_IN_NODE (CHART_PLOT_AREA, CHART_WALL, OO_NS_CHART, "wall", TRUE, &od_chart_wall, NULL),
+		GSF_XML_IN_NODE (CHART_AXIS, CHART_GRID, OO_NS_CHART, "grid", TRUE, &od_chart_grid, NULL),
+
 	    GSF_XML_IN_NODE (TABLE_SETTINGS, TABLE, OO_NS_TABLE, "table", GSF_XML_NO_CONTENT, &oo_table_start, NULL),
 	      GSF_XML_IN_NODE (TABLE, FORMS, OO_NS_OFFICE, "forms", GSF_XML_NO_CONTENT, NULL, NULL),
 	      GSF_XML_IN_NODE (TABLE, TABLE_COL, OO_NS_TABLE, "table-column", GSF_XML_NO_CONTENT, &oo_col_start, NULL),
 	      GSF_XML_IN_NODE (TABLE, TABLE_ROW, OO_NS_TABLE, "table-row", GSF_XML_NO_CONTENT, &oo_row_start, &oo_row_end),
+	      GSF_XML_IN_NODE (TABLE, TABLE_ROWS, OO_NS_TABLE, "table-rows", GSF_XML_NO_CONTENT, NULL, NULL),
 		GSF_XML_IN_NODE (TABLE_ROW, TABLE_CELL, OO_NS_TABLE, "table-cell", GSF_XML_NO_CONTENT, &oo_cell_start, &oo_cell_end),
 		  GSF_XML_IN_NODE (TABLE_CELL, CELL_FRAME, OO_NS_DRAW, "frame", GSF_XML_NO_CONTENT, NULL, NULL),
 		    GSF_XML_IN_NODE (CELL_FRAME, CELL_IMAGE, OO_NS_DRAW, "image", GSF_XML_NO_CONTENT, NULL, NULL),
 		      GSF_XML_IN_NODE (CELL_IMAGE, IMAGE_TEXT, OO_NS_TEXT, "p", GSF_XML_NO_CONTENT, NULL, NULL),
 		GSF_XML_IN_NODE (TABLE_ROW, TABLE_COVERED_CELL, OO_NS_TABLE, "covered-table-cell", GSF_XML_NO_CONTENT, &oo_covered_cell_start, &oo_covered_cell_end),
 		  GSF_XML_IN_NODE (TABLE_CELL, CELL_TEXT, OO_NS_TEXT, "p", GSF_XML_CONTENT, NULL, &oo_cell_content_end),
+
+			GSF_XML_IN_NODE (TABLE_CELL, DRAW_FRAME, OO_NS_DRAW, "frame", FALSE, &od_draw_frame, NULL),				
+			GSF_XML_IN_NODE (DRAW_FRAME, DRAW_OBJECT, OO_NS_DRAW, "object", TRUE, &od_draw_object, NULL),				
+			GSF_XML_IN_NODE (DRAW_FRAME, DRAW_IMAGE, OO_NS_DRAW, "image", TRUE, &od_draw_image, NULL),				
+
 		    GSF_XML_IN_NODE (CELL_TEXT, CELL_TEXT_S,    OO_NS_TEXT, "s", GSF_XML_NO_CONTENT, NULL, NULL),
 		    GSF_XML_IN_NODE (CELL_TEXT, CELL_TEXT_ADDR, OO_NS_TEXT, "a", GSF_XML_SHARED_CONTENT, NULL, NULL),
 		    GSF_XML_IN_NODE (CELL_TEXT, CELL_TEXT_SPAN, OO_NS_TEXT, "span", GSF_XML_SHARED_CONTENT, &oo_cell_content_span_start, &oo_cell_content_span_end),
@@ -1705,7 +2332,10 @@ openoffice_file_open (GOFileOpener const
 	state.context = io_context;
 	state.wb_view = wb_view;
 	state.pos.wb	= wb_view_workbook (wb_view);
+	state.zip = zip;
 	state.pos.sheet = NULL;
+	state.col_styles[0] = NULL;
+	state.col_styles[1] = NULL;
 	state.pos.eval.col	= -1;
 	state.pos.eval.row	= -1;
 	state.col_row_styles = g_hash_table_new_full (g_str_hash, g_str_equal,
@@ -1717,12 +2347,16 @@ openoffice_file_open (GOFileOpener const
 	state.formats = g_hash_table_new_full (g_str_hash, g_str_equal,
 		(GDestroyNotify) g_free,
 		(GDestroyNotify) go_format_unref);
+	state.cur_frame.graph_styles = g_hash_table_new_full (g_str_hash, g_str_equal,
+		(GDestroyNotify) g_free,
+		(GDestroyNotify) clean_lists);
 	state.cur_style.cell   = NULL;
 	state.default_style_cell = NULL;
 	state.cur_style_type   = OO_STYLE_UNKNOWN;
 	state.sheet_order = NULL;
 	state.exprconv = oo_conventions ();
 	state.accum_fmt = NULL;
+	state.cur_frame.has_legend = FALSE;
 
 	if (meta_file != NULL) {
 		meta_data = gsf_doc_meta_data_new ();
@@ -1768,7 +2402,10 @@ openoffice_file_open (GOFileOpener const
 		gnm_style_unref (state.default_style_cell);
 	g_hash_table_destroy (state.col_row_styles);
 	g_hash_table_destroy (state.cell_styles);
+	g_hash_table_destroy (state.cur_frame.graph_styles);
 	g_hash_table_destroy (state.formats);
+	g_slist_free (state.col_styles[0]);
+	g_slist_free (state.col_styles[1]);
 	g_object_unref (G_OBJECT (content));
 
 	g_object_unref (G_OBJECT (zip));
