[gthumb] selections: show an emblem when a file is added to a selection



commit bdc81841beef5ea609987259eb93d8947b6df364
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Mon Apr 9 21:20:08 2012 +0200

    selections: show an emblem when a file is added to a selection

 extensions/selections/Makefile.am                  |   20 ++--
 .../selections/gth-metadata-provider-selections.c  |  108 ++++++++++++++++++++
 .../selections/gth-metadata-provider-selections.h  |   51 +++++++++
 extensions/selections/gth-selections-manager.c     |   54 ++++++++--
 extensions/selections/gth-selections-manager.h     |    4 +
 extensions/selections/main.c                       |    2 +
 gthumb/glib-utils.h                                |    1 +
 gthumb/gth-browser.c                               |   73 +++++++++++++
 gthumb/gth-file-list.c                             |   44 ++++++++
 gthumb/gth-file-list.h                             |    2 +
 gthumb/gth-file-store.c                            |   16 +++-
 gthumb/gth-file-store.h                            |    1 +
 gthumb/gth-grid-view.c                             |   53 ++++++++++
 gthumb/gth-main-default-metadata.c                 |    1 +
 gthumb/gth-monitor.c                               |   41 ++++++++
 gthumb/gth-monitor.h                               |    6 +-
 16 files changed, 453 insertions(+), 24 deletions(-)
---
diff --git a/extensions/selections/Makefile.am b/extensions/selections/Makefile.am
index 1d1156e..95889b8 100644
--- a/extensions/selections/Makefile.am
+++ b/extensions/selections/Makefile.am
@@ -1,15 +1,17 @@
 extensiondir = $(pkglibdir)/extensions
 extension_LTLIBRARIES = libselections.la
 
-libselections_la_SOURCES = 		\
-	actions.c			\
-	actions.h			\
-	callbacks.c			\
-	callbacks.h			\
-	gth-file-source-selections.c 	\
-	gth-file-source-selections.h	\
-	gth-selections-manager.c	\
-	gth-selections-manager.h	\
+libselections_la_SOURCES = 			\
+	actions.c				\
+	actions.h				\
+	callbacks.c				\
+	callbacks.h				\
+	gth-file-source-selections.c 		\
+	gth-file-source-selections.h		\
+	gth-metadata-provider-selections.c	\
+	gth-metadata-provider-selections.h	\
+	gth-selections-manager.c		\
+	gth-selections-manager.h		\
 	main.c
 
 libselections_la_CFLAGS = $(GTHUMB_CFLAGS) -I$(top_srcdir) -I$(top_builddir)/gthumb 
