[gthumb/ext] put the used tags first in the tags expander



commit 80dd535d4dbc14e302aaa9b7d2a31d56557e10aa
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Sun Oct 25 11:26:21 2009 +0100

    put the used tags first in the tags expander

 gthumb/gth-tags-entry.c    |   11 ++-
 gthumb/gth-tags-expander.c |  237 +++++++++++++++++++++++++++++---------------
 2 files changed, 168 insertions(+), 80 deletions(-)
---
diff --git a/gthumb/gth-tags-entry.c b/gthumb/gth-tags-entry.c
index 3f8ad6e..f09c834 100644
--- a/gthumb/gth-tags-entry.c
+++ b/gthumb/gth-tags-entry.c
@@ -440,7 +440,8 @@ gth_tags_entry_get_tags (GthTagsEntry *self,
 		all_tags[i] = g_strstrip (all_tags[i]);
 		if (all_tags[i][0] != '\0') {
 			tags[j] = g_strdup (all_tags[i]);
-			gth_tags_file_add (tags_file, tags[j]);
+			if (update_globals)
+				gth_tags_file_add (tags_file, tags[j]);
 			j++;
 		}
 	}
@@ -462,6 +463,14 @@ gth_tags_entry_set_tags (GthTagsEntry  *self,
 {
 	char *s;
 
+	if (tags == NULL)
+		return;
+
+	if (tags[0] == NULL) {
+		gtk_entry_set_text (GTK_ENTRY (self), "");
+		return;
+	}
+
 	s = g_strjoinv(", ", tags);
 	gtk_entry_set_text (GTK_ENTRY (self), s);
 	g_free (s);
diff --git a/gthumb/gth-tags-expander.c b/gthumb/gth-tags-expander.c
index dc3abd2..bdca5e2 100644
--- a/gthumb/gth-tags-expander.c
+++ b/gthumb/gth-tags-expander.c
@@ -31,20 +31,29 @@
 
 enum {
 	USED_COLUMN,
+	SEPARATOR_COLUMN,
 	NAME_COLUMN,
 	N_COLUMNS
 };
 
 
 struct _GthTagsExpanderPrivate {
-	GtkEntry            *entry;
-	char               **tags;
-	GtkWidget           *tree_view;
-	GtkListStore        *store;
-	gulong               monitor_event;
+	GtkEntry      *entry;
+	char         **tags;
+	char         **last_used;
+	GtkWidget     *tree_view;
+	GtkListStore  *store;
+	gulong         monitor_event;
 };
 
 
+typedef struct {
+	char     *name;
+	gboolean  used;
+	gboolean  suggested;
+} TagData;
+
+
 static gpointer parent_class = NULL;
 
 
@@ -56,6 +65,7 @@ gth_tags_expander_finalize (GObject *obj)
 	self = GTH_TAGS_EXPANDER (obj);
 
 	g_signal_handler_disconnect (gth_main_get_default_monitor (), self->priv->monitor_event);
+	g_strfreev (self->priv->last_used);
 	g_strfreev (self->priv->tags);
 
 	G_OBJECT_CLASS (parent_class)->finalize (obj);
@@ -75,79 +85,158 @@ gth_tags_expander_class_init (GthTagsExpanderClass *klass)
 }
 
 
+static int
+sort_tag_data (gconstpointer a,
+	       gconstpointer b,
+	       gpointer      user_data)
+{
+	TagData *tag_data_a = * (TagData **) a;
+	TagData *tag_data_b = * (TagData **) b;
+
+	if (tag_data_a->used && tag_data_b->used)
+		return g_utf8_collate (tag_data_a->name, tag_data_b->name);
+	else if (tag_data_a->used || tag_data_b->used)
+		return tag_data_a->used ? -1 : 1;
+	else if (tag_data_a->suggested && tag_data_b->suggested)
+		return g_utf8_collate (tag_data_a->name, tag_data_b->name);
+	else if (tag_data_a->suggested || tag_data_b->suggested)
+		return tag_data_a->suggested ? -1 : 1;
+	else
+		return g_utf8_collate (tag_data_a->name, tag_data_b->name);
+}
+
+
 static void
-update_tag_list (GthTagsExpander *self)
+update_list_view_from_entry (GthTagsExpander *self)
 {
-	GthTagsFile *tags;
-	int          i;
+	char        **all_tags;
+	char        **used_tags;
+	TagData     **tag_data;
+	int           i;
+	GtkTreeIter   iter;
+	gboolean      separator_required;
+
+	all_tags = g_strdupv (gth_tags_file_get_tags (gth_main_get_default_tag_file ()));
+	used_tags = gth_tags_entry_get_tags (GTH_TAGS_ENTRY (self->priv->entry), FALSE);
+
+	tag_data = g_new (TagData *, g_strv_length (all_tags) + 1);
+	for (i = 0; all_tags[i] != NULL; i++) {
+		int j;
+
+		tag_data[i] = g_new0 (TagData, 1);
+		tag_data[i]->name = g_strdup (all_tags[i]);
+		tag_data[i]->suggested = FALSE;
+		tag_data[i]->used = FALSE;
+		for (j = 0; ! tag_data[i]->used && (used_tags[j] != NULL); j++)
+			if (g_utf8_collate (tag_data[i]->name, used_tags[j]) == 0)
+				tag_data[i]->used = TRUE;
+
+		if (! tag_data[i]->used)
+			for (j = 0; ! tag_data[i]->suggested && (self->priv->last_used[j] != NULL); j++)
+				if (g_utf8_collate (tag_data[i]->name, self->priv->last_used[j]) == 0)
+					tag_data[i]->suggested = TRUE;
+	}
+	tag_data[i] = NULL;
 
-	tags = gth_main_get_default_tag_file ();
+	g_qsort_with_data (tag_data,
+			   g_strv_length (all_tags),
+			   sizeof (TagData *),
+			   sort_tag_data,
+			   NULL);
 
-	g_strfreev (self->priv->tags);
-	self->priv->tags = g_strdupv (gth_tags_file_get_tags (tags));
+	gtk_list_store_clear (self->priv->store);
+
+	/* used */
 
-	for (i = 0; self->priv->tags[i] != NULL; i++) {
+	separator_required = FALSE;
+	for (i = 0; tag_data[i] != NULL; i++) {
 		GtkTreeIter iter;
 
+		if (! tag_data[i]->used)
+			continue;
+
+		separator_required = TRUE;
+
 		gtk_list_store_append (self->priv->store, &iter);
 		gtk_list_store_set (self->priv->store, &iter,
-				    NAME_COLUMN, self->priv->tags[i],
+				    USED_COLUMN, TRUE,
+				    SEPARATOR_COLUMN, FALSE,
+				    NAME_COLUMN, tag_data[i]->name,
 				    -1);
 	}
 
-	gtk_list_store_clear (self->priv->store);
-	for (i = 0; self->priv->tags[i] != NULL; i++) {
-		GtkTreeIter iter;
-
+	if (separator_required) {
 		gtk_list_store_append (self->priv->store, &iter);
 		gtk_list_store_set (self->priv->store, &iter,
-				    NAME_COLUMN, self->priv->tags[i],
+				    USED_COLUMN, FALSE,
+				    SEPARATOR_COLUMN, TRUE,
+				    NAME_COLUMN, "",
 				    -1);
 	}
-}
 
+	/* suggested */
 
-static void
-tags_changed_cb (GthMonitor      *monitor,
-		 GthTagsExpander *self)
-{
-	update_tag_list (self);
-}
+	separator_required = FALSE;
+	for (i = 0; tag_data[i] != NULL; i++) {
+		GtkTreeIter iter;
 
+		if (! tag_data[i]->suggested)
+			continue;
 
-static void
-update_list_view_from_entry (GthTagsExpander *self)
-{
-	char        **tags;
-	GtkTreeIter   iter;
+		separator_required = TRUE;
+
+		gtk_list_store_append (self->priv->store, &iter);
+		gtk_list_store_set (self->priv->store, &iter,
+				    USED_COLUMN, FALSE,
+				    SEPARATOR_COLUMN, FALSE,
+				    NAME_COLUMN, tag_data[i]->name,
+				    -1);
+	}
+
+	if (separator_required) {
+		gtk_list_store_append (self->priv->store, &iter);
+		gtk_list_store_set (self->priv->store, &iter,
+				    USED_COLUMN, FALSE,
+				    SEPARATOR_COLUMN, TRUE,
+				    NAME_COLUMN, "",
+				    -1);
+	}
 
-	tags = gth_tags_entry_get_tags (GTH_TAGS_ENTRY (self->priv->entry), FALSE);
-	if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->priv->store), &iter))
-		do {
-			char     *name;
-			gboolean  used = FALSE;
-			int       i;
+	/* others */
 
-			gtk_tree_model_get (GTK_TREE_MODEL (self->priv->store), &iter,
-					    NAME_COLUMN, &name,
-					    -1);
+	for (i = 0; tag_data[i] != NULL; i++) {
+		GtkTreeIter iter;
 
-			for (i = 0; ! used && (tags[i] != NULL); i++)
-				if (g_utf8_collate (name, tags[i]) == 0)
-					used = TRUE;
+		if (tag_data[i]->used || tag_data[i]->suggested)
+			continue;
 
-			gtk_list_store_set (self->priv->store, &iter,
-					    USED_COLUMN, used,
-					    -1);
+		gtk_list_store_append (self->priv->store, &iter);
+		gtk_list_store_set (self->priv->store, &iter,
+ 				    USED_COLUMN, FALSE,
+ 				    SEPARATOR_COLUMN, FALSE,
+				    NAME_COLUMN, tag_data[i]->name,
+				    -1);
+	}
 
-			g_free (name);
-		}
-		while (gtk_tree_model_iter_next (GTK_TREE_MODEL (self->priv->store), &iter));
+	g_strfreev (self->priv->last_used);
+	self->priv->last_used = used_tags;
 
-	g_strfreev (tags);
+	for (i = 0; tag_data[i] != NULL; i++) {
+		g_free (tag_data[i]->name);
+		g_free (tag_data[i]);
+	}
+	g_free (tag_data);
+	g_strfreev (all_tags);
 }
 
 
