[goffice] Revisited the component API.



commit 40f5a78a21b41446500cf17e6e7ea90300f31dc3
Author: Jean Brefort <jean brefort normalesup org>
Date:   Tue Aug 2 20:59:36 2011 +0200

    Revisited the component API.

 ChangeLog                                    |   25 ++
 configure.in                                 |   13 +
 goffice/canvas/Makefile.am                   |    2 +
 goffice/canvas/goc-component.c               |  317 ++++++++++++++++++
 goffice/canvas/goc-component.h               |   40 +++
 goffice/canvas/goffice-canvas.h              |    2 +
 goffice/component/Makefile.am                |    6 +-
 goffice/component/go-component-factory.c     |   15 +-
 goffice/component/go-component-factory.h     |    1 +
 goffice/component/go-component-mime-dialog.c |  102 ++++++
 goffice/component/go-component-mime-dialog.h |   41 +++
 goffice/component/go-component.c             |  449 +++++++++++++++++++++++++-
 goffice/component/go-component.h             |   23 ++-
 goffice/component/goffice-component.h        |    2 +
 goffice/graph/gog-axis-line.c                |    6 +-
 goffice/graph/gog-axis.c                     |    4 +-
 goffice/graph/gog-renderer.c                 |   12 +-
 goffice/graph/gog-renderer.h                 |    4 +-
 goffice/graph/gog-series-labels.c            |    6 +-
 goffice/gtk/go-format-sel.c                  |    4 +-
 goffice/utils/go-format.c                    |   24 +-
 goffice/utils/go-pango-extras.h              |    4 +-
 plugins/plot_barcol/gog-barcol.c             |    2 +-
 23 files changed, 1061 insertions(+), 43 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index fa52a0a..5b1c8ce 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,30 @@
 2011-08-02  Jean Brefort  <jean brefort normalesup org>
 
+	* configure.in: needs librsvg.
+	* goffice/canvas/Makefile.am:  add component support to the canvas.
+	* goffice/canvas/goc-component.c: ditto.
+	* goffice/canvas/goc-component.h: ditto.
+	* goffice/canvas/goffice-canvas.h: ditto.
+	* goffice/component/Makefile.am: revisited the component API.
+	* goffice/component/go-component-factory.c: ditto.
+	* goffice/component/go-component-factory.h: ditto.
+	* goffice/component/go-component-mime-dialog.c: ditto.
+	* goffice/component/go-component-mime-dialog.h: ditto.
+	* goffice/component/go-component.c: ditto.
+	* goffice/component/go-component.h: ditto.
+	* goffice/component/goffice-component.h: ditto.
+	* goffice/graph/gog-axis-line.c: cleaned out extra spaces.
+	* goffice/graph/gog-axis.c: ditto.
+	* goffice/graph/gog-renderer.c: ditto.
+	* goffice/graph/gog-renderer.h: ditto.
+	* goffice/graph/gog-series-labels.c: ditto.
+	* goffice/gtk/go-format-sel.c: ditto.
+	* goffice/utils/go-format.c: ditto.
+	* goffice/utils/go-pango-extras.h: ditto.
+	* plugins/plot_barcol/gog-barcol.c: ditto.
+
+2011-08-02  Jean Brefort  <jean brefort normalesup org>
+
 	* goffice/data/go-data-impl.h: add markup support.
 	* goffice/data/go-data.c: ditto.
 	* goffice/data/go-data.h: ditto.
diff --git a/configure.in b/configure.in
index 0f18cf9..3958d21 100644
--- a/configure.in
+++ b/configure.in
@@ -102,6 +102,7 @@ goffice_reqs="
 	pango			>= 1.24.0
 	pangocairo		>= 1.24.0
 	cairo			>= 1.10.0
+	librsvg-2.0		>= 2.22.0
 "
 
 goffice_gtk_reqs="
@@ -134,6 +135,18 @@ if test "x$goffice_with_lasem" = "xtrue" ; then
 	EXTRA_DEPS="$EXTRA_DEPS lasem-0.4"
 fi
 
+goffice_with_rsvg=false
+AC_ARG_WITH(librsvg, [  --with-librsvg          Build with librsvg use])
+if test "x$with_librsvg" = xyes; then
+	PKG_CHECK_MODULES(rsvg, librsvg-2.0 >= 2.22.0)
+	goffice_with_rsvg=true
+fi
+if test "x$goffice_with_rsvg" = "xtrue" ; then
+	AC_DEFINE(GOFFICE_WITH_RSVG, 1, [Define if librsvg is used])
+	goffice_reqs="$goffice_reqs librsvg-2.0 >= 2.22.0 "
+	EXTRA_DEPS="$EXTRA_DEPS librsvg-2.0"
+fi
+
 AM_CONDITIONAL(GOFFICE_WITH_LASEM, $goffice_with_lasem)
 
 
diff --git a/goffice/canvas/Makefile.am b/goffice/canvas/Makefile.am
index 20b4913..47b44bf 100644
--- a/goffice/canvas/Makefile.am
+++ b/goffice/canvas/Makefile.am
@@ -4,6 +4,7 @@ libgoffice_canvas_la_SOURCES =	\
 	goc-arc.c		\
 	goc-canvas.c		\
 	goc-circle.c		\
+	goc-component.c		\
 	goc-ellipse.c		\
 	goc-graph.c		\
 	goc-group.c		\
@@ -24,6 +25,7 @@ libgoffice_canvas_la_HEADERS =	\
 	goc-arc.h		\
 	goc-canvas.h		\
 	goc-circle.h		\
+	goc-component.h		\
 	goc-ellipse.h		\
 	goc-graph.h		\
 	goc-group.h		\
