[goffice] Serialize color maps



commit d39aab4dc8d25e300bbdbcbe9db61f50a785144a
Author: Jean Brefort <jean brefort normalesup org>
Date:   Sat Nov 3 18:23:07 2012 +0100

    Serialize color maps

 ChangeLog                                |   23 +++
 docs/reference/goffice-0.10-sections.txt |   13 +-
 goffice/Makefile.am                      |    5 +-
 goffice/app/go-doc.c                     |   68 ++++----
 goffice/app/go-doc.h                     |    6 +-
 goffice/graph/gog-axis-color-map.c       |  263 ++++++++++++++++++++++--------
 goffice/graph/gog-axis-color-map.h       |    7 +-
 goffice/graph/gog-axis.c                 |   46 ++++--
 goffice/utils/goffice-utils.c            |  104 ++++++++++++
 goffice/utils/goffice-utils.h            |    2 +
 10 files changed, 409 insertions(+), 128 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index f990b48..c0605c9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2012-11-03  Jean Brefort  <jean brefort normalesup org>
+
+	* goffice/Makefile.am: add goffice-utils.c.
+	* goffice/app/go-doc.c (go_doc_finalize), (go_doc_write),
+	(load_color_map), (go_doc_read), (go_doc_save_color_map): save and load
+	used color maps.
+	* goffice/app/go-doc.h: ditto.
+	* goffice/graph/gog-axis-color-map.c (gog_axis_color_map_finalize),
+	(gog_axis_color_map_init), (gog_axis_color_map_get_id),
+	(gog_axis_color_map_from_colors), (save_name_cb),
+	(gog_axis_color_map_write), (color_stop_start), (map_start),
+	(name_start), (name_end), (color_map_loaded),
+	(color_map_load_from_uri), (parse_done_cb),
+	(gog_axis_color_map_sax_push_parser),
+	(gog_axis_color_map_get_from_id), (_gog_axis_color_maps_init): ditto.
+	* goffice/graph/gog-axis-color-map.h: ditto.
+	* goffice/graph/gog-axis.c (gog_axis_prep_sax),
+	(gog_axis_sax_save), (gog_axis_set_property),
+	(gog_axis_get_property), (gog_axis_persist_init): ditto.
+	* goffice/utils/goffice-utils.h: new uuid generator copied from
+	telepathy-gabble.
+	* goffice/utils/goffice-utils.c: new file.
+
 2012-11-01  Jean Brefort  <jean brefort normalesup org>
 
 	* goffice/Makefile.am:  add new ui file.
diff --git a/docs/reference/goffice-0.10-sections.txt b/docs/reference/goffice-0.10-sections.txt
index 8f53a72..e0dd922 100644
--- a/docs/reference/goffice-0.10-sections.txt
+++ b/docs/reference/goffice-0.10-sections.txt
@@ -843,8 +843,6 @@ go_distribution_get_type
 GODoc
 go_doc_add_image
 go_doc_end_read
-go_doc_foreach_color_map
-go_doc_get_color_map
 go_doc_get_dirty_time
 go_doc_get_image
 go_doc_get_images
@@ -856,6 +854,7 @@ go_doc_init_write
 go_doc_is_dirty
 go_doc_is_pristine
 go_doc_read
+go_doc_save_color_map
 go_doc_save_image
 go_doc_set_dirty
 go_doc_set_dirty_time
@@ -2748,10 +2747,13 @@ GogAxisColorMapHandler
 gog_axis_color_map_foreach
 gog_axis_color_map_from_colors
 gog_axis_color_map_get_color
-gog_axis_color_map_get_from_name
+gog_axis_color_map_get_from_id
 gog_axis_color_map_get_max
+gog_axis_color_map_get_id
 gog_axis_color_map_get_name
 gog_axis_color_map_get_snapshot
+gog_axis_color_map_sax_push_parser
+gog_axis_color_map_write
 <SUBSECTION Standard>
 GOG_AXIS_COLOR_MAP
 GOG_IS_AXIS_COLOR_MAP
@@ -3554,3 +3556,8 @@ GO_TYPE_SEARCH_REPLACE
 go_search_replace_get_type
 </SECTION>
 
+<SECTION>
+<FILE>go-utils</FILE>
+<TITLE>Miscellaneous</TITLE>
+go_uuid
+</SECTION>
diff --git a/goffice/Makefile.am b/goffice/Makefile.am
index 9c8d744..979773d 100644
--- a/goffice/Makefile.am
+++ b/goffice/Makefile.am
@@ -360,6 +360,7 @@ math_HEADERS = 	\
 utils_SOURCES =	\
 	utils/go-marshalers.list	\
 	\
+	utils/goffice-utils.c	\
 	utils/go-color.c		\
 	utils/go-file.c		\
 	utils/go-font.c		\
@@ -397,7 +398,7 @@ utils_SOURCES =	\
 
 utilsdir = $(goffice_include_dir)/utils
 utils_HEADERS = 	\