diff --git a/extensions/selections/gth-metadata-provider-selections.c b/extensions/selections/gth-metadata-provider-selections.c
new file mode 100644
index 0000000..14c0615
--- /dev/null
+++ b/extensions/selections/gth-metadata-provider-selections.c
@@ -0,0 +1,108 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2012 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <gthumb.h>
+#include "gth-metadata-provider-selections.h"
+#include "gth-selections-manager.h"
+
+
+G_DEFINE_TYPE (GthMetadataProviderSelections, gth_metadata_provider_selections, GTH_TYPE_METADATA_PROVIDER)
+
+
+static gboolean
+gth_metadata_provider_selections_can_read (GthMetadataProvider  *self,
+				           const char           *mime_type,
+				           char                **attribute_v)
+{
+	return _g_file_attributes_matches_any_v (GTH_FILE_ATTRIBUTE_EMBLEMS,
+					         attribute_v);
+}
+
+
+static gboolean
+gth_metadata_provider_selections_can_write (GthMetadataProvider  *self,
+				            const char           *mime_type,
+				            char                **attribute_v)
+{
+	return FALSE;
+}
+
+
+static void
+gth_metadata_provider_selections_read (GthMetadataProvider *self,
+				       GthFileData         *file_data,
+				       const char          *attributes,
+				       GCancellable        *cancellable)
+{
+	GList         *emblem_list;
+	GthStringList *emblems;
+	GthStringList *other_emblems;
+	int            i;
+
+	emblem_list = NULL;
+	for (i = GTH_SELECTIONS_MANAGER_N_SELECTIONS; i >= 0; i--) {
+		if (gth_selections_manager_file_exists (i, file_data->file))
+			emblem_list = g_list_prepend (emblem_list, g_strdup_printf ("selection%d", i));
+	}
+
+	emblems = gth_string_list_new (emblem_list);
+	other_emblems = (GthStringList *) g_file_info_get_attribute_object (file_data->info, GTH_FILE_ATTRIBUTE_EMBLEMS);
+	if (other_emblems != NULL)
+		gth_string_list_append (emblems, other_emblems);
+
+	g_file_info_set_attribute_object (file_data->info, GTH_FILE_ATTRIBUTE_EMBLEMS, G_OBJECT (emblems));
+
+	g_object_unref (emblems);
+	_g_string_list_free (emblem_list);
+}
+
+
+static void
+gth_metadata_provider_selections_write (GthMetadataProvider   *self,
+				        GthMetadataWriteFlags  flags,
+				        GthFileData           *file_data,
+				        const char            *attributes,
+				        GCancellable          *cancellable)
+{
+	/* void: never called */
+}
+
+
+static void
+gth_metadata_provider_selections_class_init (GthMetadataProviderSelectionsClass *klass)
+{
+	GthMetadataProviderClass *mp_class;
+
+	mp_class = GTH_METADATA_PROVIDER_CLASS (klass);
+	mp_class->can_read = gth_metadata_provider_selections_can_read;
+	mp_class->can_write = gth_metadata_provider_selections_can_write;
+	mp_class->read = gth_metadata_provider_selections_read;
+	mp_class->write = gth_metadata_provider_selections_write;
+}
+
+
+static void
+gth_metadata_provider_selections_init (GthMetadataProviderSelections *self)
+{
+	/* void */
+}
diff --git a/extensions/selections/gth-metadata-provider-selections.h b/extensions/selections/gth-metadata-provider-selections.h
new file mode 100644
index 0000000..c370d62
--- /dev/null
+++ b/extensions/selections/gth-metadata-provider-selections.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2012 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GTH_METADATA_PROVIDER_SELECTIONS_H
+#define GTH_METADATA_PROVIDER_SELECTIONS_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gthumb.h>
+
+#define GTH_TYPE_METADATA_PROVIDER_SELECTIONS         (gth_metadata_provider_selections_get_type ())
+#define GTH_METADATA_PROVIDER_SELECTIONS(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GTH_TYPE_METADATA_PROVIDER_SELECTIONS, GthMetadataProviderSelections))
+#define GTH_METADATA_PROVIDER_SELECTIONS_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GTH_TYPE_METADATA_PROVIDER_SELECTIONS, GthMetadataProviderSelectionsClass))
+#define GTH_IS_METADATA_PROVIDER_SELECTIONS(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTH_TYPE_METADATA_PROVIDER_SELECTIONS))
+#define GTH_IS_METADATA_PROVIDER_SELECTIONS_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GTH_TYPE_METADATA_PROVIDER_SELECTIONS))
+#define GTH_METADATA_PROVIDER_SELECTIONS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GTH_TYPE_METADATA_PROVIDER_SELECTIONS, GthMetadataProviderSelectionsClass))
+
+typedef struct _GthMetadataProviderSelections         GthMetadataProviderSelections;
+typedef struct _GthMetadataProviderSelectionsClass    GthMetadataProviderSelectionsClass;
+
+struct _GthMetadataProviderSelections
+{
+	GthMetadataProvider __parent;
+};
+
+struct _GthMetadataProviderSelectionsClass
+{
+	GthMetadataProviderClass __parent_class;	
+};
+
+GType gth_metadata_provider_selections_get_type (void) G_GNUC_CONST;
+
+#endif /* GTH_METADATA_PROVIDER_SELECTIONS_H */
diff --git a/extensions/selections/gth-selections-manager.c b/extensions/selections/gth-selections-manager.c
index 5ba4c2b..93e5213 100644
--- a/extensions/selections/gth-selections-manager.c
+++ b/extensions/selections/gth-selections-manager.c
@@ -27,14 +27,12 @@
 #include "gth-selections-manager.h"
 
 
-#define N_SELECTIONS 3
-
-
 struct _GthSelectionsManagerPrivate {
-	GList    *files[N_SELECTIONS];
-	char     *order[N_SELECTIONS];
-	gboolean  order_inverse[N_SELECTIONS];
-	GMutex   *mutex;
+	GList      *files[GTH_SELECTIONS_MANAGER_N_SELECTIONS];
+	GHashTable *files_hash[GTH_SELECTIONS_MANAGER_N_SELECTIONS];
+	char       *order[GTH_SELECTIONS_MANAGER_N_SELECTIONS];
+	gboolean    order_inverse[GTH_SELECTIONS_MANAGER_N_SELECTIONS];
+	GMutex     *mutex;
 };
 
 
@@ -72,8 +70,9 @@ gth_selections_manager_finalize (GObject *object)
 
 	self = GTH_SELECTIONS_MANAGER (object);
 
-	for (i = 0; i < N_SELECTIONS; i++) {
+	for (i = 0; i < GTH_SELECTIONS_MANAGER_N_SELECTIONS; i++) {
 		_g_object_list_unref (self->priv->files[i]);
+		g_hash_table_unref (self->priv->files_hash[i]);
 		g_free (self->priv->order[i]);
 	}
 	g_mutex_free (self->priv->mutex);
@@ -101,8 +100,9 @@ gth_selections_manager_init (GthSelectionsManager *self)
 
 	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_SELECTIONS_MANAGER, GthSelectionsManagerPrivate);
 	self->priv->mutex = g_mutex_new ();
