[gthumb/ext] [tags] load and save the default tags using a configuration file



commit 2b1df2c3a8c05400293485c7ba0f09d9236d114c
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Fri Aug 21 17:53:17 2009 +0200

    [tags] load and save the default tags using a configuration file

 extensions/comments/data/ui/edit-comment-page.ui |    6 +-
 extensions/comments/gth-edit-comment-page.c      |    2 +-
 extensions/photo_importer/dlg-photo-importer.c   |    2 +-
 gthumb/Makefile.am                               |    2 +
 gthumb/gth-main.c                                |   42 +++-
 gthumb/gth-main.h                                |    4 +
 gthumb/gth-monitor.c                             |   21 ++
 gthumb/gth-monitor.h                             |    2 +
 gthumb/gth-tags-entry.c                          |  329 +++++++++++++++-------
 gthumb/gth-tags-entry.h                          |    2 +-
 gthumb/gth-tags-file.c                           |  263 +++++++++++++++++
 gthumb/gth-tags-file.h                           |   59 ++++
 gthumb/typedefs.h                                |    1 +
 13 files changed, 620 insertions(+), 115 deletions(-)
---
diff --git a/extensions/comments/data/ui/edit-comment-page.ui b/extensions/comments/data/ui/edit-comment-page.ui
index 0a68fa6..d9012e4 100644
--- a/extensions/comments/data/ui/edit-comment-page.ui
+++ b/extensions/comments/data/ui/edit-comment-page.ui
@@ -131,9 +131,6 @@
       </packing>
     </child>
     <child>
-      <placeholder/>
-    </child>
-    <child>
       <object class="GtkHBox" id="tags_entry_container">
         <property name="visible">True</property>
         <child>
@@ -147,5 +144,8 @@
         <property name="bottom_attach">5</property>
       </packing>
     </child>
+    <child>
+      <placeholder/>
+    </child>
   </object>
 </interface>
diff --git a/extensions/comments/gth-edit-comment-page.c b/extensions/comments/gth-edit-comment-page.c
index 63f3174..b30b99f 100644
--- a/extensions/comments/gth-edit-comment-page.c
+++ b/extensions/comments/gth-edit-comment-page.c
@@ -277,7 +277,7 @@ gth_edit_comment_page_init (GthEditCommentPage *self)
   	gtk_widget_show (self->priv->date_datetime);
   	gtk_box_pack_start (GTK_BOX (GET_WIDGET ("date_datetime_container")), self->priv->date_datetime, FALSE, FALSE, 0);
 
-  	self->priv->tags_entry = gth_tags_entry_new (NULL);
+  	self->priv->tags_entry = gth_tags_entry_new ();
   	gtk_widget_show (self->priv->tags_entry);
   	gtk_box_pack_start (GTK_BOX (GET_WIDGET ("tags_entry_container")), self->priv->tags_entry, TRUE, TRUE, 0);
 }
diff --git a/extensions/photo_importer/dlg-photo-importer.c b/extensions/photo_importer/dlg-photo-importer.c
index bdc1f8a..09277fa 100644
--- a/extensions/photo_importer/dlg-photo-importer.c
+++ b/extensions/photo_importer/dlg-photo-importer.c
@@ -707,7 +707,7 @@ dlg_photo_importer (GthBrowser *browser,
 		g_free (last_destination);
 	}
 
-	data->tags_entry = gth_tags_entry_new (NULL);
+	data->tags_entry = gth_tags_entry_new ();
 	gtk_widget_show (data->tags_entry);
 	gtk_box_pack_start (GTK_BOX (GET_WIDGET ("tags_entry_box")), data->tags_entry, TRUE, TRUE, 0);
 	gtk_label_set_mnemonic_widget (GTK_LABEL (GET_WIDGET ("tags_label")), data->tags_entry);
diff --git a/gthumb/Makefile.am b/gthumb/Makefile.am
index 057b014..bd175cf 100644
--- a/gthumb/Makefile.am
+++ b/gthumb/Makefile.am
@@ -80,6 +80,7 @@ PUBLIC_HEADER_FILES = 					\
 	gth-stock.h					\
 	gth-string-list.h				\
 	gth-tags-entry.h				\
+	gth-tags-file.h					\
 	gth-task.h					\
 	gth-test.h					\
 	gth-test-chain.h				\
@@ -189,6 +190,7 @@ gthumb_SOURCES = 					\
 	gth-statusbar.c					\
 	gth-string-list.c				\
 	gth-tags-entry.c				\