+static void
+tags_changed_cb (GthMonitor      *monitor,
+		 GthTagsExpander *self)
+{
+	update_list_view_from_entry (self);
+}
+
 
 static void
 update_entry_from_list_view (GthTagsExpander *self)
@@ -178,9 +267,6 @@ update_entry_from_list_view (GthTagsExpander *self)
 	}
 	while (gtk_tree_model_iter_next (GTK_TREE_MODEL (self->priv->store), &iter));
 
-	if (name_list == NULL)
-		return;
-
 	name_list = g_list_reverse (name_list);
 	tags = g_new (char *, g_list_length (name_list) + 1);
 	for (i = 0, scan = name_list; scan; scan = scan->next)
@@ -226,28 +312,6 @@ cell_renderer_toggle_toggled_cb (GtkCellRendererToggle *cell_renderer,
 
 
 static void
-tag_list_map_cb (GtkWidget       *widget,
-		 GthTagsExpander *self)
-{
-	GtkWidget   *toplevel;
-        GdkGeometry  geometry;
-
-return; /* FIXME */
-
-        toplevel = gtk_widget_get_toplevel (widget);
-        if (! GTK_WIDGET_TOPLEVEL (toplevel))
-        	return;
-
-        geometry.min_width = -1;
-        geometry.min_height = 230;
-        gtk_window_set_geometry_hints (GTK_WINDOW (toplevel),
-				       widget,
-				       &geometry,
-                                       GDK_HINT_MIN_SIZE);
-}
-
-
-static void
 tag_list_unmap_cb (GtkWidget       *widget,
 	           GthTagsExpander *self)
 {
@@ -267,6 +331,19 @@ tag_list_unmap_cb (GtkWidget       *widget,
 }
 
 
+static gboolean
+row_separator_func (GtkTreeModel *model,
+                    GtkTreeIter  *iter,
+                    gpointer      data)
+{
+	gboolean separator;
+
+	gtk_tree_model_get (model, iter, SEPARATOR_COLUMN, &separator, -1);
+
+	return separator;
+}
+
+
 static void
 gth_tags_expander_instance_init (GthTagsExpander *self)
 {
@@ -275,12 +352,17 @@ gth_tags_expander_instance_init (GthTagsExpander *self)
 	GtkWidget         *scrolled_window;
 
 	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_TAGS_EXPANDER, GthTagsExpanderPrivate);
+	self->priv->last_used = g_new0 (char *, 1);
 
 	/* the treeview */
 
-	self->priv->store = gtk_list_store_new (N_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_STRING);
+	self->priv->store = gtk_list_store_new (N_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_STRING);
 	self->priv->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (self->priv->store));
 	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (self->priv->tree_view), FALSE);