-	utils/goffice-utils.h		\
+	utils/goffice-utils.h	\
 	utils/go-cairo.h		\
 	utils/go-color.h		\
 	utils/go-file.h		\
@@ -423,7 +424,7 @@ utils_HEADERS = 	\
 	utils/go-glib-extras.h	\
 	utils/go-libxml-extras.h	\
 	utils/go-pango-extras.h	\
-	utils/go-gdk-pixbuf.h		\
+	utils/go-gdk-pixbuf.h	\
 	utils/go-persist.h		\
 	utils/go-bezier.h		\
 	utils/go-editor.h		\
diff --git a/goffice/app/go-doc.c b/goffice/app/go-doc.c
index 25997fd..971800f 100644
--- a/goffice/app/go-doc.c
+++ b/goffice/app/go-doc.c
@@ -35,7 +35,6 @@ struct _GODocPrivate {
 	GHashTable	*imagebuf; /* used when loading/saving images */
 
 	/* color maps */
-	GSList	*colormaps; /* document graph axis color maps */
 	GSList	*colormapsbuf; /* used when loading/saving color maps */
 };
 
@@ -136,7 +135,6 @@ go_doc_finalize (GObject *obj)
 	if (doc->images)
 		g_hash_table_destroy (doc->images);
 	doc->images = NULL;
-	g_slist_free_full (doc->priv->colormaps, g_object_unref);
 	g_free (doc->priv);
 	doc->priv = NULL;
 
@@ -506,15 +504,29 @@ save_image_cb (gpointer key, gpointer img_, gpointer user)
 void
 go_doc_write (GODoc *doc, GsfXMLOut *output)
 {
-	if (g_hash_table_size (doc->priv->imagebuf) > 0) {
+	GSList *ptr;
+	if (g_hash_table_size (doc->priv->imagebuf) > 0 ||
+	    doc->priv->colormapsbuf != NULL) {
 		gsf_xml_out_start_element (output, "GODoc");
 		g_hash_table_foreach (doc->priv->imagebuf, save_image_cb, output);
+		for (ptr = doc->priv->colormapsbuf; ptr; ptr = ptr->next)
+			gog_axis_color_map_write (GOG_AXIS_COLOR_MAP (ptr->data), output);
+		g_slist_free (doc->priv->colormapsbuf);
+		doc->priv->colormapsbuf = NULL;
 		gsf_xml_out_end_element (output);
 	}
 	g_hash_table_destroy (doc->priv->imagebuf);
 	doc->priv->imagebuf = NULL;
 }
 
+/**
+ * go_doc_save_image:
+ * @doc: a #GODoc
+ * @id: the Id of the #GOImage to save
+ *
+ * Saves the image with the document. Each image will be saved only
+ * once.
+ **/
 void
 go_doc_save_image (GODoc *doc, char const *id)
 {
@@ -578,6 +590,12 @@ load_image_data (GsfXMLIn *xin, GsfXMLBlob *unknown)
 	g_object_set_data (G_OBJECT (doc), "new image", NULL);
 }
 
+static void
+load_color_map (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	gog_axis_color_map_sax_push_parser (xin, attrs);
+}
+
 void
 go_doc_read (GODoc *doc, GsfXMLIn *xin, xmlChar const **attrs)
 {
@@ -589,6 +607,10 @@ go_doc_read (GODoc *doc, GsfXMLIn *xin, xmlChar const **attrs)
 					 -1, "GOImage",
 					 GSF_XML_CONTENT,
 					 &load_image, &load_image_data),
+		GSF_XML_IN_NODE 	(DOC, COLOR_MAP,
+					 -1, "GogAxisColorMap",
+					 GSF_XML_NO_CONTENT,
+					 &load_color_map, NULL),
 		GSF_XML_IN_NODE_END
 	};
 	static GsfXMLInDoc *xmldoc = NULL;
@@ -634,39 +656,19 @@ go_doc_image_fetch (GODoc *doc, char const *id, GType type)
 }
 
 /**
- * go_doc_get_color_map:
- * @doc: a #GODoc
- * @name: the color map name to search for
- *
- * Retrieves the color map whose name is @name. The difference with
- * gog_axis_color_map_get_from_name() is that color maps specific to the
- * document are searched first if any.
- * Returns: (transfer none): the found color map or %NULL.
- **/
-GogAxisColorMap	const *
-go_doc_get_color_map (GODoc *doc, char const *name)
-{
-	g_return_val_if_fail (GO_IS_DOC (doc) && name && *name, NULL);
-#if 0
-	if (doc->priv->colormaps == NULL)
-		return NULL;
-	return g_hash_table_lookup (doc->priv->colormaps, name);
-#endif
-	return gog_axis_color_map_get_from_name (name);
-}
-
-/**
- * go_doc_foreach_color_map:
+ * go_doc_save_color_map:
  * @doc: a #GODoc
- * @handler: (scope call): a #GogAxisColorMapHandler
- * @user_data: data to pass to @handler
+ * @map: the #GogAxisColorMap to save
  *
- * Executes @handler to each color map installed on the system or specific to
- * @doc. This function calls gog_axis_color_map_foreach() but don't execute the
- * handler if a color map with the same name exists in the document.
+ * Saves the color map with the document. Each color map will be saved only
+ * once.
  **/
 void