+	gth-tags-file.c					\
 	gth-task.c					\
 	gth-test.c					\
 	gth-test-chain.c				\
diff --git a/gthumb/gth-main.c b/gthumb/gth-main.c
index 491efb8..52dd13b 100644
--- a/gthumb/gth-main.c
+++ b/gthumb/gth-main.c
@@ -101,6 +101,7 @@ struct _GthMainPrivate
 	GHashTable          *objects;
 	GBookmarkFile       *bookmarks;
 	GthFilterFile       *filters;
+	GthTagsFile         *tags;
 	GthMonitor          *monitor;
 	GthExtensionManager *extension_manager;
 };
@@ -1034,15 +1035,54 @@ gth_main_filters_changed (void)
 	char *filename;
 
 	gth_user_dir_make_dir_for_file (GTH_DIR_CONFIG, GTHUMB_DIR, FILTERS_FILE, NULL);
-
 	filename = gth_user_dir_get_file (GTH_DIR_CONFIG, GTHUMB_DIR, FILTERS_FILE, NULL);
 	gth_filter_file_to_file (Main->priv->filters, filename, NULL);
+
 	g_free (filename);
 
 	gth_monitor_filters_changed (gth_main_get_default_monitor ());
 }
 
 
+GthTagsFile *
+gth_main_get_default_tag_file (void)
+{
+	char *path;
+
+	if (Main->priv->tags != NULL)
+		return Main->priv->tags;
+
+	Main->priv->tags = gth_tags_file_new ();
+	path = gth_user_dir_get_file (GTH_DIR_CONFIG, GTHUMB_DIR, TAGS_FILE, NULL);
+	gth_tags_file_load_from_file (Main->priv->tags, path, NULL);
+	g_free (path);
+
+	return Main->priv->tags;
+}
+
+
+const char **
+gth_main_get_all_tags (void)
+{
+	return gth_tags_file_get_tags (gth_main_get_default_tag_file ());
+}
+
+
+void
+gth_main_tags_changed (void)
+{
+	char *filename;
+
+	gth_user_dir_make_dir_for_file (GTH_DIR_CONFIG, GTHUMB_DIR, TAGS_FILE, NULL);
+	filename = gth_user_dir_get_file (GTH_DIR_CONFIG, GTHUMB_DIR, TAGS_FILE, NULL);
+	gth_tags_file_to_file (Main->priv->tags, filename, NULL);
+
+	g_free (filename);
+
+	gth_monitor_tags_changed (gth_main_get_default_monitor ());
+}
+
+
 GthMonitor *
 gth_main_get_default_monitor (void)
 {
diff --git a/gthumb/gth-main.h b/gthumb/gth-main.h
index c04b439..3c77467 100644
--- a/gthumb/gth-main.h
+++ b/gthumb/gth-main.h
@@ -33,6 +33,7 @@
 #include "gth-hook.h"
 #include "gth-metadata-provider.h"
 #include "gth-monitor.h"
+#include "gth-tags-file.h"
 #include "gth-test.h"
 
 G_BEGIN_DECLS
@@ -108,6 +109,9 @@ void                   gth_main_bookmarks_changed             (void);
 GthFilterFile *        gth_main_get_default_filter_file       (void);
 GList *                gth_main_get_all_filters               (void);
 void                   gth_main_filters_changed               (void);
+GthTagsFile *          gth_main_get_default_tag_file          (void);
+const char **          gth_main_get_all_tags                  (void);
+void                   gth_main_tags_changed                  (void);
 GthMonitor *           gth_main_get_default_monitor           (void);
 GthExtensionManager *  gth_main_get_default_extension_manager (void);
 void                   gth_main_register_default_hooks        (void);
diff --git a/gthumb/gth-monitor.c b/gthumb/gth-monitor.c
index 471760d..043b083 100644
--- a/gthumb/gth-monitor.c
+++ b/gthumb/gth-monitor.c
@@ -35,6 +35,7 @@ enum {
 	ICON_THEME_CHANGED,
 	BOOKMARKS_CHANGED,
 	FILTERS_CHANGED,
+	TAGS_CHANGED,
 	FOLDER_CONTENT_CHANGED,
 	FILE_RENAMED,
 	METADATA_CHANGED,
@@ -110,6 +111,15 @@ gth_monitor_class_init (GthMonitorClass *class)
 			      g_cclosure_marshal_VOID__VOID,
 			      G_TYPE_NONE,
 			      0);
+	monitor_signals[TAGS_CHANGED] =
+		g_signal_new ("tags-changed",
+			      G_TYPE_FROM_CLASS (class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GthMonitorClass, tags_changed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE,
+			      0);
 	monitor_signals[FOLDER_CONTENT_CHANGED] =
 		g_signal_new ("folder-changed",
 			      G_TYPE_FROM_CLASS (class),
@@ -238,6 +248,17 @@ gth_monitor_filters_changed (GthMonitor *monitor)
 
 
 void
+gth_monitor_tags_changed (GthMonitor *monitor)
+{
+	g_return_if_fail (GTH_IS_MONITOR (monitor));
+
+	g_signal_emit (G_OBJECT (monitor),
+		       monitor_signals[TAGS_CHANGED],
+		       0);
+}
+
+
+void
 gth_monitor_folder_changed (GthMonitor      *monitor,
 			    GFile           *parent,
 			    GList           *list,
diff --git a/gthumb/gth-monitor.h b/gthumb/gth-monitor.h
index 8a7e589..1fb562d 100644
--- a/gthumb/gth-monitor.h
+++ b/gthumb/gth-monitor.h
@@ -62,6 +62,7 @@ struct _GthMonitorClass
 	void   (*icon_theme_changed)      (GthMonitor      *monitor);
 	void   (*bookmarks_changed)       (GthMonitor      *monitor);
 	void   (*filters_changed)         (GthMonitor      *monitor);
+	void   (*tags_changed)            (GthMonitor      *monitor);
 	void   (*folder_changed)          (GthMonitor      *monitor,
 					   GFile           *parent,
 					   GList           *list,
@@ -81,6 +82,7 @@ void          gth_monitor_resume                     (GthMonitor      *monitor);
 void          gth_monitor_icon_theme_changed         (GthMonitor      *monitor);
 void          gth_monitor_bookmarks_changed          (GthMonitor      *monitor);
 void          gth_monitor_filters_changed            (GthMonitor      *monitor);
+void          gth_monitor_tags_changed               (GthMonitor      *monitor);
 void          gth_monitor_folder_changed             (GthMonitor      *monitor,
 						      GFile           *parent,
 						      GList           *list,
diff --git a/gthumb/gth-tags-entry.c b/gthumb/gth-tags-entry.c
index d316bc2..090b1f9 100644
--- a/gthumb/gth-tags-entry.c
+++ b/gthumb/gth-tags-entry.c
@@ -22,7 +22,9 @@
 
 #include <config.h>
 #include <glib/gi18n.h>
+#include "gth-main.h"
 #include "gth-tags-entry.h"
+#include "gth-tags-file.h"
 
 
 enum {
@@ -30,11 +32,6 @@ enum {
 	N_COLUMNS
 };
 
-enum  {
-	PROP_0,
-	PROP_TAGS
-};
-
 
 struct _GthTagsEntryPrivate {
 	char               **tags;
@@ -42,6 +39,7 @@ struct _GthTagsEntryPrivate {
 	GtkListStore        *store;
 	char                *new_tag;
 	gboolean             action_create;
+	gulong               monitor_event;
 };
 
 
@@ -49,56 +47,17 @@ static gpointer parent_class = NULL;
 
 
 static void
-gth_tags_entry_get_property (GObject    *object,
-			     guint       property_id,
-			     GValue     *value,
-			     GParamSpec *pspec)
-{
-	GthTagsEntry *self;
-
-	self = GTH_TAGS_ENTRY (object);
-
-	switch (property_id) {
-	case PROP_TAGS:
-		g_value_set_boxed (value, self->priv->tags);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-		break;
-	}
-}
-
-
-static void
-gth_tags_entry_set_property (GObject      *object,
-			     guint         property_id,
-			     const GValue *value,
-			     GParamSpec   *pspec)
-{
-	GthTagsEntry *self;
-
-	self = GTH_TAGS_ENTRY (object);
-
-	switch (property_id) {
-	case PROP_TAGS:
-		self->priv->tags = g_strdupv (g_value_get_boxed (value));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-		break;
-	}
-}
-
-
-static void
 gth_tags_entry_finalize (GObject *obj)
 {
 	GthTagsEntry *self;
 
 	self = GTH_TAGS_ENTRY (obj);
 
+	g_signal_handler_disconnect (gth_main_get_default_monitor (), self->priv->monitor_event);
+
 	g_free (self->priv->new_tag);
 	g_object_unref (self->priv->completion);
+	g_strfreev (self->priv->tags);
 
 	G_OBJECT_CLASS (parent_class)->finalize (obj);
 }
@@ -113,17 +72,7 @@ gth_tags_entry_class_init (GthTagsEntryClass *klass)
 	g_type_class_add_private (klass, sizeof (GthTagsEntryPrivate));
 
 	object_class = (GObjectClass*) (klass);
-	object_class->get_property = gth_tags_entry_get_property;
-	object_class->set_property = gth_tags_entry_set_property;
 	object_class->finalize = gth_tags_entry_finalize;
-
-	g_object_class_install_property (object_class,
-					 PROP_TAGS,
-					 g_param_spec_boxed ("tags",
-							     "Tags",
-							     "List of tags",
-							     G_TYPE_STRV,
-							     G_PARAM_READWRITE));
 }
 
 
@@ -171,16 +120,36 @@ get_tag_limits (GthTagsEntry  *self,
 }
 
 
+static gboolean
+can_create_tag (GthTagsEntry *self,
+		const char   *tag)
+{
+	int i;
+
+	if (tag == NULL)
+		return FALSE;
+	if (tag[0] == '\0')
+		return FALSE;
+
+	for (i = 0; self->priv->tags[i] != NULL; i++)
+		if (strcmp (self->priv->tags[i], tag) == 0)
+			return FALSE;
+
+	return TRUE;
+}
+
+
 static void
 text_changed_cb (GthTagsEntry *self)
 {
 	const char *tag_start;
 	const char *tag_end;
 
+	g_free (self->priv->new_tag);
+	self->priv->new_tag = NULL;
+
 	if (self->priv->action_create) {
 		gtk_entry_completion_delete_action (self->priv->completion, 0);
-		g_free (self->priv->new_tag);
-		self->priv->new_tag = NULL;
 		self->priv->action_create = FALSE;
 	}
 
@@ -190,10 +159,10 @@ text_changed_cb (GthTagsEntry *self)
 
 	self->priv->new_tag = g_strndup (tag_start, tag_end - tag_start);
 	self->priv->new_tag = g_strstrip (self->priv->new_tag);
-	if (self->priv->new_tag[0] != '\0') {
+
+	if (can_create_tag (self, self->priv->new_tag)) {
 		char *action_text;
 
-		/* â??%sâ?? */
 		action_text = g_strdup_printf (_("Create tag «%s»"), self->priv->new_tag);
 		gtk_entry_completion_insert_action_text (self->priv->completion, 0, action_text);
 		self->priv->action_create = TRUE;
@@ -211,8 +180,6 @@ match_func (GtkEntryCompletion *completion,
 {
 	GthTagsEntry *self = user_data;
 	char         *name;
-	char         *k1;
-	char         *k2;
 	gboolean      result;
 
 	if (self->priv->new_tag == NULL)
@@ -224,13 +191,23 @@ match_func (GtkEntryCompletion *completion,
 	gtk_tree_model_get (GTK_TREE_MODEL (self->priv->store), iter,
 			    NAME_COLUMN, &name,
 			    -1);
-	k1 = g_utf8_casefold (self->priv->new_tag, -1);
-	k2 = g_utf8_casefold (name, strlen (self->priv->new_tag));
 
-	result = g_utf8_collate (k1, k2) == 0;
+	if (name != NULL) {
+		char *k1;
+		char *k2;
+
+		k1 = g_utf8_casefold (self->priv->new_tag, -1);
+		k2 = g_utf8_casefold (name, strlen (self->priv->new_tag));
+
+		result = g_utf8_collate (k1, k2) == 0;
+
+
+		g_free (k2);
+		g_free (k1);
+	}
+	else
+		result = FALSE;
 
-	g_free (k2);
-	g_free (k1);
 	g_free (name);
 
 	return result;
@@ -250,7 +227,6 @@ completion_match_selected_cb (GtkEntryCompletion *widget,
 	char         *head;
 	const char   *tail;
 	char         *tag_name = NULL;
-	char         *new_text;
 
 	get_tag_limits (self, &tag_start, &tag_end);
 	text = gtk_entry_get_text (GTK_ENTRY (self));
@@ -263,29 +239,162 @@ completion_match_selected_cb (GtkEntryCompletion *widget,
 	gtk_tree_model_get (model, iter,
 			    NAME_COLUMN, &tag_name,
 			    -1);
+
+	if (tag_name != NULL) {
+		char *new_text;
+
+		new_text = g_strconcat (head,
+					" ",
+					tag_name,
+					", " /*(tail != tag_end ? ", " : "")*/,
+					tail,
+					NULL);
+		gtk_entry_set_text (GTK_ENTRY (self), new_text);
+		gtk_editable_set_position (GTK_EDITABLE (self), -1);
+
+		g_free (new_text);
+		g_free (tag_name);
+	}
+
+	g_free (head);
+
+	return TRUE;
+}
+
+
+static void
+completion_action_activated_cb (GtkEntryCompletion *widget,
+                                int                 index,
+                                gpointer            user_data)
+{
+	GthTagsEntry *self = user_data;
+	const char   *tag_start;
+	const char   *tag_end;
+	const char   *text;
+	char         *head;
+	const char   *tail;
+	char         *tag_name = NULL;
+	char         *new_text;
+	GthTagsFile  *tags_file;
+
+	if (index != 0)
+		return;
+
+	get_tag_limits (self, &tag_start, &tag_end);
+	text = gtk_entry_get_text (GTK_ENTRY (self));
+	head = g_strndup (text, tag_start - text);
+	head = g_strstrip (head);
+	if (tag_end[0] != '\0')
+		tail = g_utf8_next_char (tag_end);
+	else
+		tail = tag_end;
+	tag_name = g_strndup (tag_start, tag_end - tag_start);
+	tag_name = g_strstrip (tag_name);
 	new_text = g_strconcat (head,
 				" ",
 				tag_name,
-				(tail != tag_end ? ", " : ""),
+				", ",
 				tail,
 				NULL);
 
 	gtk_entry_set_text (GTK_ENTRY (self), new_text);
 	gtk_editable_set_position (GTK_EDITABLE (self), -1);
 
+	tags_file = gth_main_get_default_tag_file ();
+	gth_tags_file_add (tags_file, tag_name);
+	gth_main_tags_changed ();
+
 	g_free (new_text);
 	g_free (tag_name);
 	g_free (head);
+}
 
-	return TRUE;
+
+static int
+sort_tag_by_name (gconstpointer a,
+		  gconstpointer b,
+		  gpointer      user_data)
+{
+	char *sa = * (char **) a;
+	char *sb = * (char **) b;
+
+	return g_utf8_collate (sa, sb);
 }
 
 
 static void
-gth_tags_entry_instance_init (GthTagsEntry *self)
+update_tag_list (GthTagsEntry *self)
+{
+	GthTagsFile *tags;
+	int          i;
+
+	tags = gth_main_get_default_tag_file ();
+
+	g_strfreev (self->priv->tags);
+	self->priv->tags = g_strdupv ((char **)gth_tags_file_get_tags (tags));
+
+	for (i = 0; self->priv->tags[i] != NULL; i++) {
+		GtkTreeIter iter;
+
+		gtk_list_store_append (self->priv->store, &iter);
+		gtk_list_store_set (self->priv->store, &iter,
+				    NAME_COLUMN, self->priv->tags[i],
+				    -1);
+	}
+
+	if ((self->priv->tags == NULL) || self->priv->tags[0] == NULL) {
+		char *default_tags[] = { N_("Holidays"),
+                                         N_("Temporary"),
+                                         N_("Screenshots"),
+                                         N_("Science"),
+                                         N_("Favorite"),
+                                         N_("Important"),
+                                         N_("GNOME"),
+                                         N_("Games"),
+                                         N_("Party"),
+                                         N_("Birthday"),
+                                         N_("Astronomy"),
+                                         N_("Family"),
+                                         NULL };
+
+		if (self->priv->tags != NULL)
+			g_strfreev (self->priv->tags);
+
+		self->priv->tags = g_new (char *, g_strv_length (default_tags) + 1);
+		for (i = 0; default_tags[i] != NULL; i++)
+			self->priv->tags[i] = g_strdup (_(default_tags[i]));
+		self->priv->tags[i] = NULL;
+	}
+
+	g_qsort_with_data (self->priv->tags,
+			   g_strv_length (self->priv->tags),
+			   sizeof (char *),
+			   sort_tag_by_name,
+			   NULL);
+
+	gtk_list_store_clear (self->priv->store);
+	for (i = 0; self->priv->tags[i] != NULL; i++) {
+		GtkTreeIter iter;
+
+		gtk_list_store_append (self->priv->store, &iter);
+		gtk_list_store_set (self->priv->store, &iter,
+				    NAME_COLUMN, self->priv->tags[i],
+				    -1);
+	}
+}
+
+
+static void
+tags_changed_cb (GthMonitor   *monitor,
+		 GthTagsEntry *self)
 {
+	update_tag_list (self);
+}
 
 
+static void
+gth_tags_entry_instance_init (GthTagsEntry *self)
+{
 	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_TAGS_ENTRY, GthTagsEntryPrivate);
 	self->priv->completion = gtk_entry_completion_new ();
 	gtk_entry_completion_set_popup_completion (self->priv->completion, TRUE);
@@ -296,34 +405,22 @@ gth_tags_entry_instance_init (GthTagsEntry *self)
 	gtk_entry_completion_set_text_column (self->priv->completion, NAME_COLUMN);
 	gtk_entry_completion_set_match_func (self->priv->completion, match_func, self, NULL);
 
-	{
-		char *default_tags[] = { N_("Holidays"),
-                                      N_("Temporary"),
-                                      N_("Screenshots"),
-                                      N_("Science"),
-                                      N_("Favorite"),
-                                      N_("Important"),
-                                      N_("GNOME"),
-                                      N_("Games"),
-                                      N_("Party"),
-                                      N_("Birthday"),
-                                      N_("Astronomy"),
-                                      N_("Family"),
-                                      NULL };
-		int i;
-
-		for (i = 0; default_tags[i] != NULL; i++) {
-			GtkTreeIter iter;
-
-			gtk_list_store_append (self->priv->store, &iter);
-			gtk_list_store_set (self->priv->store, &iter,
-					    NAME_COLUMN, _(default_tags[i]),
-					    -1);
-		}
-	}
-
-	g_signal_connect (self, "notify::text", G_CALLBACK (text_changed_cb), self);
-	g_signal_connect (self->priv->completion, "match-selected", G_CALLBACK (completion_match_selected_cb), self);
+	g_signal_connect (self,
+			  "notify::text",
+			  G_CALLBACK (text_changed_cb),
+			  self);
+	g_signal_connect (self->priv->completion,
+			  "match-selected",
+			  G_CALLBACK (completion_match_selected_cb),
+			  self);
+	g_signal_connect (self->priv->completion,
+			  "action-activated",
+			  G_CALLBACK (completion_action_activated_cb),
+			  self);
+	self->priv->monitor_event = g_signal_connect (gth_main_get_default_monitor (),
+						      "tags-changed",
+						      G_CALLBACK (tags_changed_cb),
+						      self);
 }
 
 
@@ -356,28 +453,44 @@ gth_tags_entry_get_type (void)
 
 
 GtkWidget *
-gth_tags_entry_new (char **tags)
+gth_tags_entry_new (void)
 {
-	return g_object_new (GTH_TYPE_TAGS_ENTRY, "tags", tags, NULL);
+	GthTagsEntry *self;
+
+	self = g_object_new (GTH_TYPE_TAGS_ENTRY, NULL);
+	update_tag_list (self);
+
+	return (GtkWidget *) self;
 }
 
 
 char **
 gth_tags_entry_get_tags (GthTagsEntry *self)
 {
-	char **all_tags;
-	char **tags;
-	int    i;
-	int    j;
+	GthTagsFile  *tags_file;
+	char        **all_tags;
+	char        **tags;
+	int           i;
+	int           j;
+
+	tags_file = gth_main_get_default_tag_file ();
 
 	all_tags = g_strsplit (gtk_entry_get_text (GTK_ENTRY (self)), ",", -1);
 	tags = g_new0 (char *, g_strv_length (all_tags) + 1);
 	for (i = 0, j = 0; all_tags[i] != NULL; i++) {
 		all_tags[i] = g_strstrip (all_tags[i]);
-		if (all_tags[i][0] != '\0')
-			tags[j++] = g_strdup (all_tags[i]);
+		if (all_tags[i][0] != '\0') {
+			tags[j] = g_strdup (all_tags[i]);
+			gth_tags_file_add (tags_file, tags[j]);
+			j++;
+		}
 	}
 	g_strfreev (all_tags);
 
+	for (i = 0; self->priv->tags[i] != NULL; i++)
+		gth_tags_file_add (tags_file, self->priv->tags[i]);
+
+	gth_main_tags_changed ();
+
 	return tags;
 }
diff --git a/gthumb/gth-tags-entry.h b/gthumb/gth-tags-entry.h
index 3023f1f..e36948e 100644
--- a/gthumb/gth-tags-entry.h
+++ b/gthumb/gth-tags-entry.h
@@ -48,7 +48,7 @@ struct _GthTagsEntryClass {
 };
 
 GType        gth_tags_entry_get_type  (void);
-GtkWidget *  gth_tags_entry_new       (char         **tags);
+GtkWidget *  gth_tags_entry_new       (void);
 char **      gth_tags_entry_get_tags  (GthTagsEntry  *self);
 
 G_END_DECLS
diff --git a/gthumb/gth-tags-file.c b/gthumb/gth-tags-file.c
new file mode 100644
index 0000000..7016299
--- /dev/null
+++ b/gthumb/gth-tags-file.c
@@ -0,0 +1,263 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ *  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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <string.h>
+#include "dom.h"
+#include "glib-utils.h"
+#include "gth-tags-file.h"
+
+
+#define FILE_FORMAT "1.0"
+
+
+struct _GthTagsFile
+{
+	GList  *items;
+	char  **tags;
+};
+
+
+GthTagsFile *
+gth_tags_file_new (void)
+{
+	GthTagsFile *tags;
+
+	tags = g_new0 (GthTagsFile, 1);
+  	tags->items = NULL;
+  	tags->tags = NULL;
+
+  	return tags;
+}
+
+
+void
+gth_tags_file_free (GthTagsFile *tags)
+{
+	_g_string_list_free (tags->items);
+	g_strfreev (tags->tags);
+	g_free (tags);
+}
+
+
+gboolean
+gth_tags_file_load_from_data (GthTagsFile  *tags,
+                              const char   *data,
+                              gsize         length,
+                              GError      **error)
+{
+	DomDocument *doc;
+	gboolean     success;
+
+	_g_string_list_free (tags->items);
+	tags->items = NULL;
+
+	doc = dom_document_new ();
+	success = dom_document_load (doc, data, length, error);
+	if (success) {
+		DomElement *tags_node;
+		DomElement *child;
+
+		tags_node = DOM_ELEMENT (doc)->first_child;
+		if ((tags_node != NULL) && (g_strcmp0 (tags_node->tag_name, "tags") == 0)) {
+			for (child = tags_node->first_child;
+			     child != NULL;
+			     child = child->next_sibling)
+			{
+				if (strcmp (child->tag_name, "tag") == 0) {
+					const char *tag_value;
+
+					tag_value = dom_element_get_attribute (child, "value");
+					if (tag_value != NULL)
+						tags->items = g_list_prepend (tags->items, g_strdup (tag_value));
+				}
+			}
+
+			tags->items = g_list_reverse (tags->items);
+		}
+	}
+
+	g_object_unref (doc);
+
+	return success;
+}
+
+
+gboolean
+gth_tags_file_load_from_file (GthTagsFile  *tags,
+                              const char   *filename,
+                              GError      **error)
+{
+	char     *buffer;
+	gsize     len;
+	GError   *read_error;
+	gboolean  retval;
+
+	g_return_val_if_fail (tags != NULL, FALSE);
+	g_return_val_if_fail (filename != NULL, FALSE);
+
+	read_error = NULL;
+	g_file_get_contents (filename, &buffer, &len, &read_error);
+	if (read_error != NULL) {
+		g_propagate_error (error, read_error);
+		return FALSE;
+	}
+
+	read_error = NULL;
+	retval = gth_tags_file_load_from_data (tags,
+					       buffer,
+					       len,
+					       &read_error);
+  	if (read_error != NULL) {
+		g_propagate_error (error, read_error);
+		g_free (buffer);
+		return FALSE;
+	}
+
+  	g_free (buffer);
+
+	return retval;
+}
+
+
+char *
+gth_tags_file_to_data (GthTagsFile  *tags,
+		       gsize        *len,
+		       GError      **data_error)
+{
+	DomDocument *doc;
+	DomElement  *root;
+	char        *data;
+	GList       *scan;
+
+	doc = dom_document_new ();
+	root = dom_document_create_element (doc, "tags",
+					    "version", FILE_FORMAT,
+					    NULL);
+	dom_element_append_child (DOM_ELEMENT (doc), root);
+	for (scan = tags->items; scan; scan = scan->next) {
+		const char *tag_value = scan->data;
+		dom_element_append_child (root, dom_document_create_element (doc, "tag", "value", tag_value, NULL));
+	}
+	data = dom_document_dump (doc, len);
+
+	g_object_unref (doc);
+
+	return data;
+}
+
+
+gboolean
+gth_tags_file_to_file (GthTagsFile  *tags,
+                       const char   *filename,
+                       GError      **error)
+{
+	char     *data;
+	GError   *data_error, *write_error;
+	gsize     len;
+	gboolean  retval;
+
+	g_return_val_if_fail (tags != NULL, FALSE);
+	g_return_val_if_fail (filename != NULL, FALSE);
+
+	data_error = NULL;
+	data = gth_tags_file_to_data (tags, &len, &data_error);
+	if (data_error) {
+		g_propagate_error (error, data_error);
+		return FALSE;
+	}
+
+	write_error = NULL;
+	g_file_set_contents (filename, data, len, &write_error);
+	if (write_error) {
+		g_propagate_error (error, write_error);
+		retval = FALSE;
+	}
+	else
+		retval = TRUE;
+
+	g_free (data);
+
+	return retval;
+}
+
+
+const char **
+gth_tags_file_get_tags (GthTagsFile *tags)
+{
+	GList *scan;
+	int    i;
+
+	if (tags->tags != NULL) {
+		g_strfreev (tags->tags);
+		tags->tags = NULL;
+	}
+
+	tags->tags = g_new (char *, g_list_length (tags->items) + 1);
+	for (i = 0, scan = tags->items; scan; scan = scan->next)
+		tags->tags[i++] = g_strdup ((char *) scan->data);
+	tags->tags[i] = NULL;
+
+	return tags->tags;
+}
+
+
+gboolean
+gth_tags_file_has_tag (GthTagsFile *tags,
+		       const char  *tag)
+{
+	return g_list_find_custom (tags->items, tag, (GCompareFunc) strcmp) != NULL;
+}
+
+
+void
+gth_tags_file_add (GthTagsFile *tags,
+		   const char  *tag)
+{
+	GList *link;
+
+	link = g_list_find_custom (tags->items, tag, (GCompareFunc) strcmp);
+	if (link == NULL)
+		tags->items = g_list_append (tags->items, g_strdup (tag));
+}
+
+
+void
+gth_tags_file_remove (GthTagsFile *tags,
+		      const char  *tag)
+{
+	GList *link;
+
+	link = g_list_find_custom (tags->items, tag, (GCompareFunc) strcmp);
+	if (link == NULL)
+		return;
+	tags->items = g_list_remove_link (tags->items, link);
+	_g_string_list_free (link);
+}
+
+
+void
+gth_tags_file_clear (GthTagsFile *tags)
+{
+	_g_string_list_free (tags->items);
+	tags->items = NULL;
+}
diff --git a/gthumb/gth-tags-file.h b/gthumb/gth-tags-file.h
new file mode 100644
index 0000000..aa3d15a
--- /dev/null
+++ b/gthumb/gth-tags-file.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ *  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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTH_TAGS_FILE_H
+#define GTH_TAGS_FILE_H
+
+#include <glib.h>
+#include "gth-test.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GthTagsFile GthTagsFile;
+
+GthTagsFile *  gth_tags_file_new              (void);
+void           gth_tags_file_free             (GthTagsFile  *tags);
+gboolean       gth_tags_file_load_from_data   (GthTagsFile  *tags,
+					       const char   *data,
+					       gsize         length,
+					       GError      **error);
+gboolean       gth_tags_file_load_from_file   (GthTagsFile  *bookmark,
+                                               const char   *filename,
+                                               GError      **error);
+char *         gth_tags_file_to_data          (GthTagsFile  *tags,
+					       gsize        *len,
+					       GError      **data_error);
+gboolean       gth_tags_file_to_file          (GthTagsFile  *tags,
+                                               const char   *filename,
+                                               GError      **error);
+const char **  gth_tags_file_get_tags         (GthTagsFile  *tags);
+gboolean       gth_tags_file_has_tag          (GthTagsFile  *tags,
+					       const char   *tag);
+void           gth_tags_file_add              (GthTagsFile  *tags,
+					       const char   *tag);
+void           gth_tags_file_remove           (GthTagsFile  *tags,
+					       const char   *tag);
+void           gth_tags_file_clear            (GthTagsFile  *tags);
+
+G_END_DECLS
+
+#endif /* GTH_TAGS_FILE_H */
diff --git a/gthumb/typedefs.h b/gthumb/typedefs.h
index 1ef0975..1a30ca9 100644
--- a/gthumb/typedefs.h
+++ b/gthumb/typedefs.h
@@ -39,6 +39,7 @@ G_BEGIN_DECLS
 
 #define BOOKMARKS_FILE "bookmarks.xbel"
 #define FILTERS_FILE   "filters.xml"
+#define TAGS_FILE      "tags.xml"
 #define FILE_CACHE     "cache"
 
 



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