-	for (i = 0; i < N_SELECTIONS; i++) {
+	for (i = 0; i < GTH_SELECTIONS_MANAGER_N_SELECTIONS; i++) {
 		self->priv->files[i] = NULL;
+		self->priv->files_hash[i] = g_hash_table_new (g_file_hash, (GEqualFunc) g_file_equal);
 		self->priv->order[i] = NULL;
 		self->priv->order_inverse[i] = FALSE;
 	}
@@ -280,7 +280,7 @@ _gth_selections_manager_for_each_selection (gpointer user_data)
 	ForEachChildData *data = user_data;
 	int               i;
 
-	for (i = 0; i < N_SELECTIONS; i++) {
+	for (i = 0; i < GTH_SELECTIONS_MANAGER_N_SELECTIONS; i++) {
 		char      *uri;
 		GFile     *file;
 		GFileInfo *info;
@@ -356,6 +356,7 @@ gth_selections_manager_add_files (GFile *folder,
 	GthSelectionsManager *self;
 	int                   n_selection;
 	GList                *new_list;
+	GList                *scan;
 	GList                *link;
 
 	if (! g_file_has_uri_scheme (folder, "selection"))
@@ -369,6 +370,10 @@ gth_selections_manager_add_files (GFile *folder,
 	g_mutex_lock (self->priv->mutex);
 
 	new_list = _g_file_list_dup (file_list);
+
+	for (scan = new_list; scan; scan = scan->next)
+		g_hash_table_insert (self->priv->files_hash[n_selection - 1], scan->data, GINT_TO_POINTER (1));
+
 	link = g_list_nth (self->priv->files[n_selection - 1], destination_position);
 	if (link != NULL) {
 		GList *last_new;
@@ -386,6 +391,7 @@ gth_selections_manager_add_files (GFile *folder,
 	else
 		self->priv->files[n_selection - 1] = g_list_concat (self->priv->files[n_selection - 1], new_list);
 
+	gth_monitor_emblems_changed (gth_main_get_default_monitor (), file_list);
 	gth_monitor_folder_changed (gth_main_get_default_monitor (),
 				    folder,
 				    file_list,
@@ -415,8 +421,10 @@ gth_selections_manager_remove_files (GFile *folder,
 	g_mutex_lock (self->priv->mutex);
 
 	files_to_remove = g_hash_table_new (g_file_hash, (GEqualFunc) g_file_equal);
-	for (scan = file_list; scan; scan = scan->next)
+	for (scan = file_list; scan; scan = scan->next) {
 		g_hash_table_insert (files_to_remove, scan->data, GINT_TO_POINTER (1));
+		g_hash_table_remove (self->priv->files_hash[n_selection - 1], scan->data);
+	}
 
 	new_list = NULL;
 	for (scan = self->priv->files[n_selection - 1]; scan; scan = scan->next) {
@@ -438,6 +446,7 @@ gth_selections_manager_remove_files (GFile *folder,
 				    folder,
 				    file_list,
 				    GTH_MONITOR_EVENT_REMOVED);
+	gth_monitor_emblems_changed (gth_main_get_default_monitor (), file_list);
 
 	g_mutex_unlock (self->priv->mutex);
 }
@@ -506,6 +515,27 @@ gth_selections_manager_set_sort_type (GFile      *folder,
 }
 
 
+gboolean
+gth_selections_manager_file_exists (int    n_selection,
+				    GFile *file)
+{
+	GthSelectionsManager *self;
+	gboolean             result;
+
+	if ((n_selection <= 0) || (n_selection > GTH_SELECTIONS_MANAGER_N_SELECTIONS))
+		return FALSE;
+
+	self = gth_selections_manager_get_default ();
+	g_mutex_lock (self->priv->mutex);
+
+	result = (g_hash_table_lookup (self->priv->files_hash[n_selection - 1], file) != NULL);
+
+	g_mutex_unlock (self->priv->mutex);
+
+	return result;
+}
+
+
 int
 _g_file_get_n_selection (GFile *file)
 {
@@ -522,7 +552,7 @@ _g_file_get_n_selection (GFile *file)
 
 	g_free (uri);
 
-	if (n > N_SELECTIONS)
+	if (n > GTH_SELECTIONS_MANAGER_N_SELECTIONS)
 		n = -1;
 
 	return n;
diff --git a/extensions/selections/gth-selections-manager.h b/extensions/selections/gth-selections-manager.h
index f6294a1..92058b0 100644
--- a/extensions/selections/gth-selections-manager.h
+++ b/extensions/selections/gth-selections-manager.h
@@ -28,6 +28,8 @@
 
 G_BEGIN_DECLS
 
+#define GTH_SELECTIONS_MANAGER_N_SELECTIONS 3
+
 #define GTH_TYPE_SELECTIONS_MANAGER         (gth_selections_manager_get_type ())
 #define GTH_SELECTIONS_MANAGER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GTH_TYPE_SELECTIONS_MANAGER, GthSelectionsManager))
 #define GTH_SELECTIONS_MANAGER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GTH_TYPE_SELECTIONS_MANAGER, GthSelectionsManagerClass))
@@ -70,6 +72,8 @@ void     gth_selections_manager_set_sort_type    (GFile                *folder,
 						  gboolean              sort_inverse);
 void     gth_selections_manager_update_file_info (GFile                *file,
 						  GFileInfo            *info);
+gboolean gth_selections_manager_file_exists      (int                   n_selection,
+						  GFile                *file);
 
 /* utilities */
 
diff --git a/extensions/selections/main.c b/extensions/selections/main.c
index 2dcfaeb..abd97ad 100644
--- a/extensions/selections/main.c
+++ b/extensions/selections/main.c
@@ -25,12 +25,14 @@
 #include <gthumb.h>
 #include "callbacks.h"
 #include "gth-file-source-selections.h"
+#include "gth-metadata-provider-selections.h"
 
 
 G_MODULE_EXPORT void
 gthumb_extension_activate (void)
 {
 	gth_main_register_file_source (GTH_TYPE_FILE_SOURCE_SELECTIONS);
+	gth_main_register_metadata_provider (GTH_TYPE_METADATA_PROVIDER_SELECTIONS);
 	gth_hook_add_callback ("gth-browser-construct", 10, G_CALLBACK (selections__gth_browser_construct_cb), NULL);
 	gth_hook_add_callback ("gth-browser-file-list-key-press", 10, G_CALLBACK (selections__gth_browser_file_list_key_press_cb), NULL);
 	gth_hook_add_callback ("gth-browser-load-location-after", 10, G_CALLBACK (selections__gth_browser_load_location_after_cb), NULL);
diff --git a/gthumb/glib-utils.h b/gthumb/glib-utils.h
index 28fd1d8..b15babc 100644
--- a/gthumb/glib-utils.h
+++ b/gthumb/glib-utils.h
@@ -55,6 +55,7 @@ G_BEGIN_DECLS
 #define GFILE_STANDARD_ATTRIBUTES_WITH_FAST_CONTENT_TYPE (DEFINE_STANDARD_ATTRIBUTES(",standard::fast-content-type"))
 #define GFILE_STANDARD_ATTRIBUTES_WITH_CONTENT_TYPE (DEFINE_STANDARD_ATTRIBUTES(",standard::fast-content-type,standard::content-type"))
 #define GIO_ATTRIBUTES ("standard::*,etag::*,id::*,access::*,mountable::*,time::*,unix::*,dos::*,owner::*,thumbnail::*,filesystem::*,gvfs::*,xattr::*,xattr-sys::*,selinux::*")
+#define GTH_FILE_ATTRIBUTE_EMBLEMS "gth::file::emblems"
 
 #define GNOME_COPIED_FILES (gdk_atom_intern_static_string ("x-special/gnome-copied-files"))
 #define IROUND(x) ((int)floor(((double)x) + 0.5))
diff --git a/gthumb/gth-browser.c b/gthumb/gth-browser.c
index 0ed580b..1b0c81b 100644
--- a/gthumb/gth-browser.c
+++ b/gthumb/gth-browser.c
@@ -129,6 +129,7 @@ struct _GthBrowserPrivate {
 	gulong             folder_changed_id;
 	gulong             file_renamed_id;
 	gulong             metadata_changed_id;
+	gulong             emblems_changed_id;
 	gulong             entry_points_changed_id;
 	gulong             order_changed_id;
 	GthFileData       *location;
@@ -1339,6 +1340,13 @@ _gth_browser_get_list_attributes (GthBrowser *browser,
 		g_free (thumbnail_caption);
 	}
 
+	/* other attributes */
+
+	g_string_append (attributes, ",");
+	g_string_append (attributes, GTH_FILE_ATTRIBUTE_EMBLEMS);
+
+	/* save in a variable to avoid recalculation */
+
 	browser->priv->list_attributes = g_string_free (attributes, FALSE);
 
 	return browser->priv->list_attributes;
@@ -2234,6 +2242,8 @@ _gth_browser_real_close (GthBrowser *browser)
 	g_signal_handler_disconnect (gth_main_get_default_monitor (),
 				     browser->priv->metadata_changed_id);
 	g_signal_handler_disconnect (gth_main_get_default_monitor (),
+				     browser->priv->emblems_changed_id);
+	g_signal_handler_disconnect (gth_main_get_default_monitor (),
 				     browser->priv->entry_points_changed_id);
 	g_signal_handler_disconnect (gth_main_get_default_monitor (),
 				     browser->priv->order_changed_id);
@@ -3301,6 +3311,64 @@ metadata_changed_cb (GthMonitor  *monitor,
 }
 
 
+typedef struct {
+	GthBrowser    *browser;
+	GthFileSource *file_source;
+	GList         *files;
+} EmblemsData;
+
+
+static void
+emblems_data_free (EmblemsData *data)
+{
+	_g_object_list_unref (data->files);
+	g_object_unref (data->file_source);
+	g_free (data);
+}
+
+
+static void
+emblems_attributes_ready_cb (GthFileSource *file_source,
+			     GList         *files,
+			     GError        *error,
+			     gpointer       user_data)
+{
+	EmblemsData *data = user_data;
+
+	if (error == NULL) {
+		GthBrowser *browser = data->browser;
+
+		gth_file_list_update_emblems (GTH_FILE_LIST (browser->priv->file_list), files);
+		gth_file_list_update_emblems (GTH_FILE_LIST (browser->priv->thumbnail_list), files);
+	}
+
+	emblems_data_free (data);
+}
+
+
+static void
+emblems_changed_cb (GthMonitor  *monitor,
+		    GList       *files, /* GFile list */
+		    GthBrowser  *browser)
+{
+	EmblemsData *data;
+
+	if (browser->priv->location_source == NULL)
+		return;
+
+	data = g_new0 (EmblemsData, 1);
+	data->browser = browser;
+	data->file_source = g_object_ref (browser->priv->location_source);
+	data->files = _g_object_list_ref (files);
+
+	gth_file_source_read_attributes (browser->priv->location_source,
+					 files,
+					 GTH_FILE_ATTRIBUTE_EMBLEMS,
+					 emblems_attributes_ready_cb,
+					 data);
+}
+
+
 static void
 entry_points_changed_cb (GthMonitor *monitor,
 			 GthBrowser *browser)
@@ -4495,6 +4563,11 @@ gth_browser_init (GthBrowser *browser)
 				  "metadata-changed",
 				  G_CALLBACK (metadata_changed_cb),
 				  browser);
+	browser->priv->emblems_changed_id =
+		g_signal_connect (gth_main_get_default_monitor (),
+				  "emblems-changed",
+				  G_CALLBACK (emblems_changed_cb),
+				  browser);
 	browser->priv->entry_points_changed_id =
 		g_signal_connect (gth_main_get_default_monitor (),
 				  "entry-points-changed",
diff --git a/gthumb/gth-file-list.c b/gthumb/gth-file-list.c
index e416a6c..2eec4ee 100644
--- a/gthumb/gth-file-list.c
+++ b/gthumb/gth-file-list.c
@@ -49,6 +49,7 @@ typedef enum {
 	GTH_FILE_LIST_OP_TYPE_CLEAR_FILES,
 	GTH_FILE_LIST_OP_TYPE_ADD_FILES,
 	GTH_FILE_LIST_OP_TYPE_UPDATE_FILES,
+	GTH_FILE_LIST_OP_TYPE_UPDATE_EMBLEMS,
 	GTH_FILE_LIST_OP_TYPE_DELETE_FILES,
 	GTH_FILE_LIST_OP_TYPE_SET_FILTER,
 	GTH_FILE_LIST_OP_TYPE_SET_SORT_FUNC,
@@ -181,6 +182,7 @@ gth_file_list_op_free (GthFileListOp *op)
 		break;
 	case GTH_FILE_LIST_OP_TYPE_ADD_FILES:
 	case GTH_FILE_LIST_OP_TYPE_UPDATE_FILES:
+	case GTH_FILE_LIST_OP_TYPE_UPDATE_EMBLEMS:
 		_g_object_list_unref (op->file_list);
 		break;
 	case GTH_FILE_LIST_OP_TYPE_DELETE_FILES:
@@ -1002,6 +1004,45 @@ gth_file_list_update_files (GthFileList *file_list,
 
 
 static void
+gfl_update_emblems (GthFileList *file_list,
+		    GList       *files)
+{
+	GthFileStore *file_store;
+	GList        *scan;
+
+	file_store = (GthFileStore*) gth_file_view_get_model (GTH_FILE_VIEW (file_list->priv->view));
+	for (scan = files; scan; scan = scan->next) {
+		GthFileData *file_data = scan->data;
+		ThumbData   *thumb_data;
+		GtkTreeIter  iter;
+
+		thumb_data = g_hash_table_lookup (file_list->priv->thumb_data, file_data->file);
+		if (thumb_data == NULL)
+			continue;
+
+		if (gth_file_store_find (file_store, file_data->file, &iter))
+			gth_file_store_queue_set (file_store,
+						  &iter,
+						  GTH_FILE_STORE_EMBLEMS_COLUMN, g_file_info_get_attribute_object (file_data->info, GTH_FILE_ATTRIBUTE_EMBLEMS),
+						  -1);
+	}
+	gth_file_store_exec_set (file_store);
+}
+
+
+void
+gth_file_list_update_emblems (GthFileList *file_list,
+			      GList       *files /* GthFileData */)
+{
+	GthFileListOp *op;
+
+	op = gth_file_list_op_new (GTH_FILE_LIST_OP_TYPE_UPDATE_EMBLEMS);
+	op->file_list = _g_object_list_ref (files);
+	_gth_file_list_queue_op (file_list, op);
+}
+
+
+static void
 gfl_rename_file (GthFileList *file_list,
 		 GFile       *file,
 		 GthFileData *file_data)
@@ -1858,6 +1899,9 @@ _gth_file_list_exec_next_op (GthFileList *file_list)
 	case GTH_FILE_LIST_OP_TYPE_UPDATE_FILES:
 		gfl_update_files (file_list, op->file_list);
 		break;
+	case GTH_FILE_LIST_OP_TYPE_UPDATE_EMBLEMS:
+		gfl_update_emblems (file_list, op->file_list);
+		break;
 	case GTH_FILE_LIST_OP_TYPE_ENABLE_THUMBS:
 		gfl_enable_thumbs (file_list, op->ival);
 		exec_next_op = FALSE;
diff --git a/gthumb/gth-file-list.h b/gthumb/gth-file-list.h
index 3caea6b..a1e2254 100644
--- a/gthumb/gth-file-list.h
+++ b/gthumb/gth-file-list.h
@@ -84,6 +84,8 @@ void              gth_file_list_delete_files      (GthFileList          *file_li
 					           GList                *list /* GFile */);
 void              gth_file_list_update_files      (GthFileList          *file_list,
 					           GList                *list /* GthFileData */);
+void              gth_file_list_update_emblems    (GthFileList          *file_list,
+					           GList                *list /* GthFileData */);
 void              gth_file_list_rename_file       (GthFileList          *file_list,
 					           GFile                *file,
 					           GthFileData          *file_data);
diff --git a/gthumb/gth-file-store.c b/gthumb/gth-file-store.c
index 41216b5..5a23416 100644
--- a/gthumb/gth-file-store.c
+++ b/gthumb/gth-file-store.c
@@ -24,6 +24,7 @@
 #include "glib-utils.h"
 #include "gth-file-store.h"
 #include "gth-marshal.h"
+#include "gth-string-list.h"
 
 
 #undef  DEBUG_FILE_STORE
@@ -264,6 +265,7 @@ gth_file_store_init (GthFileStore *file_store)
 		column_type[GTH_FILE_STORE_FILE_DATA_COLUMN] = GTH_TYPE_FILE_DATA;
 		column_type[GTH_FILE_STORE_THUMBNAIL_COLUMN] = GDK_TYPE_PIXBUF;
 		column_type[GTH_FILE_STORE_IS_ICON_COLUMN] = G_TYPE_BOOLEAN;
+		column_type[GTH_FILE_STORE_EMBLEMS_COLUMN] = GTH_TYPE_STRING_LIST;
 	}
 }
 
@@ -375,6 +377,10 @@ gth_file_store_get_value (GtkTreeModel *tree_model,
 		g_value_init (value, G_TYPE_BOOLEAN);
 		g_value_set_boolean (value, row->is_icon);
 		break;
+	case GTH_FILE_STORE_EMBLEMS_COLUMN:
+		g_value_init (value, G_TYPE_STRING);
+		g_value_set_object (value, g_file_info_get_attribute_object (row->file_data->info, GTH_FILE_ATTRIBUTE_EMBLEMS));
+		break;
 	}
 }
 
@@ -1397,8 +1403,9 @@ gth_file_store_queue_set_valist (GthFileStore *file_store,
 
  	column = va_arg (var_args, int);
   	while (column != -1) {
-  		GthFileData *file_data;
-  		GdkPixbuf   *thumbnail;
+  		GthFileData   *file_data;
+  		GdkPixbuf     *thumbnail;
+  		GthStringList *string_list;
 
   		switch (column) {
   		case GTH_FILE_STORE_FILE_DATA_COLUMN:
@@ -1418,6 +1425,11 @@ gth_file_store_queue_set_valist (GthFileStore *file_store,
   			row->is_icon = va_arg (var_args, gboolean);
   			row->changed = TRUE;
   			break;
+  		case GTH_FILE_STORE_EMBLEMS_COLUMN:
+  			string_list = va_arg (var_args, GthStringList *);
+  			g_file_info_set_attribute_object (row->file_data->info, GTH_FILE_ATTRIBUTE_EMBLEMS, G_OBJECT (string_list));
+  			row->changed = TRUE;
+  			break;
   		default:
   			g_warning ("%s: Invalid column number %d added to iter (remember to end your list of columns with a -1)", G_STRLOC, column);
   			break;
diff --git a/gthumb/gth-file-store.h b/gthumb/gth-file-store.h
index 6dd3fbf..b4db381 100644
--- a/gthumb/gth-file-store.h
+++ b/gthumb/gth-file-store.h
@@ -43,6 +43,7 @@ enum {
 	GTH_FILE_STORE_FILE_DATA_COLUMN,
 	GTH_FILE_STORE_THUMBNAIL_COLUMN,
 	GTH_FILE_STORE_IS_ICON_COLUMN,
+	GTH_FILE_STORE_EMBLEMS_COLUMN,
 	GTH_FILE_STORE_N_COLUMNS
 };
 
diff --git a/gthumb/gth-grid-view.c b/gthumb/gth-grid-view.c
index 2b733c6..374fb0a 100644
--- a/gthumb/gth-grid-view.c
+++ b/gthumb/gth-grid-view.c
@@ -33,6 +33,7 @@
 #include "gth-file-selection.h"
 #include "gth-file-store.h"
 #include "gth-file-view.h"
+#include "gth-icon-cache.h"
 #include "gth-grid-view.h"
 #include "gth-marshal.h"
 #include "gth-enum-types.h"
@@ -205,6 +206,8 @@ struct _GthGridViewPrivate {
 	char                  *caption_attributes;
 	char                 **caption_attributes_v;
 	PangoLayout           *caption_layout;
+
+	GthIconCache          *icon_cache;
 };
 
 
@@ -1030,6 +1033,9 @@ gth_grid_view_unrealize (GtkWidget *widget)
 	g_object_unref (self->priv->caption_layout);
 	self->priv->caption_layout = NULL;
 
+	gth_icon_cache_free (self->priv->icon_cache);
+	self->priv->icon_cache = NULL;
+
 	GTK_WIDGET_CLASS (gth_grid_view_parent_class)->unrealize (widget);
 }
 
@@ -1483,6 +1489,51 @@ _gth_grid_view_item_draw_caption (GthGridViewItem *item,
 }
 
 
+#define EMBLEM_SIZE 16
+
+
+static void
+_gth_grid_view_item_draw_emblems (GthGridViewItem *item,
+				  cairo_t         *cr,
+				  GtkWidget       *widget,
+				  GtkStateFlags    item_state,
+				  GthGridView     *grid_view)
+{
+	GthStringList *emblems;
+	GList         *scan;
+	int            emblem_offset;
+
+	cairo_save (cr);
+
+	emblem_offset = 0;
+	emblems = (GthStringList *) g_file_info_get_attribute_object (item->file_data->info, GTH_FILE_ATTRIBUTE_EMBLEMS);
+	for (scan = gth_string_list_get_list (emblems); scan; scan = scan->next) {
+		char      *emblem = scan->data;
+		GIcon     *icon;
+		GdkPixbuf *pixbuf;
+
+		if (grid_view->priv->icon_cache == NULL)
+			grid_view->priv->icon_cache = gth_icon_cache_new (gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (grid_view))), EMBLEM_SIZE);
+
+		icon = g_themed_icon_new (emblem);
+		pixbuf = gth_icon_cache_get_pixbuf (grid_view->priv->icon_cache, icon);
+		if (pixbuf != NULL) {
+			gdk_cairo_set_source_pixbuf (cr, pixbuf, item->thumbnail_area.x + emblem_offset + 1, item->thumbnail_area.y + 1);
+			cairo_rectangle (cr, item->thumbnail_area.x + emblem_offset + 1, item->thumbnail_area.y + 1, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf));
+			cairo_fill (cr);
+
+			g_object_unref (pixbuf);
+
+			emblem_offset += EMBLEM_SIZE + (EMBLEM_SIZE / 2);
+		}
+
+		g_object_unref (icon);
+	}
+
+	cairo_restore (cr);
+}
+
+
 static void
 _gth_grid_view_draw_item (GthGridView     *self,
 			  GthGridViewItem *item,
@@ -1518,6 +1569,7 @@ _gth_grid_view_draw_item (GthGridView     *self,
 
 	_gth_grid_view_item_draw_thumbnail (item, cr, GTK_WIDGET (self), item_state, self);
 	_gth_grid_view_item_draw_caption (item, cr, GTK_WIDGET (self), item_state, self->priv->caption_layout, self);
+	_gth_grid_view_item_draw_emblems (item, cr, GTK_WIDGET (self), item_state, self);
 }
 
 
@@ -3786,6 +3838,7 @@ gth_grid_view_init (GthGridView *self)
 	self->priv->caption_attributes = NULL;
 	self->priv->caption_attributes_v = NULL;
 	self->priv->caption_layout = NULL;
+	self->priv->icon_cache = NULL;
 
 	_gth_grid_view_set_hadjustment (self, gtk_adjustment_new (0.0, 1.0, 0.0, 0.1, 1.0, 1.0));
 	_gth_grid_view_set_vadjustment (self, gtk_adjustment_new (0.0, 1.0, 0.0, 0.1, 1.0, 1.0));
diff --git a/gthumb/gth-main-default-metadata.c b/gthumb/gth-main-default-metadata.c
index 02ec2a0..ba8d52a 100644
--- a/gthumb/gth-main-default-metadata.c
+++ b/gthumb/gth-main-default-metadata.c
@@ -53,6 +53,7 @@ GthMetadataInfo file_metadata_info[] = {
 	{ "general::tags", N_("Tags"), "general", 18, NULL, GTH_METADATA_ALLOW_EVERYWHERE },
 	{ "general::rating", N_("Rating"), "general", 19, NULL, GTH_METADATA_ALLOW_EVERYWHERE },
 
+	{ "gth::file::emblems", "", "", 0, NULL, GTH_METADATA_ALLOW_NOWHERE },
 	{ "image::width", "", "", 0, NULL, GTH_METADATA_ALLOW_NOWHERE },
 	{ "image::height", "", "", 0, NULL, GTH_METADATA_ALLOW_NOWHERE },
 	{ "frame::width", "", "", 0, NULL, GTH_METADATA_ALLOW_NOWHERE },
diff --git a/gthumb/gth-monitor.c b/gthumb/gth-monitor.c
index cf9fd7e..6475003 100644
--- a/gthumb/gth-monitor.c
+++ b/gthumb/gth-monitor.c
@@ -38,6 +38,7 @@ enum {
 	FOLDER_CONTENT_CHANGED,
 	FILE_RENAMED,
 	METADATA_CHANGED,
+	EMBLEMS_CHANGED,
 	ENTRY_POINTS_CHANGED,
 	ORDER_CHANGED,
 	LAST_SIGNAL
@@ -156,6 +157,16 @@ gth_monitor_class_init (GthMonitorClass *class)
 			      G_TYPE_NONE,
 			      1,
 			      G_TYPE_OBJECT);
+	monitor_signals[EMBLEMS_CHANGED] =
+		g_signal_new ("emblems-changed",
+			      G_TYPE_FROM_CLASS (class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GthMonitorClass, emblems_changed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__BOXED,
+			      G_TYPE_NONE,
+			      1,
+			      G_TYPE_OBJECT_LIST);
 	monitor_signals[ENTRY_POINTS_CHANGED] =
 		g_signal_new ("entry-points-changed",
 			      G_TYPE_FROM_CLASS (class),
@@ -340,6 +351,36 @@ gth_monitor_metadata_changed (GthMonitor  *self,
 
 
 void
+gth_monitor_emblems_changed (GthMonitor *self,
+			     GList      *list /* GFile list */)
+{
+	GList *changed_list = NULL;
+	GList *scan;
+
+	/* ignore paused files */
+	for (scan = list; scan; scan = scan->next) {
+		GFile *file = scan->data;
+
+		if (g_hash_table_lookup (self->priv->paused_files, file) != NULL)
+			continue;
+
+		changed_list = g_list_prepend (changed_list, g_object_ref (file));
+	}
+	changed_list = g_list_reverse (changed_list);
+
+	if (changed_list == NULL)
+		return;
+
+	g_signal_emit (G_OBJECT (self),
+		       monitor_signals[EMBLEMS_CHANGED],
+		       0,
+		       changed_list);
+
+	_g_object_list_unref (changed_list);
+}
+
+
+void
 gth_monitor_entry_points_changed (GthMonitor *self)
 {
 	g_return_if_fail (GTH_IS_MONITOR (self));
diff --git a/gthumb/gth-monitor.h b/gthumb/gth-monitor.h
index 42eb49e..c75acfa 100644
--- a/gthumb/gth-monitor.h
+++ b/gthumb/gth-monitor.h
@@ -65,7 +65,7 @@ struct _GthMonitorClass
 	void   (*tags_changed)            (GthMonitor      *monitor);
 	void   (*folder_changed)          (GthMonitor      *monitor,
 					   GFile           *parent,
-					   GList           *list,
+					   GList           *list /* GFile list */,
 					   int              position,
 					   GthMonitorEvent  event);
 	void   (*file_renamed)            (GthMonitor      *monitor,
@@ -73,6 +73,8 @@ struct _GthMonitorClass
 					   GFile           *new_file);
 	void   (*metadata_changed)        (GthMonitor      *monitor,
 					   GthFileData     *file_data);
+	void   (*emblems_changed)         (GthMonitor      *monitor,
+					   GList           *list /* GFile list */);
 	void   (*entry_points_changed)    (GthMonitor      *monitor);
 	void   (*order_changed)           (GthMonitor      *monitor,
 					   GFile           *file,
@@ -102,6 +104,8 @@ void          gth_monitor_file_renamed               (GthMonitor      *monitor,
 						      GFile           *new_file);
 void          gth_monitor_metadata_changed           (GthMonitor      *monitor,
 						      GthFileData     *file_data);
+void          gth_monitor_emblems_changed            (GthMonitor      *monitor,
+						      GList           *list /* GFile list */);
 void          gth_monitor_entry_points_changed       (GthMonitor      *monitor);
 void          gth_monitor_order_changed              (GthMonitor      *monitor,
 						      GFile           *file,



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