goffice r2165 - in trunk: . goffice/app goffice/graph goffice/utils



Author: jbrefort
Date: Sun Aug  3 10:08:28 2008
New Revision: 2165
URL: http://svn.gnome.org/viewvc/goffice?rev=2165&view=rev

Log:
2008-08-03  Jean Brefort  <jean brefort normalesup org>

	* configure.in: add a test for g_hash_table_iter_init.
	* goffice/app/go-doc-impl.h: serialize images in charts. [#348780]
	* goffice/app/go-doc.c: ditto.
	* goffice/app/go-doc.h: ditto.
	* goffice/graph/gog-chart-impl.h: removed unused 3d params.
	* goffice/graph/gog-graph.c: serialize images in charts.
	* goffice/graph/gog-object.c: ditto.
	* goffice/graph/gog-object.h:ditto.
	* goffice/graph/gog-style.c: ditto.
	* goffice/graph/gog-styled-object.c: ditto.
	* goffice/utils/go-image.c: ditto.
	* goffice/utils/go-image.h: ditto.



Modified:
   trunk/ChangeLog
   trunk/NEWS
   trunk/configure.in
   trunk/goffice/app/go-doc-impl.h
   trunk/goffice/app/go-doc.c
   trunk/goffice/app/go-doc.h
   trunk/goffice/graph/gog-chart-impl.h
   trunk/goffice/graph/gog-graph.c
   trunk/goffice/graph/gog-object.c
   trunk/goffice/graph/gog-object.h
   trunk/goffice/graph/gog-style.c
   trunk/goffice/graph/gog-styled-object.c
   trunk/goffice/utils/go-image.c
   trunk/goffice/utils/go-image.h

Modified: trunk/NEWS
==============================================================================
--- trunk/NEWS	(original)
+++ trunk/NEWS	Sun Aug  3 10:08:28 2008
@@ -1,6 +1,7 @@
 goffice 0.7.1:
 
 Jean:
+	* Serialize images used as background in charts. [#348780]
 	* Fix plot engines memory leaks. [#542506]
 	* Fix gog_style_font_sax_save() writes unescaped font name. [#543986]
 

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Sun Aug  3 10:08:28 2008
@@ -371,7 +371,7 @@
 SAVE_LIBS=$LIBS
 LIBS="$GOFFICE_LIBS $LIBS"
 AC_CHECK_FUNCS(cairo_surface_set_fallback_resolution cairo_ps_surface_set_eps)
-AC_CHECK_FUNCS(g_file_new_for_commandline_arg g_file_new_for_uri)
+AC_CHECK_FUNCS(g_file_new_for_commandline_arg g_file_new_for_uri g_hash_table_iter_init)
 LIBS=$SAVE_LIBS
 
 SAVE_CFLAGS=$CFLAGS

Modified: trunk/goffice/app/go-doc-impl.h
==============================================================================
--- trunk/goffice/app/go-doc-impl.h	(original)
+++ trunk/goffice/app/go-doc-impl.h	Sun Aug  3 10:08:28 2008
@@ -33,6 +33,7 @@
 	gboolean	 modified;
 	gboolean	 pristine;
 	GHashTable	*images;
+	GHashTable	*imagebuf; /* used when loading/saving images */
 };
 
 typedef struct {

Modified: trunk/goffice/app/go-doc.c
==============================================================================
--- trunk/goffice/app/go-doc.c	(original)
+++ trunk/goffice/app/go-doc.c	Sun Aug  3 10:08:28 2008
@@ -26,8 +26,11 @@
 
 #include <gsf/gsf-doc-meta-data.h>
 #include <gsf/gsf-impl-utils.h>
+#include <gsf/gsf-libxml.h>
 #include <glib/gi18n.h>
 
+#include <string.h>
+
 enum {
 	PROP_0,
 	PROP_URI,
@@ -292,6 +295,7 @@
 		NULL;
 }
 
+#ifndef HAVE_G_HASH_TABLE_ITER_INIT
 struct check_for_pixbuf {
 	GOImage *src_image;
 	GOImage *dst_image;
@@ -308,6 +312,7 @@
 			cl->dst_image = img;
 	}
 }
+#endif
 
 GOImage *
 go_doc_add_image (GODoc *doc, char const *id, GOImage *image)
@@ -315,19 +320,33 @@
 	GOImage *img;
 	int i = 0;
 	char *new_id;
+#ifdef HAVE_G_HASH_TABLE_ITER_INIT
+	GHashTableIter iter; 	 
+	char const *key;
+#else
 	struct check_for_pixbuf cl;
+#endif
 
 	if (doc->images == NULL)
 		doc->images = g_hash_table_new_full (g_str_hash, g_str_equal,
 						     g_free, g_object_unref);
 
 	/* check if the image is already there */
+#ifdef HAVE_G_HASH_TABLE_ITER_INIT
+	g_hash_table_iter_init (&iter, doc->images);
+	while (g_hash_table_iter_next (&iter, (void**) &key, (void**) &img))
+		if (go_image_same_pixbuf (image, img))
+			return img;
+#else
 	cl.src_image = image;
 	cl.dst_image = NULL;
 	g_hash_table_foreach (doc->images, check_for_pixbuf, &img);
 	if (cl.dst_image)
 		return cl.dst_image;
+#endif
 
+	if (!id || !*id)
+		id = _("Image");
 	/* now check if the id is not a duplicate */
 	if (g_hash_table_lookup (doc->images, id)) {
 		while (1) {
@@ -350,14 +369,128 @@
 	return doc->images;
 }
 
+void
+go_doc_init_write (GODoc *doc, GsfXMLOut *output)
+{
+	if (doc->imagebuf != NULL)
+		g_critical ("Images buffer should be NULL");
+	doc->imagebuf = g_hash_table_new (g_str_hash, g_str_equal);
+	g_object_set_data (G_OBJECT (gsf_xml_out_get_output (output)), "document", doc);
+}
+
+void
+go_doc_init_read (GODoc *doc, GsfInput *input)
+{
+	if (doc->imagebuf != NULL)
+		g_critical ("Images buffer should be NULL");
+	doc->imagebuf = g_hash_table_new (g_str_hash, g_str_equal);
+	g_object_set_data (G_OBJECT (input), "document", doc);
+}
+
+static void
+save_image_cb (gpointer key, gpointer img_, gpointer user)
+{
+	go_image_save ((GOImage *) img_, (GsfXMLOut *) user);
+}
+
+void
+go_doc_write (GODoc *doc, GsfXMLOut *output)
+{
+	gsf_xml_out_start_element (output, "GODoc");
+	g_hash_table_foreach (doc->imagebuf, save_image_cb, output);
+	gsf_xml_out_end_element (output);
+	g_hash_table_destroy (doc->imagebuf);
+	doc->imagebuf = NULL;
+}
+
+void
+go_doc_save_image (GODoc *doc, char const *id)
+{
+	if (!doc)
+		return;
+	if (!g_hash_table_lookup (doc->imagebuf, id)) {
+		GOImage *image = g_hash_table_lookup (doc->images, id);
+		if (image)
+			g_hash_table_insert (doc->imagebuf, (gpointer) id, image);
+	}
+}
+
 static void
-init_func (gpointer key, gpointer value, gpointer data)
+load_image (GsfXMLIn *xin, xmlChar const **attrs)
 {
-	//go_image_init_save ((GOImage*) value);
+	GODoc *doc = GO_DOC (xin->user_state);
+	GOImage *image;
+	xmlChar const **attr = 	attrs;
+	while (*attr && strcmp (*attr, "name"))
+		attr += 2;
+	if (!attr)
+		return;
+	image = (GOImage *) g_hash_table_lookup (doc->imagebuf, attr[1]);
+	if (!image) /* this should not occur, but if it does, we might want to load the image? */
+		return;
+	go_image_load_attrs (image, xin, attrs);
+	g_object_set_data (G_OBJECT (doc), "new image", image);
+}
+
+static void
+load_image_data (GsfXMLIn *xin, GsfXMLBlob *unknown)
+{
+	GODoc *doc = GO_DOC (xin->user_state);
+	GOImage *image = GO_IMAGE (g_object_get_data (G_OBJECT (doc), "new image")), *real;
+	g_return_if_fail (image != NULL);
+	go_image_load_data (image, xin);
+	real = go_doc_add_image (doc, go_image_get_name (image), image);
+	g_hash_table_remove (doc->imagebuf, (gpointer) go_image_get_name (image));
+	/* We have an issue if the image already existed and this can happen on pasting
+	 or if one day, we implement merging two documents (import a workbook as new sheets
+	 in an existing workbook). At the moment, I don't see any way to tell the clients
+	 to reference the image stored in the document instead of the one created by
+	 go_doc_image_fetch, so let's just make certain they share the same id. Anyway
+	 this should not happen very often (may be with a company logo?) and it is not so harmful
+	 since the duplicationwill not survive serialization. (Jean)
+	*/
+	if (real == image)
+		g_object_unref (image);
+	else
+		go_image_set_name (image, go_image_get_name (real));
+	g_object_set_data (G_OBJECT (doc), "new image", NULL);
+
+}
+
+void
+go_doc_read (GODoc *doc, GsfXMLIn *xin, xmlChar const **attrs)
+{
+	static GsfXMLInNode const dtd[] = {
+		GSF_XML_IN_NODE 	(DOC, DOC, 
+					 -1, "GODoc", 
+					 FALSE, NULL, NULL),
+		GSF_XML_IN_NODE 	(DOC, IMAGE,
+					 -1, "GOImage", 
+					 GSF_XML_CONTENT, 
+					 &load_image, &load_image_data),
+		GSF_XML_IN_NODE_END
+	};
+	static GsfXMLInDoc *xmldoc = NULL;
+	if (NULL == xmldoc)
+		xmldoc = gsf_xml_in_doc_new (dtd, NULL);
+	gsf_xml_in_push_state (xin, xmldoc, doc, NULL, attrs);
 }
 
 void
-go_doc_init_write (GODoc *doc)
+go_doc_end_read	(GODoc *doc)
 {
-	g_hash_table_foreach (doc->images, init_func, NULL);
+	g_hash_table_destroy (doc->imagebuf);
+	doc->imagebuf = NULL;
+}
+
+GOImage*
+go_doc_image_fetch (GODoc *doc, char const *id)
+{
+	GOImage *image = g_hash_table_lookup (doc->imagebuf, id);
+	if (!image) {
+		image = g_object_new (GO_IMAGE_TYPE, NULL);
+		go_image_set_name (image, id);
+		g_hash_table_insert (doc->imagebuf, (gpointer) go_image_get_name (image), image);
+	}
+	return image;
 }

Modified: trunk/goffice/app/go-doc.h
==============================================================================
--- trunk/goffice/app/go-doc.h	(original)
+++ trunk/goffice/app/go-doc.h	Sun Aug  3 10:08:28 2008
@@ -66,7 +66,13 @@
 GOImage		*go_doc_get_image	(GODoc *doc, char const *id);
 GOImage		*go_doc_add_image	(GODoc *doc, char const *id, GOImage *image);
 GHashTable	*go_doc_get_images	(GODoc *doc);
-void		 go_doc_init_write	(GODoc *doc);
+void		 go_doc_init_write	(GODoc *doc, GsfXMLOut *output);
+void		 go_doc_write		(GODoc *doc, GsfXMLOut *output);
+void		 go_doc_save_image	(GODoc *doc, char const *id);
+void		 go_doc_init_read	(GODoc *doc, GsfInput *input);
+void		 go_doc_read		(GODoc *doc, GsfXMLIn *xin, xmlChar const **attrs);
+void		 go_doc_end_read	(GODoc *doc);
+GOImage		*go_doc_image_fetch 	(GODoc *doc, char const *id);
 
 G_END_DECLS
 

Modified: trunk/goffice/graph/gog-chart-impl.h
==============================================================================
--- trunk/goffice/graph/gog-chart-impl.h	(original)
+++ trunk/goffice/graph/gog-chart-impl.h	Sun Aug  3 10:08:28 2008
@@ -29,8 +29,6 @@
 
 G_BEGIN_DECLS
 
-typedef struct _GogChart3dParms GogChart3dParms;
-
 struct _GogChart {
 	GogOutlinedObject	 base;
 
@@ -47,7 +45,6 @@
 
 	GogViewAllocation plot_area;
 	gboolean	  is_plot_area_manual;
-	GogChart3dParms *p3d;
 };
 typedef GogOutlinedObjectClass GogChartClass;
 

Modified: trunk/goffice/graph/gog-graph.c
==============================================================================
--- trunk/goffice/graph/gog-graph.c	(original)
+++ trunk/goffice/graph/gog-graph.c	Sun Aug  3 10:08:28 2008
@@ -89,14 +89,18 @@
 		break;
 	case GRAPH_PROP_DOCUMENT: {
 		GObject *obj = g_value_get_object (value);
+		if ((GODoc *) obj == graph->doc)
+			break;
 /*		if (graph->doc) {
 			g_object_unref (graph->doc);
 			graph->doc = NULL;
 		}
 		if (IS_GO_DOC (obj))
 			graph->doc = (GODoc *) g_object_ref (obj);*/
-		if (IS_GO_DOC (obj))
+		if (IS_GO_DOC (obj)) {
 			graph->doc = (GODoc *) obj;
+			gog_object_document_changed (GOG_OBJECT (graph), graph->doc);
+		}
 		break;
 	}
 

Modified: trunk/goffice/graph/gog-object.c
==============================================================================
--- trunk/goffice/graph/gog-object.c	(original)
+++ trunk/goffice/graph/gog-object.c	Sun Aug  3 10:08:28 2008
@@ -1937,3 +1937,13 @@
 			(gpointer )roles[i].id, (gpointer) (roles + i));
 	}
 }
+
+void
+gog_object_document_changed (GogObject *obj, GODoc *doc)
+{
+	GSList *ptr;
+	if (GOG_OBJECT_GET_CLASS (obj)->document_changed != NULL)
+		GOG_OBJECT_GET_CLASS (obj)->document_changed (obj, doc);
+	for (ptr = obj->children; ptr != NULL; ptr = ptr->next)
+		gog_object_document_changed (GOG_OBJECT (ptr->data), doc);
+}

Modified: trunk/goffice/graph/gog-object.h
==============================================================================
--- trunk/goffice/graph/gog-object.h	(original)
+++ trunk/goffice/graph/gog-object.h	Sun Aug  3 10:08:28 2008
@@ -119,6 +119,7 @@
 					 GogEditor *editor,
 					 GogDataAllocator *dalloc, 
 					 GOCmdContext *cc);