diff --git a/goffice/canvas/goc-component.c b/goffice/canvas/goc-component.c
new file mode 100644
index 0000000..ebfad44
--- /dev/null
+++ b/goffice/canvas/goc-component.c
@@ -0,0 +1,317 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-component.c :
+ *
+ * Copyright (C) 2010 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+
+#include <glib/gi18n-lib.h>
+#include <gsf/gsf-impl-utils.h>
+
+/**
+ * SECTION:goc-component
+ * @short_description: Components.
+ *
+ * #GocComponent implements #GOComponent embedding in the canvas.
+**/
+
+struct _GocComponent {
+	GocItem base;
+
+	double x, y, w, h;
+	double rotation;
+	GOComponent *component;
+};
+
+typedef GocItemClass GocComponentClass;
+
+static GObjectClass *parent_klass;
+
+enum {
+	COMPONENT_PROP_0,
+	COMPONENT_PROP_X,
+	COMPONENT_PROP_Y,
+	COMPONENT_PROP_H,
+	COMPONENT_PROP_W,
+	COMPONENT_PROP_ROTATION,
+	COMPONENT_PROP_OBJECT
+};
+
+static void
+goc_component_set_property (GObject *obj, guint param_id,
+			GValue const *value, GParamSpec *pspec)
+{
+	GocComponent *component = GOC_COMPONENT (obj);
+
+	switch (param_id) {
+	case COMPONENT_PROP_X: {
+		double x = g_value_get_double (value);
+		if (x == component->x)
+			return;
+		component->x = x;
+		return;
+	}
+	case COMPONENT_PROP_Y: {
+		double y = g_value_get_double (value);
+		if (y == component->y)
+			return;
+		component->y = y;
+		break;
+	}
+	/* NOTE: it is allowed to set width and height even if the component is not resizable
+	 * but this should be only used to convert the size in inches to pixels.
+	 * The default is 1 pixel == 1 point.
+	 */
+	case COMPONENT_PROP_H: {
+		double h = g_value_get_double (value);
+		if (!component->component || h == component->h)
+			return;
+		component->h = h;
+		break;
+	}
+	case COMPONENT_PROP_W: {
+		double w = g_value_get_double (value);
+		if (!component->component || w == component->w)
+			return;
+		component->w = w;
+		break;
+	}
+	case COMPONENT_PROP_ROTATION: {
+		double r = g_value_get_double (value) / 180. * M_PI;
+		if (!component->component || go_component_needs_window (component->component) || r == component->rotation)
+			return;
+		component->rotation = r;
+		break;
+	}
+
+	case COMPONENT_PROP_OBJECT:
+		if (component->component != NULL)
+			g_object_unref (component->component);
+		component->component = GO_COMPONENT (g_value_get_object (value));
+		if (component->component != NULL) {
+			g_object_ref (component->component);
+			/* set default or fixed size */
+			go_component_get_size (component->component, &component->w, &component->h);
+			component->w = GO_IN_TO_PT (component->w);
+			component->h = GO_IN_TO_PT (component->h);
+		}
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+
+	goc_item_bounds_changed (GOC_ITEM (component));
+}
+
+static void
+goc_component_get_property (GObject *obj, guint param_id,
+			GValue *value, GParamSpec *pspec)
+{
+	GocComponent *component = GOC_COMPONENT (obj);
+
+	switch (param_id) {
+	case COMPONENT_PROP_X:
+		g_value_set_double (value, component->x);
+		break;
+	case COMPONENT_PROP_Y:
+		g_value_set_double (value, component->y);
+		break;
+	case COMPONENT_PROP_H:
+		g_value_set_double (value, component->h);
+		break;
+	case COMPONENT_PROP_W:
+		g_value_set_double (value, component->w);
+		break;
+	case COMPONENT_PROP_ROTATION:
+		g_value_set_double (value, component->rotation * 180. / M_PI);
+		break;
+	case COMPONENT_PROP_OBJECT:
+		g_value_set_object (value, component->component);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+		break;
+	}
+}
+
+static void
+goc_component_finalize (GObject *obj)
+{
+	GocComponent *component = GOC_COMPONENT (obj);
+
+	if (component->component != NULL) {
+		g_object_unref (component->component);
+		component->component = NULL;
+	}
+	(*parent_klass->finalize) (obj);
+}
+
+static double
+goc_component_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+	GocComponent *component = GOC_COMPONENT (item);
+	double dx, dy;
+	x -= component->x;
+	y -= component->y;
+	/* adjust for rotation */
+	if (component->rotation != 0.) {
+		double sinr = sin (-component->rotation), cosr = cos (component->rotation), t;
+		x -= component->w / 2.;
+		y -= component->h / 2.;
+		t = x * cosr + y * sinr;
+		y = y * cosr - x * sinr;
+		x = t + component->w / 2.;
+		y += component->h / 2.;
+	}
+	if (x < 0) {
+		dx = -x;
+	} else if (x < component->w) {
+		dx = 0;
+	} else {
+		dx = x - component->w;
+	}
+	if (y < 0) {
+		dy = -y;
+	} else if (y < component->h) {
+		dy = 0;
+	} else {
+		dy = y - component->h;
+	}
+	*near_item = item;
+	return hypot (dx, dy);
+}
+
+static void
+goc_component_draw (GocItem const *item, cairo_t *cr)
+{
+	GocComponent *component = GOC_COMPONENT (item);
+	GocCanvas *canvas = item->canvas;
+	double x0, y0 = component->y;
+	if (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL) {
+		x0 = component->x + component->w;
+		goc_group_adjust_coords (item->parent, &x0, &y0);
+		x0 = canvas->width - (int) (x0 - canvas->scroll_x1) * canvas->pixels_per_unit;
+	} else {
+		x0 = component->x;
+		goc_group_adjust_coords (item->parent, &x0, &y0);
+		x0 = (int) (x0 - canvas->scroll_x1) * canvas->pixels_per_unit;
+	}
+	cairo_save (cr);
+	if (component->rotation == 0.)
+		cairo_translate (cr, x0,
+			         (int) (y0 - canvas->scroll_y1) * canvas->pixels_per_unit);
+	else {
+		cairo_translate (cr, x0 + component->w / 2 * canvas->pixels_per_unit,
+			         (int) (y0 - canvas->scroll_y1 + component->h / 2) * canvas->pixels_per_unit);
+		cairo_rotate (cr, -component->rotation);
+		cairo_translate (cr, -component->w / 2 * canvas->pixels_per_unit,
+			         -component->h / 2 * canvas->pixels_per_unit);
+	}
+	cairo_rectangle (cr, 0., 0., component->w * canvas->pixels_per_unit,
+	                     component->h * canvas->pixels_per_unit);
+	cairo_clip (cr);
+	go_component_render (component->component, cr,
+	                     component->w * canvas->pixels_per_unit,
+	                     component->h * canvas->pixels_per_unit);
+	cairo_restore (cr);
+}
+
+static void
+goc_component_update_bounds (GocItem *item)
+{
+	GocComponent *component = GOC_COMPONENT (item);
+	if (component->rotation == 0.) {
+		item->x0 = component->x;
+		item->y0 = component->y;
+		item->x1 = component->x + component->w;
+		item->y1 = component->y + component->h;
+	} else {
+		double cosr = cos (component->rotation), sinr = sin (component->rotation);
+		double w = fabs (component->w * cosr) + fabs (component->h * sinr), h = fabs (component->h * cosr) + fabs (component->w * sinr);
+		item->x0 = component->x + (component->w - w) / 2.;
+		item->x1 = item->x0 + w;
+		item->y0 = component->y + (component->h - h) / 2.;
+		item->y1 = item->y0 + h;
+	}
+}
+
+static void
+goc_component_class_init (GocItemClass *item_klass)
+{
+	GObjectClass *obj_klass = (GObjectClass *) item_klass;
+
+	parent_klass = g_type_class_peek_parent (obj_klass);
+
+	obj_klass->set_property = goc_component_set_property;
+	obj_klass->get_property = goc_component_get_property;
+	obj_klass->finalize	= goc_component_finalize;
+
+	g_object_class_install_property (obj_klass, COMPONENT_PROP_X,
+		g_param_spec_double ("x",
+			_("x"),
+			_("The object left position"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, COMPONENT_PROP_Y,
+		g_param_spec_double ("y",
+			_("y"),
+			_("The object top position"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, COMPONENT_PROP_H,
+		 g_param_spec_double ("height",
+			_("Height"),
+			_("Height"),
+			0, G_MAXDOUBLE, 100.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, COMPONENT_PROP_W,
+		 g_param_spec_double ("width",
+			_("Width"),
+			_("Width"),
+			0, G_MAXDOUBLE, 100.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, COMPONENT_PROP_ROTATION,
+		g_param_spec_double ("rotation",
+			_("Rotation"),
+			_("The rotation around center, only available for windowless components"),
+			0., 360., 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, COMPONENT_PROP_OBJECT,
+		g_param_spec_object ("object",
+			_("Object"),
+			_("The embedded GOComponent object"),
+			GO_TYPE_COMPONENT,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+
+	item_klass->draw = goc_component_draw;
+	item_klass->update_bounds = goc_component_update_bounds;
+	item_klass->distance = goc_component_distance;
+}
+
+GSF_CLASS (GocComponent, goc_component,
+	   goc_component_class_init, NULL,
+	   GOC_TYPE_ITEM)
+
+GOComponent * goc_component_get_object (GocComponent *component)
+{
+	g_return_val_if_fail (GOC_IS_COMPONENT (component), NULL);
+	return component->component;
+}
diff --git a/goffice/canvas/goc-component.h b/goffice/canvas/goc-component.h
new file mode 100644
index 0000000..729b3cd
--- /dev/null
+++ b/goffice/canvas/goc-component.h
@@ -0,0 +1,40 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-component.h :
+ *
+ * Copyright (C) 2010 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_COMPONENT_H
+#define GOC_COMPONENT_H
+
+#include <goffice/goffice.h>
+#include <goffice/component/goffice-component.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_COMPONENT	(goc_component_get_type ())
+#define GOC_COMPONENT(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_COMPONENT, GocComponent))
+#define GOC_IS_COMPONENT(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_COMPONENT))
+
+GType goc_component_get_type (void);
+
+GOComponent * goc_component_get_object (GocComponent *component);
+
+G_END_DECLS
+
+#endif  /* GOC_COMPONENT_H */
diff --git a/goffice/canvas/goffice-canvas.h b/goffice/canvas/goffice-canvas.h
index ff41f38..c5034bc 100644
--- a/goffice/canvas/goffice-canvas.h
+++ b/goffice/canvas/goffice-canvas.h
@@ -44,6 +44,7 @@ typedef struct _GocStyledItem	GocStyledItem;
 typedef struct _GocText		GocText;
 typedef struct _GocWidget	GocWidget;
 typedef struct _GocGraph	GocGraph;
+typedef struct _GocComponent	GocComponent;
 
 G_END_DECLS
 
@@ -56,6 +57,7 @@ G_END_DECLS
 #include <goffice/canvas/goc-utils.h>
 
 #include <goffice/canvas/goc-circle.h>
+#include <goffice/canvas/goc-component.h>
 #include <goffice/canvas/goc-ellipse.h>
 #include <goffice/canvas/goc-graph.h>
 #include <goffice/canvas/goc-group.h>
diff --git a/goffice/component/Makefile.am b/goffice/component/Makefile.am
index 76a4b05..c68f52b 100644
--- a/goffice/component/Makefile.am
+++ b/goffice/component/Makefile.am
@@ -2,13 +2,15 @@ noinst_LTLIBRARIES = libgoffice-component.la
 
 libgoffice_component_la_SOURCES =	\
 	go-component.c 		\
-	go-component-factory.c
+	go-component-factory.c	\
+	go-component-mime-dialog.c
 
 libgoffice_component_ladir = $(goffice_include_dir)/component
 libgoffice_component_la_HEADERS = 	\
 	goffice-component.h		\
 	go-component.h			\
-	go-component-factory.h
+	go-component-factory.h	\
+	go-component-mime-dialog.h
 
 include $(top_srcdir)/goffice.mk
 
diff --git a/goffice/component/go-component-factory.c b/goffice/component/go-component-factory.c
index 469f6ad..f31b8a9 100644
--- a/goffice/component/go-component-factory.c
+++ b/goffice/component/go-component-factory.c
@@ -330,7 +330,7 @@ GOComponent *
 go_component_new_by_mime_type (char const *mime_type)
 {
 	GType type;
-	GOMimeType *mtype = g_hash_table_lookup (mime_types, mime_type);
+	GOMimeType *mtype = (mime_types)? g_hash_table_lookup (mime_types, mime_type): NULL;
 	if (mtype == NULL)
 		return NULL;
 	type = g_type_from_name (mtype->component_type_name);
@@ -370,3 +370,16 @@ go_component_new_by_mime_type (char const *mime_type)
 
 	return g_object_new (type, "mime-type", mime_type, NULL);
 }
+
+void go_components_add_filter (GtkFileChooser *chooser)
+{
+	GtkFileFilter* filter;
+	GSList *ptr;
+
+	g_return_if_fail (GTK_IS_FILE_CHOOSER (chooser));
+
+	filter = gtk_file_filter_new ();
+	for (ptr = mime_types_names; ptr != NULL; ptr = ptr->next)
+		gtk_file_filter_add_mime_type (filter, (char const *) ptr->data);
+	gtk_file_chooser_set_filter (chooser, filter);
+}
diff --git a/goffice/component/go-component-factory.h b/goffice/component/go-component-factory.h
index 475a2ec..9553df7 100644
--- a/goffice/component/go-component-factory.h
+++ b/goffice/component/go-component-factory.h
@@ -47,6 +47,7 @@ gboolean go_components_support_clipboard (char const *mime_type);
 void go_components_add_mime_type (char *mime, GOMimePriority priority, char const *service_id);
 void go_components_set_mime_suffix (char const *mime, char const *suffix);
 char const *go_components_get_mime_suffix (char const *mime);
+void go_components_add_filter (GtkFileChooser *chooser);
 
 void _goc_plugin_services_init (void);
 void _goc_plugin_services_shutdown (void);
diff --git a/goffice/component/go-component-mime-dialog.c b/goffice/component/go-component-mime-dialog.c
new file mode 100644
index 0000000..b024f0e
--- /dev/null
+++ b/goffice/component/go-component-mime-dialog.c
@@ -0,0 +1,102 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * go-component-mime-dialog.c :
+ *
+ * Copyright (C) 2010 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+#include <goffice/component/goffice-component.h>
+#include <gsf/gsf-impl-utils.h>
+
+struct _GOComponentMimeDialog {
+	GtkDialog base;
+	GtkTreeSelection *sel;
+	GtkTreeModel *list;
+};
+typedef GtkDialogClass GOComponentMimeDialogClass;
+
+static gboolean
+button_press_cb (GtkDialog *dlg, GdkEventButton *ev)
+{
+	if (ev->type == GDK_2BUTTON_PRESS)
+		gtk_dialog_response (dlg, GTK_RESPONSE_OK);
+	return FALSE;
+}
+
+static void
+go_component_mime_dialog_init (GOComponentMimeDialog *dlg)
+{
+	GtkListStore *list = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+	GtkWidget *w = gtk_tree_view_new_with_model (GTK_TREE_MODEL (list));
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+	GSList *mime_types = go_components_get_mime_types ();
+	GSList *l = mime_types;
+	GtkTreeIter iter;
+	char const *mime_type;
+
+	gtk_dialog_add_buttons (&dlg->base,
+	                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+	                        GTK_STOCK_OK, GTK_RESPONSE_OK,
+	                        NULL);
+	gtk_window_set_modal (GTK_WINDOW (dlg), TRUE);
+	gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE);
+	dlg->sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (w));
+	g_signal_connect_swapped (w, "button-press-event", G_CALLBACK (button_press_cb), dlg);
+	renderer = gtk_cell_renderer_text_new ();
+	column = gtk_tree_view_column_new_with_attributes ("Object type:", renderer, "text", 0, NULL);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (w), column);
+	gtk_tree_selection_set_mode (dlg->sel, GTK_SELECTION_BROWSE);
+	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list), 0, GTK_SORT_ASCENDING);
+	while (l) {
+		mime_type = (char const *) l->data;
+		if (go_components_get_priority (mime_type) >= GO_MIME_PRIORITY_PARTIAL) {
+			gtk_list_store_append (list, &iter);
+			gtk_list_store_set (list, &iter,
+					  0, go_mime_type_get_description (mime_type),
+					  1, mime_type,
+					  -1);
+		}
+		l = l->next;
+	}
+	dlg->list = GTK_TREE_MODEL (list);
+	gtk_container_addt (GTK_CONTAINER (gtk_dialog_get_content_area (&dlg->base)), w, FALSE, FALSE, 0);
+	gtk_widget_show_all (gtk_dialog_get_content_area (&dlg->base));
+}
+
+GSF_CLASS (GOComponentMimeDialog, go_component_mime_dialog,
+	NULL, go_component_mime_dialog_init,
+	GTK_TYPE_DIALOG)
+
+GtkWidget  *
+go_component_mime_dialog_new ()
+{
+	return GTK_WIDGET (g_object_new (GO_TYPE_COMPONENT_MIME_DIALOG, NULL));
+}
+
+char const *
+go_component_mime_dialog_get_mime_type (GOComponentMimeDialog *dlg)
+{
+	GtkTreeIter iter;
+	char const *mime_type = NULL;
+	if (gtk_tree_selection_get_selected (dlg->sel, NULL, &iter))
+		gtk_tree_model_get (dlg->list, &iter, 1, &mime_type, -1);
+	return mime_type;
+}
+
diff --git a/goffice/component/go-component-mime-dialog.h b/goffice/component/go-component-mime-dialog.h
new file mode 100644
index 0000000..dd1a5ca
--- /dev/null
+++ b/goffice/component/go-component-mime-dialog.h
@@ -0,0 +1,41 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * go-component-mime-dialog.c :
+ *
+ * Copyright (C) 2010 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GO_COMPONENT_MIME_DIALOG_H
+#define GO_COMPONENT_MIME_DIALOG_H
+
+#include <glib-object.h>
+#include <goffice/goffice.h>
+#include <goffice/component/goffice-component.h>
+
+G_BEGIN_DECLS
+
+#define GO_TYPE_COMPONENT_MIME_DIALOG	(go_component_mime_dialog_get_type ())
+#define GO_COMPONENT_MIME_DIALOG(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GO_TYPE_COMPONENT_MIME_DIALOG, GOComponentMimeDialog))
+#define GO_IS_COMPONENT_MIME_DIALOG(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GO_TYPE_COMPONENT_MIME_DIALOG))
+
+GType	  go_component_mime_dialog_get_type (void);
+GtkWidget  *go_component_mime_dialog_new (void);
+char const *go_component_mime_dialog_get_mime_type (GOComponentMimeDialog *dlg);
+
+G_END_DECLS
+
+#endif  /* GO_COMPONENT_MIME_DIALOG_H */
diff --git a/goffice/component/go-component.c b/goffice/component/go-component.c
index 95a4904..77df27c 100644
--- a/goffice/component/go-component.c
+++ b/goffice/component/go-component.c
@@ -2,7 +2,7 @@
 /*
  * go-component.c :
  *
- * Copyright (C) 2005 Jean Brefort (jean brefort normalesup org)
+ * Copyright (C) 2005-2010 Jean Brefort (jean brefort normalesup org)
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
@@ -22,8 +22,39 @@
 #include <goffice/goffice-config.h>
 #include <goffice/component/goffice-component.h>
 #include <goffice/component/go-component.h>
-
+#include <gsf/gsf-libxml.h>
 #include <gsf/gsf-impl-utils.h>
+#include <gsf/gsf-input.h>
+#include <gsf/gsf-output-memory.h>
+#include <gio/gio.h>
+#include <cairo-svg.h>
+#include <librsvg/rsvg.h>
+#include <librsvg/rsvg-cairo.h>
+#include <string.h>
+
+static struct {
+	GOSnapshotType type;
+	char const *name;
+} snapshot_types[GO_SNAPSHOT_MAX] = {
+	{ GO_SNAPSHOT_NONE, "none"},
+	{ GO_SNAPSHOT_SVG, "svg"},
+	{ GO_SNAPSHOT_PNG, "png"}
+};
+
+static GOSnapshotType
+go_snapshot_type_from_string (char const *name)
+{
+	unsigned i;
+	GOSnapshotType ret = GO_SNAPSHOT_NONE;
+
+	for (i = 0; i < GO_SNAPSHOT_MAX; i++) {
+		if (strcmp (snapshot_types[i].name, name) == 0) {
+			ret = snapshot_types[i].type;
+			break;
+		}
+	}
+	return ret;
+}
 
 /**
  * GOComponentClass:
@@ -59,6 +90,12 @@ enum {
 };
 static gulong go_component_signals [LAST_SIGNAL] = { 0, };
 
+enum {
+	GO_COMPONENT_SNAPSHOT_NONE,
+	GO_COMPONENT_SNAPSHOT_SVG,
+	GO_COMPONENT_SNAPSHOT_PNG,
+};
+
 static GObjectClass *component_parent_klass;
 
 static void go_component_set_property (GObject *obj, guint param_id,
@@ -125,6 +162,11 @@ go_component_finalize (GObject *obj)
 
 	g_free (component->mime_type);
 
+	if (component->destroy_notify != NULL) {
+		component->destroy_notify (component->destroy_data);
+		component->destroy_notify = NULL;
+	}
+
 	(*component_parent_klass->finalize) (obj);
 }
 
@@ -140,7 +182,7 @@ go_component_class_init (GOComponentClass *klass)
 
 	g_object_class_install_property (gobject_klass, COMPONENT_PROP_MIME_TYPE,
 		g_param_spec_string ("mime-type", "mime-type", "mime type of the content of the component",
-			NULL, G_PARAM_READWRITE));
+			NULL, (GParamFlags) (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
 	g_object_class_install_property (gobject_klass, COMPONENT_PROP_WIDTH,
 		g_param_spec_double ("width", "Width",
 			"Component width",
@@ -185,6 +227,123 @@ GSF_CLASS_ABSTRACT (GOComponent, go_component,
 		    go_component_class_init, go_component_init,
 		    G_TYPE_OBJECT)
 
+/******************************************************************************
+ * GOComponentSnapshot: component class used when actual class is not         *
+ * available, just displays the snapshot                                      *
+ ******************************************************************************/
+
+typedef struct {
+	GOComponent base;
+	gpointer *image;
+} GOComponentSnapshot;
+typedef GOComponentClass GOComponentSnapshotClass;
+
+GType go_component_snapshot_get_type (void);
+
+static GObjectClass *snapshot_parent_klass;
+
+static void
+go_component_snapshot_render (GOComponent *component, cairo_t *cr,
+			double width, double height)
+{
+	GOComponentSnapshot *snapshot = (GOComponentSnapshot *) component;
+	switch (component->snapshot_type) {
+	case GO_SNAPSHOT_SVG:
+#if defined(GOFFICE_WITH_RSVG)
+		if (snapshot->image == NULL) {
+			GError *err = NULL;
+			snapshot->image = (void *) rsvg_handle_new_from_data (
+							component->snapshot_data,
+							component->snapshot_length,
+							&err);
+			if (err) {
+				g_error_free (err);
+				if (snapshot->image)
+					g_object_unref (snapshot->image);
+				snapshot->image = NULL;
+			}
+		}
+		if (snapshot->image != NULL) {
+			RsvgDimensionData dim;
+			double scalex = 1., scaley = 1.;
+			cairo_save (cr);
+			rsvg_handle_get_dimensions (RSVG_HANDLE (snapshot->image), &dim);
+			cairo_user_to_device_distance (cr, &scalex, &scaley);
+			cairo_scale (cr, width * scalex / dim.width,
+						 height * scaley / dim.height);
+			rsvg_handle_render_cairo (RSVG_HANDLE (snapshot->image), cr);
+			cairo_restore (cr);
+		}
+		break;
+#elif defined(GOFFICE_WITH_LASEM)
+		/* TODO: implement a Lasem based svg rendering when possible */
+#endif
+	case GO_SNAPSHOT_PNG: {
+		cairo_pattern_t *pattern;
+		if (snapshot->image == NULL) {
+			GInputStream *in = g_memory_input_stream_new_from_data (
+						component->snapshot_data,
+						component->snapshot_length,
+						NULL);
+			GError *err = NULL;
+			GdkPixbuf *pixbuf = gdk_pixbuf_new_from_stream (in, NULL, &err);
+			if (err) {
+				g_error_free (err);
+			} else
+				snapshot->image = (void *) go_image_new_from_pixbuf (pixbuf);
+			if (pixbuf)
+				g_object_unref (pixbuf);
+
+		}
+		cairo_rectangle (cr, 0, 0, width, height);
+		if (snapshot->image != NULL) {
+			int w, h;
+			double scalex = 1., scaley = 1.;
+			cairo_matrix_t matrix;
+			pattern = go_image_create_cairo_pattern (GO_IMAGE (snapshot->image));
+			g_object_get (snapshot->image, "width", &w, "height", &h, NULL);
+			cairo_user_to_device_distance (cr, &scalex, &scaley);
+			cairo_matrix_init_scale (&matrix,
+						 w / width * scalex,
+						 h / height * scaley);
+			cairo_pattern_set_matrix (pattern, &matrix);
+		} else
+			pattern = cairo_pattern_create_rgba (1, 1, 1, 1);
+		cairo_set_source (cr, pattern);
+		cairo_pattern_destroy (pattern);
+		cairo_fill (cr);
+		break;
+	}
+	default:
+		break;
+	}
+}
+
+static void
+go_component_shapshot_finalize (GObject *obj)
+{
+	GOComponentSnapshot *snapshot = (GOComponentSnapshot *) obj;
+
+	if (G_IS_OBJECT (snapshot->image))
+		g_object_unref (G_OBJECT (snapshot->image));
+
+	(*snapshot_parent_klass->finalize) (obj);
+}
+
+static void
+go_component_snapshot_class_init (GOComponentClass *klass)
+{
+	snapshot_parent_klass = g_type_class_peek_parent (klass);
+	((GObjectClass *) klass)->finalize = go_component_shapshot_finalize;
+	klass->render = go_component_snapshot_render;
+}
+
+GSF_CLASS (GOComponentSnapshot, go_component_snapshot,
+	go_component_snapshot_class_init, NULL,
+	GO_TYPE_COMPONENT)
+
+/******************************************************************************/
+
 void
 go_component_set_default_size (GOComponent *component, double width, double ascent, double descent)
 {
@@ -255,13 +414,23 @@ go_component_get_data (GOComponent *component, gpointer *data, int *length,
 		       GDestroyNotify *clearfunc, gpointer *user_data)
 {
 	GOComponentClass *klass;
+	gboolean res =  FALSE;
 
 	g_return_val_if_fail (GO_IS_COMPONENT (component), FALSE);
 
-	klass = GO_COMPONENT_GET_CLASS(component);
+	if (component->destroy_notify != NULL) {
+		component->destroy_notify (component->destroy_data);
+		component->destroy_notify = NULL;
+	}
+
+	klass = GO_COMPONENT_GET_CLASS (component);
 	if (klass->get_data)
-		return klass->get_data (component, data, length, clearfunc, user_data);
-	return FALSE;
+		res = klass->get_data (component, data, length, clearfunc, user_data);
+	if (res) {
+		component->data = (char const *) *data;
+		component->length = *length;
+	}
+	return res;
 }
 
 void
@@ -324,6 +493,10 @@ go_component_emit_changed (GOComponent *component)
 {
 	g_return_if_fail (GO_IS_COMPONENT (component));
 
+	g_free (component->snapshot_data);
+	component->snapshot_data = NULL;
+	component->snapshot_length = 0;
+
 	g_signal_emit (G_OBJECT (component),
 		go_component_signals [CHANGED], 0);
 }
@@ -345,3 +518,267 @@ go_component_get_command_context (void)
 {
 	return goc_cc;
 }
+
+void
+go_component_get_size (GOComponent *component, double *width, double *height)
+{
+	*width = component->width;
+	if (component->height == 0.)
+		component->height = component->ascent >+ component->descent;
+	*height = component->height;
+}
+
+void
+go_component_write_xml_sax (GOComponent *component, GsfXMLOut *output)
+{
+	guint i, nbprops;
+	GType    prop_type;
+	GValue	 value;
+	GParamSpec **specs = g_object_class_list_properties (
+				G_OBJECT_GET_CLASS (component), &nbprops);
+
+	gsf_xml_out_start_element (output, "GOComponent");
+	gsf_xml_out_add_cstr (output, "mime-type", component->mime_type);
+	gsf_xml_out_add_float (output, "width", component->width, 3);
+	gsf_xml_out_add_float (output, "height", component->height, 3);
+	/* save needed component specific properties */
+	for (i = 0; i < nbprops; i++)
+		if (specs[i]->flags & GOC_PARAM_PERSISTENT) {
+			prop_type = G_PARAM_SPEC_VALUE_TYPE (specs[i]);
+			memset (&value, 0, sizeof (value));
+			g_value_init (&value, prop_type);
+			g_object_get_property  (G_OBJECT (component), specs[i]->name, &value);
+			if (!g_param_value_defaults (specs[i], &value))
+				gsf_xml_out_add_gvalue (output, specs[i]->name, &value);
+			g_value_unset (&value);
+		}
+	gsf_xml_out_start_element (output, "data");
+	if (component->length == 0)
+		go_component_get_data (component, (void **) &component->data, &component->length,
+		                       &component->destroy_notify, &component->destroy_data);
+	gsf_xml_out_add_base64 (output, NULL, component->data, component->length);
+	gsf_xml_out_end_element (output);
+	if (component->snapshot_type != GO_SNAPSHOT_NONE && component->snapshot_data == NULL)
+		go_component_build_snapshot (component);
+	if (component->snapshot_data != NULL) {
+		gsf_xml_out_start_element (output, "snapshot");
+		gsf_xml_out_add_cstr (output, "type", component->snapshot_type == GO_SNAPSHOT_SVG? "svg": "png");
+		gsf_xml_out_add_base64 (output, NULL, component->snapshot_data, component->snapshot_length);
+		gsf_xml_out_end_element (output);
+	}
+	gsf_xml_out_end_element (output);
+}
+
+typedef struct {
+	GOComponent	*component;
+	unsigned	 dimension_id;
+
+	GOComponentSaxHandler handler;
+	gpointer user_data;
+} GOCompXMLReadState;
+
+static void
+_go_component_start (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	GOCompXMLReadState *state = (GOCompXMLReadState *) xin->user_state;
+	char const *mime_type = NULL;
+	int i;
+	double width = 1., height = 1.;
+
+	for (i = 0; attrs != NULL && attrs[i] && attrs[i+1] ; i += 2)
+		if (0 == strcmp (attrs[i], "mime-type"))
+			mime_type = (char const *) attrs[i+1];
+		else if (0 == strcmp (attrs[i], "width"))
+			width = go_ascii_strtod ((char const *) attrs[i+1], NULL);
+		else if (0 == strcmp (attrs[i], "height"))
+			height = go_ascii_strtod ((char const *) attrs[i+1], NULL);
+
+	g_return_if_fail (mime_type);
+	state->component = go_component_new_by_mime_type (mime_type);
+	if (!state->component) {
+		state->component = g_object_new (go_component_snapshot_get_type (), NULL);
+		state->component->mime_type = g_strdup (mime_type);
+		state->component->width = width;
+		state->component->height = height;
+	} else for (i = 0; attrs != NULL && attrs[i] && attrs[i+1] ; i += 2) {
+		GParamSpec *prop_spec;
+		GValue res;
+		memset (&res, 0, sizeof (res));
+		prop_spec = g_object_class_find_property (
+				G_OBJECT_GET_CLASS (state->component), attrs[i]);
+		if (prop_spec && (prop_spec->flags & GOC_PARAM_PERSISTENT) &&
+			gsf_xml_gvalue_from_str (&res,
+				G_TYPE_FUNDAMENTAL (G_PARAM_SPEC_VALUE_TYPE (prop_spec)),
+				attrs[i+1])) {
+			g_object_set_property (G_OBJECT (state->component), attrs[i], &res);
+			g_value_unset (&res);
+		}
+	}
+
+}
+
+static void
+_go_component_load_data (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *unknown)
+{
+	GOCompXMLReadState *state = (GOCompXMLReadState *) xin->user_state;
+	GOComponentClass *klass;
+	GOComponent *component = state->component;
+	size_t length;
+
+	g_return_if_fail (component);
+
+	component->data = component->destroy_data = g_base64_decode (xin->content->str, &length);
+	component->destroy_notify = g_free;
+	component->length = length;
+	klass = GO_COMPONENT_GET_CLASS (component);
+	if (klass->set_data)
+		klass->set_data (component);
+}
+
+static void
+_go_component_start_snapshot (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	GOCompXMLReadState *state = (GOCompXMLReadState *) xin->user_state;
+	int i;
+
+	for (i = 0; attrs != NULL && attrs[i] && attrs[i+1] ; i += 2)
+		if (0 == strcmp (attrs[i], "type"))
+			state->component->snapshot_type = go_snapshot_type_from_string ((char const *) attrs[i+1]);
+}
+
+static void
+_go_component_load_snapshot (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *unknown)
+{
+	GOCompXMLReadState *state = (GOCompXMLReadState *) xin->user_state;
+	size_t length;
+	state->component->snapshot_data = g_base64_decode (xin->content->str, &length);
+	state->component->snapshot_length = length;
+}
+
+static void
+_go_component_sax_parser_done (GsfXMLIn *xin, GOCompXMLReadState *state)
+{
+	(*state->handler) (state->component, state->user_data);
+	g_free (state);
+}
+
+void
+go_component_sax_push_parser (GsfXMLIn *xin, xmlChar const **attrs,
+				GOComponentSaxHandler handler, gpointer user_data)
+{
+	static GsfXMLInNode const dtd[] = {
+	  GSF_XML_IN_NODE (GO_COMP, GO_COMP, -1, "GOComponent",	GSF_XML_NO_CONTENT, &_go_component_start, NULL),
+	    GSF_XML_IN_NODE (GO_COMP, GO_COMP_DATA, -1, "data", GSF_XML_CONTENT, NULL, &_go_component_load_data),
+	    GSF_XML_IN_NODE (GO_COMP, GO_COMP_SNAPSHOT, -1, "snapshot", GSF_XML_CONTENT, &_go_component_start_snapshot, &_go_component_load_snapshot),
+	  GSF_XML_IN_NODE_END
+	};
+	static GsfXMLInDoc *doc = NULL;
+	GOCompXMLReadState *state;
+
+	if (NULL == doc)
+		doc = gsf_xml_in_doc_new (dtd, NULL);
+	state = g_new0 (GOCompXMLReadState, 1);
+	state->handler = handler;
+	state->user_data = user_data;
+	gsf_xml_in_push_state (xin, doc, state,
+		(GsfXMLInExtDtor) _go_component_sax_parser_done, attrs);
+}
+
+struct write_state {
+	size_t length;
+	GsfOutput *output;
+};
+
+static cairo_status_t
+gsf_output_from_cairo (struct write_state *state, unsigned char *data, unsigned int length)
+{
+	if (gsf_output_write (state->output, length, data)) {
+		state->length += length;
+		return CAIRO_STATUS_SUCCESS;
+	} else
+		return CAIRO_STATUS_WRITE_ERROR;
+}
+
+GOSnapshotType
+go_component_build_snapshot (GOComponent *component)
+{
+	cairo_surface_t *surface;
+	cairo_t *cr;
+	cairo_status_t status;
+	GOSnapshotType res;
+	struct write_state state;
+
+	g_return_val_if_fail (GO_IS_COMPONENT (component), GO_SNAPSHOT_NONE);
+
+	state.output = gsf_output_memory_new ();
+	state.length = 0;
+
+	switch (component->snapshot_type) {
+	case GO_SNAPSHOT_SVG:
+		surface = cairo_svg_surface_create_for_stream (
+                                     (cairo_write_func_t) gsf_output_from_cairo,
+                                     &state,
+                                     component->width * 72,
+                                     component->height * 72);
+		cr = cairo_create (surface);
+		go_component_render (component, cr, component->width * 72, component->height * 72);
+		break;
+	case GO_SNAPSHOT_PNG:
+		surface = cairo_image_surface_create (
+		                                     CAIRO_FORMAT_ARGB32,
+		                                     component->width * 300,
+		                                     component->height * 300);
+		cr = cairo_create (surface);
+		go_component_render (component, cr, component->width * 300, component->height * 300);
+		cairo_surface_write_to_png_stream (surface,
+		                     (cairo_write_func_t) gsf_output_from_cairo,
+		                     &state);
+		break;
+	default:
+		return GO_SNAPSHOT_NONE;
+	}
+	if (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS) {
+	} else
+		res = GO_SNAPSHOT_NONE;
+
+	cairo_surface_destroy (surface);
+	status = cairo_status (cr);
+	cairo_destroy (cr);
+	if (status == CAIRO_STATUS_SUCCESS && state.length > 0) {
+		component->snapshot_length = state.length;
+		component->snapshot_data = g_new (char, state.length);
+		memcpy(component->snapshot_data, gsf_output_memory_get_bytes ((GsfOutputMemory *) state.output), state.length);
+	}
+	g_object_unref (state.output);
+	return res;
+}
+
+GOComponent  *
+go_component_new_from_uri (char const *uri)
+{
+	char *mime_type;
+	GsfInput *input;
+	GOComponent *component;
+	GError *err;
+	size_t length;
+	char *data;
+
+	g_return_val_if_fail (uri && *uri, NULL);
+
+	mime_type = go_get_mime_type (uri);
+	if (!mime_type)
+		return NULL;
+	component = go_component_new_by_mime_type (mime_type);
+	g_free (mime_type);
+	input = go_file_open (uri, &err);
+	if (err) {
+		g_error_free (err);
+		return NULL;
+	}
+	length = gsf_input_size (input);
+	data = g_new (guint8, length);
+	gsf_input_read (input, length, data);
+	go_component_set_data (component, data, length);
+	component->destroy_notify = g_free;
+	return component;
+}
diff --git a/goffice/component/go-component.h b/goffice/component/go-component.h
index 255c9bb..6444362 100644
--- a/goffice/component/go-component.h
+++ b/goffice/component/go-component.h
@@ -2,7 +2,7 @@
 /*
  * go-component.h :
  *
- * Copyright (C) 2005 Jean Brefort (jean brefort normalesup org)
+ * Copyright (C) 2005-2010 Jean Brefort (jean brefort normalesup org)
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
@@ -30,6 +30,13 @@ G_BEGIN_DECLS
 
 GO_VAR_DECL double GOCXres, GOCYres;
 
+typedef enum {
+	GO_SNAPSHOT_NONE,
+	GO_SNAPSHOT_SVG,
+	GO_SNAPSHOT_PNG,
+	GO_SNAPSHOT_MAX
+} GOSnapshotType;
+
 struct _GOComponent {
 	GObject parent;
 
@@ -39,8 +46,13 @@ struct _GOComponent {
 	double default_width, default_ascent, default_descent;
 	gboolean needs_window, resizable, editable;
 	char const *data;
+	GDestroyNotify destroy_notify;
+	gpointer destroy_data;
 	int length;
 	GdkWindow *window;
+	GOSnapshotType snapshot_type;
+	void *snapshot_data;
+	size_t snapshot_length;
 };
 
 struct _GOComponentClass {
@@ -71,6 +83,7 @@ typedef struct _GOComponentClass GOComponentClass;
 
 GType	  go_component_get_type (void);
 GOComponent  *go_component_new_by_mime_type	(char const *mime_type);
+GOComponent  *go_component_new_from_uri	(char const *uri);
 
 void go_component_set_default_size (GOComponent *component,
 				    double width, double ascent, double descent);
@@ -89,6 +102,14 @@ void go_component_emit_changed (GOComponent *component);
 void go_component_set_command_context (GOCmdContext *cc);
 GOCmdContext *go_component_get_command_context (void);
 void go_component_render (GOComponent *component, cairo_t *cr, double width, double height);
+void go_component_get_size (GOComponent *component, double *width, double *height);
+
+void go_component_write_xml_sax (GOComponent *component, GsfXMLOut *output);
+typedef void (*GOComponentSaxHandler)(GOComponent *component, gpointer user_data);
+void go_component_sax_push_parser (GsfXMLIn *xin, xmlChar const **attrs,
+				       GOComponentSaxHandler handler, gpointer user_data);
+
+GOSnapshotType go_component_build_snapshot (GOComponent *component);
 
 G_END_DECLS
 
diff --git a/goffice/component/goffice-component.h b/goffice/component/goffice-component.h
index a97e83a..2b2cc44 100644
--- a/goffice/component/goffice-component.h
+++ b/goffice/component/goffice-component.h
@@ -28,9 +28,11 @@ G_BEGIN_DECLS
 
 typedef struct _GOComponent GOComponent;
 typedef struct _GOComponentType GOComponentType;
+typedef struct _GOComponentMimeDialog GOComponentMimeDialog;
 
 #include <goffice/component/go-component.h>
 #include <goffice/component/go-component-factory.h>
+#include <goffice/component/go-component-mime-dialog.h>
 G_END_DECLS
 
 #endif	/* GOFFICE_COMPONENT_H */
diff --git a/goffice/graph/gog-axis-line.c b/goffice/graph/gog-axis-line.c
index 44e924c..95dc8ff 100644
--- a/goffice/graph/gog-axis-line.c
+++ b/goffice/graph/gog-axis-line.c
@@ -1473,7 +1473,7 @@ axis_circle_render (GogAxisBase *axis_base, GogRenderer *renderer,
 			if (!first_label_done ||
 			    (!go_geometry_test_OBR_overlap (&txt_obr, &txt_obr_old) &&
 			     !go_geometry_test_OBR_overlap (&txt_obr, &txt_obr_first))) {
-				gog_renderer_draw_gostring 
+				gog_renderer_draw_gostring
 					(renderer, ticks[i].str,
 					 &label_pos, GO_ANCHOR_CENTER);
 				txt_obr_old = txt_obr;
@@ -2063,9 +2063,9 @@ xyz_process (GogAxisBaseAction action, GogView *view, GogViewPadding *padding,
 				for (i = 0; i < tick_nbr; i++) {
 					if (ticks[i].str == NULL)
 						continue;
-					gog_renderer_get_text_OBR 
+					gog_renderer_get_text_OBR
 						(view->renderer,
-						 ticks[i].str->str, 
+						 ticks[i].str->str,
 						 FALSE, &obr);
 					if (obr.w > label_w)
 						label_w = obr.w;
diff --git a/goffice/graph/gog-axis.c b/goffice/graph/gog-axis.c
index 61bbbdd..b9016e7 100644
--- a/goffice/graph/gog-axis.c
+++ b/goffice/graph/gog-axis.c
@@ -178,13 +178,13 @@ axis_format_value (GogAxis *axis, double val, GOString **str)
 	if (err)
 		*str = go_string_new ("#####");
 	else
-		*str = go_string_new_rich 
+		*str = go_string_new_rich
 			(g_strdup (pango_layout_get_text (layout)),
 			 -1,
 			 FALSE,
 			 pango_attr_list_ref (pango_layout_get_attributes (layout)),
 			 NULL);
-	
+
 	g_object_unref (layout);
 }
 
diff --git a/goffice/graph/gog-renderer.c b/goffice/graph/gog-renderer.c
index 9637ede..5bd6c41 100644
--- a/goffice/graph/gog-renderer.c
+++ b/goffice/graph/gog-renderer.c
@@ -818,9 +818,9 @@ gog_renderer_draw_gostring (GogRenderer *rend, GOString *str,
 	pango_layout_set_font_description (layout, style->font.font->desc);
 	pango_layout_get_size (layout, &iw, &ih);
 
-	obr.w = rend->scale * ((double) iw + (double) PANGO_SCALE / 2.0) 
+	obr.w = rend->scale * ((double) iw + (double) PANGO_SCALE / 2.0)
 		/ (double) PANGO_SCALE;
-	obr.h = rend->scale * ((double) ih + (double) PANGO_SCALE / 2.0) 
+	obr.h = rend->scale * ((double) ih + (double) PANGO_SCALE / 2.0)
 		/(double) PANGO_SCALE;
 	obr.alpha = -style->text_layout.angle * M_PI / 180.0;
 	obr.x = pos->x;
@@ -849,9 +849,9 @@ gog_renderer_draw_gostring (GogRenderer *rend, GOString *str,
 
 	cairo_save (cairo);
 	cairo_set_source_rgba (cairo, GO_COLOR_TO_CAIRO (style->font.color));
-	cairo_move_to (cairo, obr.x - (obr.w / 2.0) * cos (obr.alpha) + 
+	cairo_move_to (cairo, obr.x - (obr.w / 2.0) * cos (obr.alpha) +
 		       (obr.h / 2.0) * sin (obr.alpha),
-		       obr.y - (obr.w / 2.0) * sin (obr.alpha) - 
+		       obr.y - (obr.w / 2.0) * sin (obr.alpha) -
 		       (obr.h / 2.0) * cos (obr.alpha));
 	cairo_rotate (cairo, obr.alpha);
 	cairo_scale (cairo, rend->scale, rend->scale);
@@ -941,9 +941,9 @@ gog_renderer_get_gostring_OBR (GogRenderer *rend, GOString *str, GOGeometryOBR *
 	pango_layout_get_extents (layout, NULL, &logical);
 	g_object_unref (layout);
 
-	obr->w = rend->scale * ((double) logical.width + (double) PANGO_SCALE / 2.0) 
+	obr->w = rend->scale * ((double) logical.width + (double) PANGO_SCALE / 2.0)
 		/ (double) PANGO_SCALE;
-	obr->h = rend->scale * ((double) logical.height + (double) PANGO_SCALE / 2.0) 
+	obr->h = rend->scale * ((double) logical.height + (double) PANGO_SCALE / 2.0)
 		/(double) PANGO_SCALE;
 
 	/* Make sure invisible things don't skew size */
diff --git a/goffice/graph/gog-renderer.h b/goffice/graph/gog-renderer.h
index 203be4b..12414df 100644
--- a/goffice/graph/gog-renderer.h
+++ b/goffice/graph/gog-renderer.h
@@ -86,13 +86,13 @@ void  gog_renderer_draw_selection_rectangle	(GogRenderer *renderer, GogViewAlloc
 void  gog_renderer_draw_marker	  (GogRenderer *rend, double x, double y);
 
 void  gog_renderer_draw_text	  (GogRenderer *rend, char const *text,
-				   GogViewAllocation const *pos, 
+				   GogViewAllocation const *pos,
 				   GOAnchorType anchor,
 				   gboolean use_markup);
 
 void  gog_renderer_draw_gostring  (GogRenderer *rend,
 				   GOString *str,
-				   GogViewAllocation const *pos, 
+				   GogViewAllocation const *pos,
 				   GOAnchorType anchor);
 
 void  gog_renderer_get_gostring_OBR   (GogRenderer *rend, GOString *str,
diff --git a/goffice/graph/gog-series-labels.c b/goffice/graph/gog-series-labels.c
index 935d9ec..b027566 100644
--- a/goffice/graph/gog-series-labels.c
+++ b/goffice/graph/gog-series-labels.c
@@ -40,7 +40,7 @@ enum {
 struct {
 	char const *label;
 	GogSeriesLabelsPos pos;
-} positions [] = 
+} positions [] =
 {
 	{ N_("Centered"), GOG_SERIES_LABELS_CENTERED },
 	{ N_("Top"), GOG_SERIES_LABELS_TOP },
@@ -566,7 +566,7 @@ gog_series_labels_parent_changed (GogObject *obj, gboolean was_set)
 			break;
 		}
 	}
-	
+
 }
 
 static void
@@ -578,7 +578,7 @@ gog_series_labels_finalize (GObject *obj)
 	series_labels_parent_klass->finalize (obj);
 }
 
-static void 
+static void
 gog_series_labels_class_init (GObjectClass *obj_klass)
 {
 	GogObjectClass *gog_klass = (GogObjectClass *) obj_klass;
diff --git a/goffice/gtk/go-format-sel.c b/goffice/gtk/go-format-sel.c
index 78fad7c..6e75fbf 100644
--- a/goffice/gtk/go-format-sel.c
+++ b/goffice/gtk/go-format-sel.c
@@ -199,13 +199,13 @@ draw_format_preview (GOFormatSel *gfs, gboolean regen_format)
 
 	len = g_utf8_strlen (preview, -1);
 	if (len > FORMAT_PREVIEW_MAX)
-		strcpy (g_utf8_offset_to_pointer (preview, 
+		strcpy (g_utf8_offset_to_pointer (preview,
 						  FORMAT_PREVIEW_MAX - 5),
 			"...");
 
 	gtk_text_buffer_set_text (gfs->format.preview_buffer, preview, -1);
 
-	go_load_pango_attributes_into_buffer (attrs, 
+	go_load_pango_attributes_into_buffer (attrs,
 					      gfs->format.preview_buffer,
 					      preview);
 
diff --git a/goffice/utils/go-format.c b/goffice/utils/go-format.c
index c1d94cb..b3be4d0 100644
--- a/goffice/utils/go-format.c
+++ b/goffice/utils/go-format.c
@@ -3076,13 +3076,13 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 
 		case OP_MARKUP_SUPERSCRIPT_START:
 			if (layout)
-				markup_stack = g_slist_prepend 
+				markup_stack = g_slist_prepend
 					(markup_stack, GSIZE_TO_POINTER (dst->len));
 			break;
 
-		case OP_MARKUP_SUPERSCRIPT_END: 
+		case OP_MARKUP_SUPERSCRIPT_END:
 			if (layout) {
-				guint start = 0, 
+				guint start = 0,
 					end = (guint)dst->len;
 				PangoAttribute *attr;
 				if (markup_stack) {
@@ -3168,12 +3168,12 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 			gsize denom_chars = g_utf8_strlen (dst->str + fraction.denominator_start, -1);
 			gsize nom_chars = total_chars - denom_chars - 1;
 			int diff = denom_chars - nom_chars;
-			
+
 			if (fraction.n == 0) {
 				/* Replace all added characters by spaces of the right length.  */
 				char const *f = dst->str + fraction.nominator_start;
 				gsize chars = g_utf8_strlen (f, -1);
-				
+
 				if (chars > 0) {
 					/* We have layouts that have no fontmap set, we need to avoid them */
 					if (layout && pango_context_get_font_map (pango_layout_get_context (layout))) {
@@ -3209,12 +3209,12 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 							chars++;
 						}
 						go_list_free_custom (plist, (GFreeFunc) pango_item_free);
-					} 
-					
+					}
+
 					memset (dst->str + fraction.nominator_start, ' ', chars);
 					g_string_truncate (dst, fraction.nominator_start + chars);
 				}
-			} 
+			}
 
 			if (layout && pango_context_get_font_map (pango_layout_get_context (layout))) {
 				if (diff > 0) {
@@ -3239,20 +3239,20 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 						PangoAttribute *attr;
 						PangoRectangle ink_rect;
 						PangoRectangle logical_rect;
-						
+
 						pango_shape (zero_str->str, diff, &pi->analysis, glyphs);
 						pango_glyph_string_extents (glyphs,
 									    pi->analysis.font,
 									    &ink_rect,
 									    &logical_rect);
 						pango_glyph_string_free (glyphs);
-						
+
 						attr = pango_attr_shape_new (&ink_rect, &logical_rect);
 						attr->start_index = start;
 						attr->end_index = start + 1;
 						g_string_insert_c (dst, start, ' ');
 						pango_attr_list_insert (attrs, attr);
-						
+
 						start++;
 					}
 					go_list_free_custom (plist, (GFreeFunc) pango_item_free);
@@ -3663,7 +3663,7 @@ SUFFIX(go_format_value_gstring) (PangoLayout *layout, GString *str,
 				 unicode_minus);
 			FREE_NEW_STR;
 			return err;
-			
+
 		case GO_FMT_EMPTY:
 			SETUP_LAYOUT;
 			FREE_NEW_STR;
diff --git a/goffice/utils/go-pango-extras.h b/goffice/utils/go-pango-extras.h
index 33c7339..97f7573 100644
--- a/goffice/utils/go-pango-extras.h
+++ b/goffice/utils/go-pango-extras.h
@@ -13,8 +13,8 @@ void go_pango_attr_list_unset (PangoAttrList  *list,
 			       PangoAttrType type);
 gboolean go_pango_attr_list_is_empty (const PangoAttrList *attrs);
 
-void go_load_pango_attributes_into_buffer (PangoAttrList *markup, 
-					   GtkTextBuffer *buffer, 
+void go_load_pango_attributes_into_buffer (PangoAttrList *markup,
+					   GtkTextBuffer *buffer,
 					   gchar const *str);
 void go_create_std_tags_for_buffer (GtkTextBuffer *buffer);
 
diff --git a/plugins/plot_barcol/gog-barcol.c b/plugins/plot_barcol/gog-barcol.c
index a940a01..684cd6d 100644
--- a/plugins/plot_barcol/gog-barcol.c
+++ b/plugins/plot_barcol/gog-barcol.c
@@ -867,7 +867,7 @@ gog_barcol_view_render (GogView *view, GogViewAllocation const *bbox)
 			}
 			gog_renderer_pop_style (view->renderer);
 		}
-			
+
 	gog_chart_map_free (chart_map);
 }
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]