+	gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (self->priv->tree_view),
+					      row_separator_func,
+					      self,
+					      NULL);
 	g_object_unref (self->priv->store);
 
 	/* the checkbox column */
@@ -295,11 +377,9 @@ gth_tags_expander_instance_init (GthTagsExpander *self)
 	gtk_tree_view_column_set_attributes (column, renderer,
 					     "active", USED_COLUMN,
 					     NULL);
-	gtk_tree_view_append_column (GTK_TREE_VIEW (self->priv->tree_view), column);
 
 	/* the name column. */
 
-	column = gtk_tree_view_column_new ();
 	renderer = gtk_cell_renderer_text_new ();
         gtk_tree_view_column_pack_start (column, renderer, TRUE);
         gtk_tree_view_column_set_attributes (column, renderer,
@@ -325,7 +405,6 @@ gth_tags_expander_instance_init (GthTagsExpander *self)
 					NULL);
 	gtk_widget_set_size_request (scrolled_window, -1, 230);
 	gtk_container_add (GTK_CONTAINER (scrolled_window), self->priv->tree_view);
-	g_signal_connect (scrolled_window, "map", G_CALLBACK (tag_list_map_cb), self);
 	g_signal_connect (scrolled_window, "unmap", G_CALLBACK (tag_list_unmap_cb), self);
 	gtk_widget_show (scrolled_window);
 	gtk_container_add (GTK_CONTAINER (self), scrolled_window);
@@ -367,7 +446,7 @@ gth_tags_expander_new (GtkEntry *entry)
 
 	self = g_object_new (GTH_TYPE_TAGS_EXPANDER, "label", _("_Show all the tags"), "use-underline", TRUE, NULL);
 	self->priv->entry = entry;
-	update_tag_list (self);
+	update_list_view_from_entry (self);
 
 	g_signal_connect_swapped (self->priv->entry,
 				  "notify::text",



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