+	void	     (*document_changed)(GogObject *obj, GODoc *doc);
 
 	/* signals */
 	void (*changed)		(GogObject *obj, gboolean size);
@@ -198,6 +199,8 @@
 					   GogObjectRole const *roles, unsigned int n_roles);
 void 	 gog_object_request_editor_update (GogObject *obj);
 
+void	 gog_object_document_changed	  (GogObject *obj, GODoc *doc);
+
 G_END_DECLS
 
 #endif /* GOG_OBJECT_H */

Modified: trunk/goffice/graph/gog-style.c
==============================================================================
--- trunk/goffice/graph/gog-style.c	(original)
+++ trunk/goffice/graph/gog-style.c	Sun Aug  3 10:08:28 2008
@@ -21,6 +21,7 @@
  */
 
 #include <goffice/goffice-config.h>
+#include <goffice/app/go-doc.h>
 #include <goffice/graph/gog-style.h>
 #include <goffice/graph/gog-styled-object.h>
 #include <goffice/math/go-math.h>
@@ -1399,7 +1400,8 @@
 		/* FIXME : type is not a good characterization */
 		gsf_xml_out_add_cstr_unchecked (output, "type",
 			image_tiling_as_str (style->fill.image.type));
-/* TODO save the pixels */
+		gsf_xml_out_add_cstr (output, "name", go_image_get_name (style->fill.image.image));
+		go_doc_save_image ((GODoc *) g_object_get_data (G_OBJECT (gsf_xml_out_get_output (output)), "document"), go_image_get_name (style->fill.image.image));
 		gsf_xml_out_end_element (output);
 		break;
 	default:
@@ -1717,13 +1719,15 @@
 gog_style_sax_load_fill_image (GsfXMLIn *xin, xmlChar const **attrs)
 {
 	GogStyle *style = GOG_STYLE (xin->user_state);
+	GODoc *doc = (GODoc *) g_object_get_data (G_OBJECT (gsf_xml_in_get_input (xin)), "document");
 	g_return_if_fail (style->fill.type == GOG_FILL_STYLE_IMAGE);
+	g_return_if_fail (IS_GO_DOC (doc));
 	/* TODO: load the pixels */
 	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
 		if (0 == strcmp (attrs[0], "type")) {
 			style->fill.image.type = str_as_image_tiling (attrs[1]);
-			break;
-		}
+		} else if (0 == strcmp (attrs[0], "name"))
+			style->fill.image.image = g_object_ref (go_doc_image_fetch (doc, attrs[1]));
 }
 
 static void
@@ -1843,7 +1847,7 @@
 					 &gog_style_sax_load_fill_gradient, NULL),
 		GSF_XML_IN_NODE 	(STYLE_FILL, FILL_IMAGE, 
 					 -1, "image", 
-					 GSF_XML_CONTENT, 
+					 GSF_XML_NO_CONTENT, 
 					 &gog_style_sax_load_fill_image, NULL),
 		GSF_XML_IN_NODE 	(STYLE, STYLE_MARKER,	
 					 -1, "marker", 
@@ -2116,6 +2120,11 @@
 				return cairo_pattern_create_rgba (1, 1, 1, 1);
 
 			cr_pattern = go_image_create_cairo_pattern (style->fill.image.image);
+			if (cr_pattern == NULL) {
+				/* don't reference anymore an invalid image */
+				((GogStyle *) style)->fill.image.image = NULL;
+				return cairo_pattern_create_rgba (1, 1, 1, 1);
+			}
 			g_object_get (style->fill.image.image, "width", &w, "height", &h, NULL);
 			cairo_pattern_set_extend (cr_pattern, CAIRO_EXTEND_REPEAT);
 			switch (style->fill.image.type) {

Modified: trunk/goffice/graph/gog-styled-object.c
==============================================================================
--- trunk/goffice/graph/gog-styled-object.c	(original)
+++ trunk/goffice/graph/gog-styled-object.c	Sun Aug  3 10:08:28 2008
@@ -44,6 +44,32 @@
 static GObjectClass *parent_klass;
 
 static void
+gog_styled_object_document_changed (GogObject *obj, GODoc *doc)
+{
+	GogStyledObject *gso = GOG_STYLED_OBJECT (obj);
+	GogStyle *style = gso->style;
+	if ((style->interesting_fields & GOG_STYLE_FILL) &&
+	    (style->fill.type == GOG_FILL_STYLE_IMAGE) &&
+	    (style->fill.image.image != NULL)) {
+		GOImage *image;
+		char *id = g_strdup (go_image_get_name (style->fill.image.image));
+		/* remove the (nnn) modifier if any */
+		int i = strlen (id) - 1;
+		if (id[i] == ')') {
+			i--;
+			while (id[i] >= '0' && id[i] <= '9')
+				i--;
+			if (id[i] == '(')
+				id[i] = 0;
+		}
+		image = go_doc_add_image (doc, id, style->fill.image.image);
+		g_free (id);
+		g_object_unref (style->fill.image.image);
+		style->fill.image.image = image;
+	}
+}
+
+static void
 gog_styled_object_set_property (GObject *obj, guint param_id,
 				GValue const *value, GParamSpec *pspec)
 {
@@ -154,6 +180,7 @@
 	gobject_klass->finalize	    = gog_styled_object_finalize;
 	gog_klass->populate_editor  = styled_object_populate_editor;
 	gog_klass->parent_changed   = gog_styled_object_parent_changed;
+	gog_klass->document_changed = gog_styled_object_document_changed;
 	style_klass->init_style	    = gog_styled_object_init_style;
 
 	g_object_class_install_property (gobject_klass, STYLED_OBJECT_PROP_STYLE,

Modified: trunk/goffice/utils/go-image.c
==============================================================================
--- trunk/goffice/utils/go-image.c	(original)
+++ trunk/goffice/utils/go-image.c	Sun Aug  3 10:08:28 2008
@@ -25,6 +25,7 @@
 #include <goffice/utils/go-cairo.h>
 #include <glib/gi18n-lib.h>
 #include <string.h>
+#include <gsf/gsf-utils.h>
 #include <gsf/gsf-impl-utils.h>
 #include <glib/gi18n-lib.h>
 
@@ -571,7 +572,9 @@
 {
 	g_return_val_if_fail (image != NULL, NULL);
 	if (!image->pixbuf)
-		return NULL; /* we might build the pixbuf if necessary */
+		go_image_get_pixbuf (image);
+	if (!image->pixbuf)
+		return NULL;
 	if (!image->thumbnail) {
 		int w, h;
 		if (image->width <= THUMBNAIL_SIZE && image->height <= THUMBNAIL_SIZE)
@@ -664,6 +667,10 @@
 	int size;
 	g_return_val_if_fail (IS_GO_IMAGE (first), FALSE);
 	g_return_val_if_fail (IS_GO_IMAGE (second), FALSE);
+	if (!first->pixbuf)
+		go_image_get_pixbuf (first);
+	if (!second->pixbuf)
+		go_image_get_pixbuf (second);
 	if (!first->pixbuf || !second->pixbuf)
 		return FALSE;
 	if (gdk_pixbuf_get_n_channels (first->pixbuf) != gdk_pixbuf_get_n_channels (second->pixbuf))
@@ -688,3 +695,41 @@
 	return FALSE;
 #endif
 }
+
+void
+go_image_save (GOImage *image, GsfXMLOut *output)
+{
+	g_return_if_fail (IS_GO_IMAGE (image) && image->name);
+	gsf_xml_out_start_element (output, "GOImage");
+	gsf_xml_out_add_cstr (output, "name", image->name);
+	gsf_xml_out_add_int (output, "width", image->width);
+	gsf_xml_out_add_int (output, "height", image->height);
+	gsf_xml_out_add_int (output, "rowstride", image->rowstride);
+	gsf_xml_out_add_base64 (output, NULL,
+			go_image_get_pixels (image), image->height * image->rowstride);
+	gsf_xml_out_end_element (output);
+}
+
+void
+go_image_load_attrs (GOImage *image, GsfXMLIn *xin, xmlChar const **attrs)
+{
+	xmlChar const **attr;
+	g_return_if_fail (image != NULL);
+	for (attr = attrs; attr != NULL && attr[0] && attr[1] ; attr += 2)
+		if (0 == strcmp (attr[0], "width"))
+			image->width = strtol (attr[1], NULL, 10);
+		else if (0 == strcmp (attr[0], "height"))
+			image->height= strtol (attr[1], NULL, 10);
+		else if (0 == strcmp (attr[0], "rowstride"))
+			image->rowstride = strtol (attr[1], NULL, 10);
+}
+
+void
+go_image_load_data (GOImage *image, GsfXMLIn *xin)
+{
+	int length;
+	length = gsf_base64_decode_simple (xin->content->str, strlen(xin->content->str));
+	image->data = g_memdup (xin->content->str, length);
+	image->target_cairo = TRUE;
+}
+

Modified: trunk/goffice/utils/go-image.h
==============================================================================
--- trunk/goffice/utils/go-image.h	(original)
+++ trunk/goffice/utils/go-image.h	Sun Aug  3 10:08:28 2008
@@ -89,6 +89,10 @@
 
 gboolean	 go_image_same_pixbuf		(GOImage *first, GOImage *second);
 
+void		 go_image_save			(GOImage *image, GsfXMLOut *output);
+void		 go_image_load_attrs		(GOImage *image, GsfXMLIn *xin, xmlChar const **attrs);
+void		 go_image_load_data		(GOImage *image, GsfXMLIn *xin);
+
 G_END_DECLS
 
 #endif /* GO_IMAGE_H */



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