-go_doc_foreach_color_map (GODoc *doc, GogAxisColorMapHandler handler, gpointer user_data)
+go_doc_save_color_map (GODoc *doc, GogAxisColorMap	const *map)
 {
-	gog_axis_color_map_foreach (handler, user_data);
+	GSList *ptr;
+	for (ptr = doc->priv->colormapsbuf; ptr; ptr = ptr->next)
+		if (ptr->data == map) /* already marked for saving */
+			return;
+	doc->priv->colormapsbuf = g_slist_prepend (doc->priv->colormapsbuf, (void *) map);
 }
diff --git a/goffice/app/go-doc.h b/goffice/app/go-doc.h
index 1c1a14b..82be494 100644
--- a/goffice/app/go-doc.h
+++ b/goffice/app/go-doc.h
@@ -61,11 +61,7 @@ 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, GType type);
-
-GogAxisColorMap	const *go_doc_get_color_map	(GODoc *doc, char const *name);
-void		 go_doc_foreach_color_map	(GODoc *doc,
-			                             GogAxisColorMapHandler handler,
-			                             gpointer user_data);
+void		 go_doc_save_color_map (GODoc *doc, GogAxisColorMap	const *map);
 
 G_END_DECLS
 
diff --git a/goffice/graph/gog-axis-color-map.c b/goffice/graph/gog-axis-color-map.c
index 9bf7a86..3016036 100644
--- a/goffice/graph/gog-axis-color-map.c
+++ b/goffice/graph/gog-axis-color-map.c
@@ -23,6 +23,7 @@
 #include <goffice/goffice.h>
 #include <goffice/goffice-priv.h>
 
+#include <gsf/gsf-input.h>
 #include <gsf/gsf-impl-utils.h>
 #include <glib/gi18n-lib.h>
 #include <string.h>
@@ -45,7 +46,7 @@
  **/
 struct _GogAxisColorMap {
 	GObject base;
-	char *name, *local_name;
+	char *id, *name;
 	GHashTable *names;
 	unsigned size; /* colors number */
 	unsigned *limits;
@@ -59,10 +60,10 @@ static void
 gog_axis_color_map_finalize (GObject *obj)
 {
 	GogAxisColorMap *map = GOG_AXIS_COLOR_MAP (obj);
+	g_free (map->id);
+	map->id = NULL;
 	g_free (map->name);
 	map->name = NULL;
-	g_free (map->local_name);
-	map->local_name = NULL;
 	g_free (map->limits);
 	map->limits = NULL;
 	g_free (map->colors);
@@ -84,6 +85,7 @@ gog_axis_color_map_class_init (GObjectClass *gobject_klass)
 static void
 gog_axis_color_map_init (GogAxisColorMap *map)
 {
+	map->names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 }
 
 GSF_CLASS (GogAxisColorMap, gog_axis_color_map,
@@ -132,13 +134,27 @@ gog_axis_color_map_get_max (GogAxisColorMap const *map)
 }
 
 /**
- * gog_axis_color_map_get_snapshot:
+ * gog_axis_color_map_get_id:
  * @map: a #GogAxisMap
  *
  * Retrieves the color map name.
  * Returns: (transfer none): the map name.
  **/
 char const *
+gog_axis_color_map_get_id (GogAxisColorMap const *map)
+{
+	g_return_val_if_fail (GOG_IS_AXIS_COLOR_MAP (map), NULL);
+	return map->id;
+}
+
+/**
+ * gog_axis_color_map_get_name:
+ * @map: a #GogAxisMap
+ *
+ * Retrieves the color map localized name.
+ * Returns: (transfer none): the map name.
+ **/
+char const *
 gog_axis_color_map_get_name (GogAxisColorMap const *map)
 {
 	g_return_val_if_fail (GOG_IS_AXIS_COLOR_MAP (map), NULL);
@@ -264,6 +280,7 @@ gog_axis_color_map_from_colors (char const *name, unsigned nb, GOColor const *co
 {
 	unsigned i;
 	GogAxisColorMap *color_map = g_object_new (GOG_TYPE_AXIS_COLOR_MAP, NULL);
+	color_map->id = g_strdup (name);
 	color_map->name = g_strdup (name);
 	color_map->size = nb;
 	color_map->limits = g_new (unsigned, nb);
@@ -303,6 +320,44 @@ gog_axis_color_map_registry_add (GogAxisColorMap *map)
 	color_maps = g_slist_append (color_maps, map);
 }
 
+static void
+save_name_cb (char const *lang, char const *name, GsfXMLOut *output)
+{
+	gsf_xml_out_start_element (output, "name");
+	if (strcmp (lang, "C"))
+		gsf_xml_out_add_cstr_unchecked (output, "xml:lang", lang);
+	gsf_xml_out_add_cstr_unchecked (output, NULL, name);
+	gsf_xml_out_end_element (output);
+}
+
+/**
+ * gog_axis_color_map_write:
+ * @map: a #GogAxisColorMap
+ * @output: a #GsfXMLOut
+ *
+ * Writes the color map as an XML node to @output.
+ **/
+void
+gog_axis_color_map_write (GogAxisColorMap const *map, GsfXMLOut *output)
+{
+	unsigned i;
+	char *buf;
+	g_return_if_fail (GOG_IS_AXIS_COLOR_MAP (map));
+
+	gsf_xml_out_start_element (output, "GogAxisColorMap");
+	gsf_xml_out_add_cstr_unchecked (output, "id", map->id);
+	g_hash_table_foreach (map->names, (GHFunc) save_name_cb, output);
+	for (i = 0; i < map->size; i++) {
+		gsf_xml_out_start_element (output, "color-stop");
+		gsf_xml_out_add_uint (output, "bin", map->limits[i]);
+		buf = go_color_as_str (map->colors[i]);
+		gsf_xml_out_add_cstr_unchecked (output, "color", buf);
+		g_free (buf);
+		gsf_xml_out_end_element (output);
+	}
+	gsf_xml_out_end_element (output);
+}
+
 struct _color_stop {
 	unsigned bin;
 	GOColor color;
@@ -310,7 +365,7 @@ struct _color_stop {
 
 struct color_map_load_state {
 	GogAxisColorMap *map;
-	char *lang, *local_name;
+	char *lang, *name;
 	unsigned name_lang_score;
 	char const * const *langs;
 	GSList *color_stops;
@@ -326,6 +381,8 @@ color_stop_start (GsfXMLIn *xin, xmlChar const **attrs)
 	gboolean color_found = FALSE;
 	gboolean bin_found = FALSE;
 
+	if (state->map->name)
+		return;
 	for (; attrs != NULL && *attrs ; attrs += 2)
 		if (0 == strcmp (*attrs, "bin")) {
 			bin = strtoul (attrs[1], &end, 10);
@@ -340,7 +397,20 @@ color_stop_start (GsfXMLIn *xin, xmlChar const **attrs)
 		state->color_stops = g_slist_append (state->color_stops, stop);
 	} else
 		g_warning ("[GogAxisColorMap]: Invalid color stop");
-	
+}
+
+static void
+map_start (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	struct color_map_load_state	*state = (struct color_map_load_state *) xin->user_state;
+	if (state->map ==  NULL) {
+		state->map = g_object_new (GOG_TYPE_AXIS_COLOR_MAP, NULL);
+		for (; attrs && *attrs; attrs +=2)
+			if (!strcmp ((char const *) *attrs, "id")) {
+				state->map->id = g_strdup ((char const *) attrs[1]);
+				break;
+			}
+	}
 }
 
 static void
@@ -348,6 +418,8 @@ name_start (GsfXMLIn *xin, xmlChar const **attrs)
 {
 	struct color_map_load_state	*state = (struct color_map_load_state *) xin->user_state;
 	unsigned i;
+	if (state->map->name)
+		return;
 	for (i = 0; attrs != NULL && attrs[i] && attrs[i+1] ; i += 2)
 		if (0 == strcmp (attrs[i], "xml:lang"))
 			state->lang = g_strdup (attrs[i+1]);
@@ -358,30 +430,25 @@ name_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
 {
 	struct color_map_load_state	*state = (struct color_map_load_state *) xin->user_state;
 	char *name = NULL;
+	if (state->map->name)
+		return;
 	if (xin->content->str == NULL)
 		return;
 	name = g_strdup (xin->content->str);
-	if (state->map == NULL) {
-		state->map = g_object_new (GOG_TYPE_AXIS_COLOR_MAP, NULL);
-		state->map->names = g_hash_table_new_full (g_str_hash, g_str_equal,
-		                                           g_free, g_free);
-	}
-	if (state->lang == NULL) {
-		state->map->name = name;
-	} else {
-		if (state->name_lang_score > 0 && state->langs[0] != NULL) {
-			unsigned i;
-			for (i = 0; i < state->name_lang_score && state->langs[i] != NULL; i++) {
-				if (strcmp (state->langs[i], state->lang) == 0) {
-					g_free (state->local_name);
-					state->local_name = g_strdup (name);
-					state->name_lang_score = i;
-				}
+	if (state->lang == NULL)
+	state->lang = g_strdup ("C");
+	if (state->name_lang_score > 0 && state->langs[0] != NULL) {
+		unsigned i;
+		for (i = 0; i < state->name_lang_score && state->langs[i] != NULL; i++) {
+			if (strcmp (state->langs[i], state->lang) == 0) {
+				g_free (state->name);
+				state->name = g_strdup (name);
+				state->name_lang_score = i;
 			}
 		}
-		g_hash_table_replace (state->map->names, state->lang, name); 
-		state->lang = NULL;
 	}
+	g_hash_table_replace (state->map->names, state->lang, name);
+	state->lang = NULL;
 }
 
 static int
@@ -390,18 +457,52 @@ color_stops_cmp (struct _color_stop *first, struct _color_stop *second)
 	return (first->bin < second->bin)? -1: (int) (first->bin - second->bin);
 }
 
+static GsfXMLInNode const color_map_dtd[] = {
+	GSF_XML_IN_NODE (THEME, THEME, -1, "GogAxisColorMap", GSF_XML_NO_CONTENT, map_start, NULL),
+		GSF_XML_IN_NODE (THEME, NAME, -1, "name", GSF_XML_CONTENT, name_start, name_end),
+		GSF_XML_IN_NODE (THEME, UNAME, -1, "_name", GSF_XML_CONTENT, name_start, name_end),
+		GSF_XML_IN_NODE (THEME, STOP, -1, "color-stop", GSF_XML_CONTENT, color_stop_start, NULL),
+	GSF_XML_IN_NODE_END
+};
+static GsfXMLInDoc *xml = NULL;
+
+static void
+color_map_loaded (struct color_map_load_state *state, char const *uri, gboolean delete_invalid)
+{
+	GSList *ptr;
+	if (state->map && state->map->name)
+		return;
+	state->map->name = state->name;
+	/* populates the colors */
+	/* first sort the color list according to bins */
+	ptr = state->color_stops = g_slist_sort (state->color_stops, (GCompareFunc) color_stops_cmp);
+	if (state->map->id == NULL || ((struct _color_stop *) ptr->data)->bin != 0) {
+		g_warning ("[GogAxisColorMap]: Invalid color map in %s", uri);
+		if (delete_invalid) {
+			g_object_unref (state->map);
+			state->map = NULL;
+		}
+	} else {
+		unsigned cur_bin, n = 0;
+		state->map->size = g_slist_length (state->color_stops);
+		state->map->limits = g_new (unsigned, state->map->size);
+		state->map->colors = g_new (GOColor, state->map->size);
+		while (ptr) {
+			cur_bin = state->map->limits[n] = ((struct _color_stop *) ptr->data)->bin;
+			state->map->colors[n++] = ((struct _color_stop *) ptr->data)->color;
+			do (ptr = ptr->next);
+			while (ptr && ((struct _color_stop *) ptr->data)->bin == cur_bin);
+		}
+		state->map->size = n; /* we drop duplicate bins */
+	}
+	g_slist_free_full (state->color_stops, g_free);
+	g_free (state->lang);
+}
+
 static void
 color_map_load_from_uri (char const *uri)
 {
-	static GsfXMLInNode const color_map_dtd[] = {
-		GSF_XML_IN_NODE (THEME, THEME, -1, "GogAxisColorMap", GSF_XML_NO_CONTENT, NULL, NULL),
-			GSF_XML_IN_NODE (THEME, NAME, -1, "name", GSF_XML_CONTENT, name_start, name_end),
-			GSF_XML_IN_NODE (THEME, UNAME, -1, "_name", GSF_XML_CONTENT, name_start, name_end),
-			GSF_XML_IN_NODE (THEME, STOP, -1, "color-stop", GSF_XML_CONTENT, color_stop_start, NULL),
-		GSF_XML_IN_NODE_END
-	};
-	struct color_map_load_state	state;
-	GsfXMLInDoc *xml;
+	struct color_map_load_state state;
 	GsfInput *input = go_file_open (uri, NULL);
 
 	if (input == NULL) {
@@ -409,45 +510,59 @@ color_map_load_from_uri (char const *uri)
 		return;
 	}
 	state.map = NULL;
-	state.lang = state.local_name = NULL;
+	state.name = NULL;
+	state.lang = NULL;
 	state.langs = g_get_language_names ();
 	state.name_lang_score = G_MAXINT;
 	state.color_stops = NULL;
-	xml = gsf_xml_in_doc_new (color_map_dtd, NULL);
+	if (!xml)
+		xml = gsf_xml_in_doc_new (color_map_dtd, NULL);
 	if (!gsf_xml_in_doc_parse (xml, input, &state))
 		g_warning ("[GogAxisColorMap]: Could not parse %s", uri);
 	if (state.map != NULL) {
-		GSList *ptr;
-		state.map->local_name = state.local_name;
-		/* populates the colors */
-		/* first sort the color list according to bins */
-		ptr = state.color_stops = g_slist_sort (state.color_stops, (GCompareFunc) color_stops_cmp);
-		if (((struct _color_stop *) ptr->data)->bin != 0) {
-			g_warning ("[GogAxisColorMap]: Invalid color map in %s", uri);
-			g_object_unref (state.map);
-		} else {
-			unsigned cur_bin, n = 0;
-			state.map->size = g_slist_length (state.color_stops);
-			state.map->limits = g_new (unsigned, state.map->size);
-			state.map->colors = g_new (GOColor, state.map->size);
-			while (ptr) {
-				cur_bin = state.map->limits[n] = ((struct _color_stop *) ptr->data)->bin;
-				state.map->colors[n++] = ((struct _color_stop *) ptr->data)->color;
-				do (ptr = ptr->next);
-				while (ptr && ((struct _color_stop *) ptr->data)->bin == cur_bin);
-			}
-			state.map->size = n; /* we drop duplicate bins */
+		color_map_loaded (&state, uri, TRUE);
+		if (state.map)
 			gog_axis_color_map_registry_add (state.map);
-		}
 	} else
-		g_free (state.local_name);
-	g_slist_free_full (state.color_stops, g_free);
-	g_free (state.lang);
-	gsf_xml_in_doc_free (xml);
+		g_free (state.name);
 	g_object_unref (input);
 }
 
 static void
+parse_done_cb (GsfXMLIn *xin, struct color_map_load_state *state)
+{
+	color_map_loaded (state, gsf_input_name (gsf_xml_in_get_input (xin)), FALSE);
+	g_free (state);
+}
+
+/**
+ * gog_axis_color_map_sax_push_parser:
+ * @xin: a #GsfXMLIn
+ * @attrs: the node attributes.
+ *
+ * Reads a colormap from the XML stream.
+ **/
+void
+gog_axis_color_map_sax_push_parser (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	struct color_map_load_state *state = g_new (struct color_map_load_state, 1);
+	state->map = NULL;
+	state->name = NULL;
+	state->lang = NULL;
+	state->langs = g_get_language_names ();
+	state->name_lang_score = G_MAXINT;
+	state->color_stops = NULL;
+	if (!xml)
+		xml = gsf_xml_in_doc_new (color_map_dtd, NULL);
+	for (; attrs && *attrs; attrs +=2)
+		if (!strcmp ((char const *) *attrs, "id")) {
+			state->map = GOG_AXIS_COLOR_MAP (gog_axis_color_map_get_from_id ((char const *) attrs[1]));
+			break;
+		}
+	gsf_xml_in_push_state (xin, xml, state, (GsfXMLInExtDtor) parse_done_cb, attrs);
+}
+
+static void
 color_maps_load_from_dir (char const *path)
 {
 	GDir *dir = g_dir_open (path, 0, NULL);
@@ -473,8 +588,8 @@ color_maps_load_from_dir (char const *path)
  * @map: a #GogAxisColorMap
  * @user_data: user data
  *
- * Type of the callback to pass to gog_axis_color_map_foreach() and
- * go_doc_foreach_color_map() to iterate through color maps.
+ * Type of the callback to pass to gog_axis_color_map_foreach()
+ * to iterate through color maps.
  **/
 
 /**
@@ -482,8 +597,8 @@ color_maps_load_from_dir (char const *path)
  * @handler: (scope call): a #GogAxisColorMapHandler
  * @user_data: data to pass to @handler
  *
- * Executes @handler to each color map installed on the system. This function
- * should not be called directly, call go_doc_foreach_color_map() instead.
+ * Executes @handler to each color map installed on the system or loaded from
+ * a document.
  **/
 void
 gog_axis_color_map_foreach (GogAxisColorMapHandler handler, gpointer user_data)
@@ -494,20 +609,25 @@ gog_axis_color_map_foreach (GogAxisColorMapHandler handler, gpointer user_data)
 }
 
 /**
- * gog_axis_color_map_get_from_name:
- * @name: the color map name to search for
+ * gog_axis_color_map_get_from_id:
+ * @id: the color map identifier to search for
  *
- * Retrieves the color map whose name is @name.
- * Returns: (transfer none): the found color map or %NULL.
+ * Retrieves the color map whose identifier is @id.
+ * Returns: (transfer none): the found color map.
  **/
 GogAxisColorMap const *
-gog_axis_color_map_get_from_name (char const *name)
+gog_axis_color_map_get_from_id (char const *id)
 {
 	GSList *ptr;
+	GogAxisColorMap *map;
 	for (ptr = color_maps; ptr; ptr = ptr->next)
-		if (!strcmp (((GogAxisColorMap *) (ptr->data))->name, name))
+		if (!strcmp (((GogAxisColorMap *) (ptr->data))->id, id))
 		    return (GogAxisColorMap *) ptr->data;
-	return NULL;
+	/* create an empty new one */
+	map = g_object_new (GOG_TYPE_AXIS_COLOR_MAP, NULL);
+	map->id = g_strdup (id);
+	gog_axis_color_map_registry_add (map);
+	return map;
 }
 
 void
@@ -517,6 +637,7 @@ _gog_axis_color_maps_init (void)
 
 	/* Default color map */
 	color_map = g_object_new (GOG_TYPE_AXIS_COLOR_MAP, NULL);
+	color_map->id = g_strdup ("Default");
 	color_map->name = g_strdup (N_("Default"));
 	color_map->size = 5;
 	color_map->limits = g_new (unsigned, 5);
diff --git a/goffice/graph/gog-axis-color-map.h b/goffice/graph/gog-axis-color-map.h
index 093f4eb..5955d7a 100644
--- a/goffice/graph/gog-axis-color-map.h
+++ b/goffice/graph/gog-axis-color-map.h
@@ -23,6 +23,7 @@
 #define GOG_AXIS_COLOR_MAP_H
 
 #include <goffice/goffice.h>
+#include <gsf/gsf-libxml.h>
 
 G_BEGIN_DECLS
 
@@ -40,14 +41,16 @@ GdkPixbuf *gog_axis_color_map_get_snapshot (GogAxisColorMap const *map,
                                             gboolean horizontal,
                                             unsigned width,
                                             unsigned height);
+char const *gog_axis_color_map_get_id (GogAxisColorMap const *map);
 char const *gog_axis_color_map_get_name (GogAxisColorMap const *map);
 #ifdef GOFFICE_WITH_GTK
 GogAxisColorMap *gog_axis_color_map_edit (GogAxisColorMap *map, GOCmdContext *cc);
 #endif
 typedef void (*GogAxisColorMapHandler) (GogAxisColorMap const *map, gpointer user_data);
 void gog_axis_color_map_foreach (GogAxisColorMapHandler handler, gpointer user_data);
-GogAxisColorMap const *gog_axis_color_map_get_from_name (char const *name);
-
+GogAxisColorMap const *gog_axis_color_map_get_from_id (char const *id);
+void gog_axis_color_map_write (GogAxisColorMap const *map, GsfXMLOut *output);
+void gog_axis_color_map_sax_push_parser (GsfXMLIn *xin, xmlChar const **attrs);
 
 /* private */
 GogAxisColorMap const *_gog_axis_color_map_get_default (void);
diff --git a/goffice/graph/gog-axis.c b/goffice/graph/gog-axis.c
index c488c7e..a23d638 100644
--- a/goffice/graph/gog-axis.c
+++ b/goffice/graph/gog-axis.c
@@ -2194,7 +2194,27 @@ gog_axis_get_atype (GogAxis const *axis)
 	return axis->type;
 }
 
+static void
+gog_axis_prep_sax (GOPersist *gp, GsfXMLIn *xin, xmlChar const **attrs)
+{
+	/* Nothing to do */
+}
 
+static void
+gog_axis_sax_save (GOPersist const *gp, GsfXMLOut *output)
+{
+	GogAxis const *axis;
+	GogGraph *graph;
+
+	g_return_if_fail (GOG_IS_AXIS (gp));
+	axis = (GogAxis const*) gp;
+	if (axis->auto_color_map)
+		return;
+	graph = gog_object_get_graph (GOG_OBJECT (gp));
+	if (gog_theme_get_color_map (gog_graph_get_theme (graph), FALSE) == axis->color_map)
+		return;
+	go_doc_save_color_map (gog_graph_get_document (graph), axis->color_map);
+}
 
 static void
 gog_axis_set_property (GObject *obj, guint param_id,
@@ -2266,15 +2286,8 @@ gog_axis_set_property (GObject *obj, guint param_id,
 	case AXIS_PROP_COLOR_MAP: {
 		char const *str = g_value_get_string (value);
 		GogAxisColorMap const *map = NULL;
-		if (strcmp (str, "default")) {
-				map = go_doc_get_color_map (gog_graph_get_document (gog_object_get_graph (GOG_OBJECT (axis))), str);
-			if (!map) {
-				/* might be the continuous theme color map */
-				map = gog_theme_get_color_map (gog_graph_get_theme (gog_object_get_graph (GOG_OBJECT (axis))), FALSE);
-				if (strcmp (gog_axis_color_map_get_name (map), str))
-					map = NULL;
-			}
-		}
+		if (strcmp (str, "default"))
+			map = gog_axis_color_map_get_from_id (str);
 		if (map) {
 			axis->color_map = map;
 			axis->auto_color_map = FALSE;
@@ -2331,7 +2344,7 @@ gog_axis_get_property (GObject *obj, guint param_id,
 		g_value_set_double (value, axis->span_end);
 		break;
 	case AXIS_PROP_COLOR_MAP:
-		g_value_set_string (value, (axis->auto_color_map)? "default": gog_axis_color_map_get_name (axis->color_map));
+		g_value_set_string (value, (axis->auto_color_map)? "default": gog_axis_color_map_get_id (axis->color_map));
 		break;
 
 	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
@@ -3045,7 +3058,7 @@ gog_axis_class_init (GObjectClass *gobject_klass)
 
 	gog_object_register_roles (gog_klass, roles, G_N_ELEMENTS (roles));
 
-	gog_klass->update	= gog_axis_update;
+	gog_klass->update		= gog_axis_update;
 #ifdef GOFFICE_WITH_GTK
 	gog_klass->populate_editor	= gog_axis_populate_editor;
 #endif
@@ -3116,10 +3129,18 @@ gog_axis_dataset_init (GogDatasetClass *iface)
 	iface->dim_changed = gog_axis_dim_changed;
 }
 
+static void
+gog_axis_persist_init (GOPersistClass *iface)
+{
+	iface->sax_save = gog_axis_sax_save;
+	iface->prep_sax = gog_axis_prep_sax;
+}
+
 GSF_CLASS_FULL (GogAxis, gog_axis,
 		NULL, NULL, gog_axis_class_init, NULL,
 		gog_axis_init, GOG_TYPE_AXIS_BASE, 0,
-		GSF_INTERFACE (gog_axis_dataset_init, GOG_TYPE_DATASET))
+		GSF_INTERFACE (gog_axis_dataset_init, GOG_TYPE_DATASET) \
+		GSF_INTERFACE (gog_axis_persist_init, GO_TYPE_PERSIST))
 
 
 /**
@@ -3471,6 +3492,7 @@ gog_axis_get_circular_rotation (GogAxis *axis)
  * gog_axis_get_color_map:
  * @axis: a #GogAxis
  *
+ * Retrieves the #GogAxisColorMap associated to the axis or %NULL.
  * Returns: (transfer none): the color map used by the axis if any.
  **/
 GogAxisColorMap const *
diff --git a/goffice/utils/goffice-utils.c b/goffice/utils/goffice-utils.c
new file mode 100644
index 0000000..1542141
--- /dev/null
+++ b/goffice/utils/goffice-utils.c
@@ -0,0 +1,104 @@
+/*
+ * goffice-utils.c:
+ *
+ * Copyright (C) 2012 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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>
+
+/* This code was copied from telepathy/telepathy-gabble/tree/src/util.c.
+ * Original copyright is:
+ *
+ * Copyright (C) 2006-2007 Collabora Ltd.
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *   @author Robert McQueen <robert mcqueen collabora co uk>
+ *   @author Simon McVittie <simon mcvittie collabora co uk>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/**
+ * go_uuid:
+ *
+ * RFC4122 version 4 compliant random UUIDs generator.
+ *
+ * Returns: (transfer full): A string with RFC41122 version 4 random UUID,
+ * must be freed with _free().
+ **/
+char *
+go_uuid (void)
+{
+	GRand *grand;
+	gchar *str;
+	struct {
+		guint32 time_low;
+		guint16 time_mid;
+		guint16 time_hi_and_version;
+		guint8 clock_seq_hi_and_rsv;
+		guint8 clock_seq_low;
+		guint16 node_hi;
+		guint32 node_low;
+	} uuid;
+
+	/* Fill with random. Every new GRand are seede with 128 bit read from
+	* /dev/urandom (or the current time on non-unix systems). This makes the
+	* random source good enough for our usage, but may not be suitable for all
+	* situation outside Gabble. */
+	grand = g_rand_new ();
+	uuid.time_low = g_rand_int (grand);
+	uuid.time_mid = (guint16) g_rand_int_range (grand, 0, G_MAXUINT16);
+	uuid.time_hi_and_version = (guint16) g_rand_int_range (grand, 0, G_MAXUINT16);
+	uuid.clock_seq_hi_and_rsv = (guint8) g_rand_int_range (grand, 0, G_MAXUINT8);
+	uuid.clock_seq_low = (guint8) g_rand_int_range (grand, 0, G_MAXUINT8);
+	uuid.node_hi = (guint16) g_rand_int_range (grand, 0, G_MAXUINT16);
+	uuid.node_low = g_rand_int (grand);
+	g_rand_free (grand);
+
+	/* Set the two most significant bits (bits 6 and 7) of the
+	* clock_seq_hi_and_rsv to zero and one, respectively. */
+	uuid.clock_seq_hi_and_rsv = (uuid.clock_seq_hi_and_rsv & 0x3F) | 0x80;
+
+	/* Set the four most significant bits (bits 12 through 15) of the
+	* time_hi_and_version field to 4 */
+	uuid.time_hi_and_version = (uuid.time_hi_and_version & 0x0fff) | 0x4000;
+
+	str = g_strdup_printf ("%08x-%04x-%04x-%02x%02x-%04x%08x",
+	uuid.time_low,
+	uuid.time_mid,
+	uuid.time_hi_and_version,
+	uuid.clock_seq_hi_and_rsv,
+	uuid.clock_seq_low,
+	uuid.node_hi,
+	uuid.node_low);
+
+	return str;
+}
diff --git a/goffice/utils/goffice-utils.h b/goffice/utils/goffice-utils.h
index 3fd313b..531326f 100644
--- a/goffice/utils/goffice-utils.h
+++ b/goffice/utils/goffice-utils.h
@@ -165,4 +165,6 @@ G_END_DECLS
 #include <goffice/utils/go-units.h>
 #include <goffice/utils/regutf8.h>
 
+char *go_uuid (void);
+
 #endif /* GOFFICE_UTILS_H */



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