[gthumb] added ability to organize files by tag



commit c3c44b091cc117558a688be0d598c9247f682dfc
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Wed Aug 11 19:40:25 2010 +0200

    added ability to organize files by tag
    
    the organize command can organize files by tag, creating a catalog for each tag.

 extensions/catalogs/data/ui/organize-files.ui |   52 +++--
 extensions/catalogs/dlg-organize-files.c      |   13 +
 extensions/catalogs/gth-catalog.c             |   38 ++--
 extensions/catalogs/gth-catalog.h             |    7 +-
 extensions/catalogs/gth-organize-task.c       |  319 +++++++++++++++++++------
 extensions/catalogs/gth-organize-task.h       |    4 +-
 extensions/importer/gth-import-task.c         |    5 +-
 gthumb/gth-info-bar.c                         |    7 +
 gthumb/gth-info-bar.h                         |    1 +
 gthumb/gth-test-category.c                    |   12 +
 gthumb/gth-test-category.h                    |    4 +
 gthumb/gth-test-simple.c                      |  112 +++++-----
 gthumb/gth-test-simple.h                      |   10 +-
 gthumb/gth-time-selector.c                    |    7 +-
 gthumb/gth-time.c                             |   13 +-
 gthumb/gth-time.h                             |    2 +-
 16 files changed, 422 insertions(+), 184 deletions(-)
---
diff --git a/extensions/catalogs/data/ui/organize-files.ui b/extensions/catalogs/data/ui/organize-files.ui
index f038fc8..d9caf6f 100644
--- a/extensions/catalogs/data/ui/organize-files.ui
+++ b/extensions/catalogs/data/ui/organize-files.ui
@@ -1,32 +1,42 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0"?>
 <interface>
   <requires lib="gtk+" version="2.16"/>
   <!-- interface-naming-policy project-wide -->
   <object class="GtkDialog" id="organize_files_dialog">
     <property name="border_width">5</property>
     <property name="title" translatable="yes">Organize Files</property>
+    <property name="resizable">False</property>
     <property name="type_hint">normal</property>
     <property name="has_separator">False</property>
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox1">
         <property name="visible">True</property>
+        <property name="orientation">vertical</property>
         <property name="spacing">2</property>
         <child>
           <object class="GtkVBox" id="vbox1">
             <property name="visible">True</property>
             <property name="border_width">5</property>
+            <property name="orientation">vertical</property>
             <property name="spacing">12</property>
             <child>
               <object class="GtkHBox" id="hbox3">
                 <property name="visible">True</property>
                 <property name="spacing">12</property>
                 <child>
-                  <object class="GtkImage" id="icon_image">
+                  <object class="GtkAlignment" id="alignment3">
                     <property name="visible">True</property>
-                    <property name="yalign">0</property>
-                    <property name="stock">gtk-dialog-info</property>
-                    <property name="pixel_size">24</property>
-                    <property name="icon-size">6</property>
+                    <property name="left_padding">12</property>
+                    <property name="right_padding">12</property>
+                    <child>
+                      <object class="GtkImage" id="icon_image">
+                        <property name="visible">True</property>
+                        <property name="yalign">0</property>
+                        <property name="pixel_size">48</property>
+                        <property name="icon_name">file-catalog</property>
+                        <property name="icon-size">6</property>
+                      </object>
+                    </child>
                   </object>
                   <packing>
                     <property name="expand">False</property>
@@ -36,22 +46,20 @@
                 <child>
                   <object class="GtkVBox" id="vbox2">
                     <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
                     <property name="spacing">12</property>
                     <child>
                       <object class="GtkVBox" id="vbox4">
                         <property name="visible">True</property>
+                        <property name="orientation">vertical</property>
                         <property name="spacing">6</property>
                         <child>
-                          <object class="GtkAlignment" id="alignment2">
+                          <object class="GtkAlignment" id="info_alignment">
                             <property name="visible">True</property>
-                            <property name="bottom_padding">6</property>
+                            <property name="top_padding">6</property>
+                            <property name="bottom_padding">12</property>
                             <child>
-                              <object class="GtkLabel" id="label3">
-                                <property name="visible">True</property>
-                                <property name="xalign">0</property>
-                                <property name="label" translatable="yes">Files will be organized in catalogs. No file will be moved on disk.</property>
-                                <property name="wrap">True</property>
-                              </object>
+                              <placeholder/>
                             </child>
                           </object>
                           <packing>
@@ -156,7 +164,7 @@
                                     <property name="visible">True</property>
                                     <property name="sensitive">False</property>
                                     <property name="can_focus">True</property>
-                                    <property name="invisible_char">â??</property>
+                                    <property name="invisible_char">&#x25CF;</property>
                                     <property name="text" translatable="yes">Singles</property>
                                   </object>
                                   <packing>
@@ -270,14 +278,24 @@
     <data>
       <row>
         <col id="0">0</col>
-        <col id="1" translatable="yes">date photo was taken</col>
+        <col id="1" translatable="yes">Date photo was taken</col>
         <col id="2">camera-photo</col>
       </row>
       <row>
         <col id="0">1</col>
-        <col id="1" translatable="yes">file modified date</col>
+        <col id="1" translatable="yes">File modified date</col>
         <col id="2">appointment-soon</col>
       </row>
+      <row>
+        <col id="0">2</col>
+        <col id="1" translatable="yes">Tag</col>
+        <col id="2" translatable="yes">tag</col>
+      </row>
+      <row>
+        <col id="0">3</col>
+        <col id="1" translatable="yes">Tag (embedded)</col>
+        <col id="2" translatable="yes">tag</col>
+      </row>
     </data>
   </object>
 </interface>
diff --git a/extensions/catalogs/dlg-organize-files.c b/extensions/catalogs/dlg-organize-files.c
index 173ffa6..6518e82 100644
--- a/extensions/catalogs/dlg-organize-files.c
+++ b/extensions/catalogs/dlg-organize-files.c
@@ -101,6 +101,8 @@ dlg_organize_files (GthBrowser *browser,
 		    GFile      *folder)
 {
 	DialogData *data;
+	GtkWidget  *info_bar;
+	GtkWidget  *info_label;
 
 	g_return_if_fail (folder != NULL);
 
@@ -110,6 +112,17 @@ dlg_organize_files (GthBrowser *browser,
 	data->builder = _gtk_builder_new_from_file ("organize-files.ui", "catalogs");
 	data->dialog = GET_WIDGET ("organize_files_dialog");
 
+	info_bar = gth_info_bar_new (NULL, NULL, NULL);
+	gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_INFO);
+	info_label = gth_info_bar_get_primary_label (GTH_INFO_BAR (info_bar));
+	gtk_label_set_ellipsize (GTK_LABEL (info_label), PANGO_ELLIPSIZE_NONE);
+	gtk_label_set_line_wrap (GTK_LABEL (info_label), TRUE);
+	gtk_label_set_single_line_mode (GTK_LABEL (info_label), FALSE);
+	gtk_label_set_text (GTK_LABEL (info_label), _("Files will be organized in catalogs. No file will be moved on disk."));
+	gtk_widget_show (info_label);
+	gtk_widget_show (info_bar);
+	gtk_container_add (GTK_CONTAINER (GET_WIDGET ("info_alignment")), info_bar);
+
 	/* Set the signals handlers. */
 
 	g_signal_connect (G_OBJECT (data->dialog),
diff --git a/extensions/catalogs/gth-catalog.c b/extensions/catalogs/gth-catalog.c
index 86fa0ce..4b2712c 100644
--- a/extensions/catalogs/gth-catalog.c
+++ b/extensions/catalogs/gth-catalog.c
@@ -376,20 +376,6 @@ gth_catalog_get_order (GthCatalog *catalog,
 
 
 void
-gth_catalog_set_for_date (GthCatalog  *catalog,
-			  GthDateTime *date_time)
-{
-	GFile *catalog_file;
-
-	gth_catalog_set_date (catalog, date_time);
-	catalog_file = gth_catalog_get_file_for_date (date_time);
-	gth_catalog_set_file (catalog, catalog_file);
-
-	g_object_unref (catalog_file);
-}
-
-
-void
 gth_catalog_load_from_data (GthCatalog  *catalog,
 			    const void  *buffer,
 			    gsize        count,
@@ -1129,22 +1115,20 @@ gth_catalog_load_from_file_async (GFile         *file,
 
 
 GFile *
-gth_catalog_get_file_for_date (GthDateTime *date_time)
+gth_catalog_get_file_for_date (GthDateTime *date_time,
+			       const char  *extension)
 {
 	char  *year;
 	char  *uri;
-	GFile *base;
 	char  *display_name;
 	GFile *catalog_file;
 
 	year = gth_datetime_strftime (date_time, "%Y");
 	uri = g_strconcat ("catalog:///", year, "/", NULL);
-	base = g_file_new_for_uri (uri);
 	display_name = gth_datetime_strftime (date_time, "%Y-%m-%d");
-	catalog_file = _g_file_new_for_display_name (uri, display_name, ".catalog");
+	catalog_file = _g_file_new_for_display_name (uri, display_name, extension);
 
 	g_free (display_name);
-	g_object_unref (base);
 	g_free (uri);
 	g_free (year);
 
@@ -1152,6 +1136,22 @@ gth_catalog_get_file_for_date (GthDateTime *date_time)
 }
 
 
+GFile *
+gth_catalog_get_file_for_tag (const char *tag,
+			      const char *extension)
+{
+	char  *uri;
+	GFile *catalog_file;
+
+	uri = g_strconcat ("catalog:///", _("Tags"), "/", NULL);
+	catalog_file = _g_file_new_for_display_name (uri, tag, extension);
+
+	g_free (uri);
+
+	return catalog_file;
+}
+
+
 GthCatalog *
 gth_catalog_load_from_file (GFile *file)
 {
diff --git a/extensions/catalogs/gth-catalog.h b/extensions/catalogs/gth-catalog.h
index ec51bc1..5e0c266 100644
--- a/extensions/catalogs/gth-catalog.h
+++ b/extensions/catalogs/gth-catalog.h
@@ -88,8 +88,6 @@ void          gth_catalog_set_order       (GthCatalog           *catalog,
 					   gboolean              inverse);
 const char *  gth_catalog_get_order       (GthCatalog           *catalog,
 					   gboolean             *inverse);
-void          gth_catalog_set_for_date    (GthCatalog           *catalog,
-					   GthDateTime          *date_time);
 void          gth_catalog_load_from_data  (GthCatalog           *catalog,
 					   const void           *buffer,
 					   gsize                 count,
@@ -129,7 +127,10 @@ void           gth_catalog_load_from_file_async       (GFile         *file,
 						       GCancellable  *cancellable,
 						       ReadyCallback  ready_func,
 						       gpointer       user_data);
-GFile *        gth_catalog_get_file_for_date          (GthDateTime   *date_time);
+GFile *        gth_catalog_get_file_for_date          (GthDateTime   *date_time,
+	      	      	       	       	       	       const char    *extension);
+GFile *        gth_catalog_get_file_for_tag           (const char    *tag,
+		      	      	      	      	       const char    *extension);
 GthCatalog *   gth_catalog_load_from_file             (GFile         *file);
 void           gth_catalog_save                       (GthCatalog    *catalog);
 
diff --git a/extensions/catalogs/gth-organize-task.c b/extensions/catalogs/gth-organize-task.c
index 4db06d1..53e6f2a 100644
--- a/extensions/catalogs/gth-organize-task.c
+++ b/extensions/catalogs/gth-organize-task.c
@@ -24,6 +24,7 @@
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <gthumb.h>
+#include <extensions/search/gth-search.h>
 #include "gth-catalog.h"
 #include "gth-organize-task.h"
 
@@ -56,6 +57,7 @@ struct _GthOrganizeTaskPrivate
 	GtkWidget      *file_list;
 	int             n_catalogs;
 	int             n_files;
+	GthTest        *filter;
 };
 
 
@@ -75,6 +77,7 @@ gth_organize_task_finalize (GObject *object)
 	g_object_unref (self->priv->builder);
 	g_hash_table_destroy (self->priv->catalogs);
 	g_object_unref (self->priv->icon_pixbuf);
+	g_object_unref (self->priv->filter);
 
 	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -132,8 +135,8 @@ save_catalogs (GthOrganizeTask *self)
 		}
 		while (gtk_tree_model_iter_next (GTK_TREE_MODEL (self->priv->results_liststore), &iter));
 	}
-	g_hash_table_foreach (self->priv->catalogs, save_catalog, NULL);
 
+	g_hash_table_foreach (self->priv->catalogs, save_catalog, NULL);
 	gth_task_completed (GTH_TASK (self), NULL);
 }
 
@@ -209,6 +212,193 @@ done_func (GError   *error,
 }
 
 
+static GthCatalog *
+add_catalog_for_date (GthOrganizeTask *self,
+		      const char      *catalog_key,
+		      GTimeVal        *timeval)
+{
+	GthCatalog  *catalog;
+	GthDateTime *date_time;
+	GFile       *catalog_file;
+	char        *catalog_name;
+	GtkTreeIter  iter;
+
+	catalog = g_hash_table_lookup (self->priv->catalogs, catalog_key);
+	if (catalog != NULL)
+		return catalog;
+
+	date_time = gth_datetime_new ();
+	gth_datetime_from_timeval (date_time, timeval);
+
+	catalog_file = NULL;
+
+	if (gth_main_extension_is_active ("search")) {
+		catalog_file = gth_catalog_get_file_for_date (date_time, ".search");
+		catalog = gth_catalog_load_from_file (catalog_file);
+	}
+
+	if (catalog == NULL) {
+		_g_object_unref (catalog_file);
+		catalog_file = gth_catalog_get_file_for_date (date_time, ".catalog");
+		catalog = gth_catalog_load_from_file (catalog_file);
+	}
+
+	if (catalog == NULL) {
+		if (gth_main_extension_is_active ("search")) {
+			GthTest *date_test;
+			GthTest *test_chain;
+
+			_g_object_unref (catalog_file);
+			catalog_file = gth_catalog_get_file_for_date (date_time, ".search");
+
+			catalog = (GthCatalog *) gth_search_new ();
+			gth_search_set_folder (GTH_SEARCH (catalog), self->priv->folder);
+			gth_search_set_recursive (GTH_SEARCH (catalog), self->priv->recursive);
+
+			date_test = gth_main_get_registered_object (GTH_TYPE_TEST, (self->priv->group_policy == GTH_GROUP_POLICY_MODIFIED_DATE) ? "file::mtime" : "Embedded::Photo::DateTimeOriginal");
+			gth_test_simple_set_data_as_date (GTH_TEST_SIMPLE (date_test), date_time->date);
+			g_object_set (GTH_TEST_SIMPLE (date_test), "op", GTH_TEST_OP_EQUAL, "negative", FALSE, NULL);
+			test_chain = gth_test_chain_new (GTH_MATCH_TYPE_ALL, date_test, NULL);
+			gth_search_set_test (GTH_SEARCH (catalog), GTH_TEST_CHAIN (test_chain));
+
+			g_object_unref (test_chain);
+			g_object_unref (date_test);
+		}
+		else
+			catalog = gth_catalog_new ();
+	}
+
+	gth_catalog_set_date (catalog, date_time);
+	gth_catalog_set_file (catalog, catalog_file);
+
+	g_hash_table_insert (self->priv->catalogs, g_strdup (catalog_key), catalog);
+	self->priv->n_catalogs++;
+
+	catalog_name = gth_datetime_strftime (date_time, "%x");
+
+	gtk_list_store_append (self->priv->results_liststore, &iter);
+	gtk_list_store_set (self->priv->results_liststore, &iter,
+			    KEY_COLUMN, catalog_key,
+			    NAME_COLUMN, catalog_name,
+			    CARDINALITY_COLUMN, 0,
+			    CREATE_CATALOG_COLUMN, TRUE,
+			    ICON_COLUMN, self->priv->icon_pixbuf,
+			    -1);
+
+	g_free (catalog_name);
+	g_object_unref (catalog_file);
+	gth_datetime_free (date_time);
+
+	return catalog;
+}
+
+
+static GthCatalog *
+add_catalog_for_tag (GthOrganizeTask *self,
+		     const char      *catalog_key,
+		     const char      *tag)
+{
+	GthCatalog  *catalog;
+	GFile       *catalog_file;
+	GtkTreeIter  iter;
+
+	catalog = g_hash_table_lookup (self->priv->catalogs, catalog_key);
+	if (catalog != NULL)
+		return catalog;
+
+	catalog_file = NULL;
+
+	if (gth_main_extension_is_active ("search")) {
+		catalog_file = gth_catalog_get_file_for_tag (tag, ".search");
+		catalog = gth_catalog_load_from_file (catalog_file);
+	}
+
+	if (catalog == NULL) {
+		_g_object_unref (catalog_file);
+		catalog_file = gth_catalog_get_file_for_tag (tag, ".catalog");
+		catalog = gth_catalog_load_from_file (catalog_file);
+	}
+
+	if (catalog == NULL) {
+		if (gth_main_extension_is_active ("search")) {
+			GthTest *tag_test;
+			GthTest *test_chain;
+
+			_g_object_unref (catalog_file);
+			catalog_file = gth_catalog_get_file_for_tag (tag, ".search");
+
+			catalog = (GthCatalog *) gth_search_new ();
+			gth_search_set_folder (GTH_SEARCH (catalog), self->priv->folder);
+			gth_search_set_recursive (GTH_SEARCH (catalog), self->priv->recursive);
+
+			tag_test = gth_main_get_registered_object (GTH_TYPE_TEST, (self->priv->group_policy == GTH_GROUP_POLICY_TAG) ? "comment::category" : "general::tags");
+			gth_test_category_set (GTH_TEST_CATEGORY (tag_test), GTH_TEST_OP_EQUAL, FALSE, tag);
+			test_chain = gth_test_chain_new (GTH_MATCH_TYPE_ALL, tag_test, NULL);
+			gth_search_set_test (GTH_SEARCH (catalog), GTH_TEST_CHAIN (test_chain));
+
+			g_object_unref (test_chain);
+			g_object_unref (tag_test);
+		}
+		else
+			catalog = gth_catalog_new ();
+	}
+	gth_catalog_set_file (catalog, catalog_file);
+
+	g_hash_table_insert (self->priv->catalogs, g_strdup (catalog_key), catalog);
+	self->priv->n_catalogs++;
+
+	gtk_list_store_append (self->priv->results_liststore, &iter);
+	gtk_list_store_set (self->priv->results_liststore, &iter,
+			    KEY_COLUMN, catalog_key,
+			    NAME_COLUMN, tag,
+			    CARDINALITY_COLUMN, 0,
+			    CREATE_CATALOG_COLUMN, TRUE,
+			    ICON_COLUMN, self->priv->icon_pixbuf,
+			    -1);
+
+	g_object_unref (catalog_file);
+
+	return catalog;
+}
+
+
+static void
+add_file_to_catalog (GthOrganizeTask *self,
+		     GthCatalog      *catalog,
+		     const char      *catalog_key,
+		     GthFileData     *file_data)
+{
+	GtkTreeIter iter;
+	int         n = 0;
+
+	if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->priv->results_liststore), &iter)) {
+		do {
+			char *k;
+
+			gtk_tree_model_get (GTK_TREE_MODEL (self->priv->results_liststore),
+					    &iter,
+					    KEY_COLUMN, &k,
+					    CARDINALITY_COLUMN, &n,
+					    -1);
+			if (g_strcmp0 (k, catalog_key) == 0) {
+				gtk_list_store_set (self->priv->results_liststore, &iter,
+						    CARDINALITY_COLUMN, n + 1,
+						    -1);
+				self->priv->n_files++;
+
+				g_free (k);
+				break;
+			}
+
+			g_free (k);
+		}
+		while (gtk_tree_model_iter_next (GTK_TREE_MODEL (self->priv->results_liststore), &iter));
+	}
+
+	gth_catalog_insert_file (catalog, file_data->file, -1);
+}
+
+
 static void
 for_each_file_func (GFile     *file,
 		    GFileInfo *info,
@@ -216,103 +406,67 @@ for_each_file_func (GFile     *file,
 {
 	GthOrganizeTask *self = user_data;
 	GthFileData     *file_data;
-	char            *key;
+	char            *catalog_key;
+	GObject         *metadata;
+	GthStringList   *categories;
 	GTimeVal         timeval;
 	GthCatalog      *catalog;
 
 	if (g_file_info_get_file_type (info) != G_FILE_TYPE_REGULAR)
 		return;
 
-	key = NULL;
 	file_data = gth_file_data_new (file, info);
+
+	if (! gth_test_match (self->priv->filter, file_data)) {
+		g_object_unref (file_data);
+		return;
+	}
+
+	catalog_key = NULL;
+
 	switch (self->priv->group_policy) {
 	case GTH_GROUP_POLICY_DIGITALIZED_DATE:
-		{
-			GObject *metadata;
-
-			metadata = g_file_info_get_attribute_object (info, "Embedded::Photo::DateTimeOriginal");
-			if (metadata != NULL) {
-				if (_g_time_val_from_exif_date (gth_metadata_get_raw (GTH_METADATA (metadata)), &timeval))
-					key = _g_time_val_strftime (&timeval, KEY_FORMAT);
+		metadata = g_file_info_get_attribute_object (info, "Embedded::Photo::DateTimeOriginal");
+		if (metadata != NULL) {
+			if (_g_time_val_from_exif_date (gth_metadata_get_raw (GTH_METADATA (metadata)), &timeval)) {
+				catalog_key = _g_time_val_strftime (&timeval, KEY_FORMAT);
+				catalog = add_catalog_for_date (self, catalog_key, &timeval);
+				add_file_to_catalog (self, catalog, catalog_key, file_data);
 			}
 		}
 		break;
+
 	case GTH_GROUP_POLICY_MODIFIED_DATE:
 		timeval = *gth_file_data_get_modification_time (file_data);
-		key = _g_time_val_strftime (&timeval, KEY_FORMAT);
+		catalog_key = _g_time_val_strftime (&timeval, KEY_FORMAT);
+		catalog = add_catalog_for_date (self, catalog_key, &timeval);
+		add_file_to_catalog (self, catalog, catalog_key, file_data);
 		break;
-	}
 
-	if (key == NULL)
-		return;
-
-	catalog = g_hash_table_lookup (self->priv->catalogs, key);
-	if (catalog == NULL) {
-		GthDateTime *date_time;
-		GFile       *catalog_file;
-		char        *name;
-		GtkTreeIter  iter;
-
-		date_time = gth_datetime_new ();
-		gth_datetime_from_timeval (date_time, &timeval);
-
-		catalog_file = gth_catalog_get_file_for_date (date_time);
-		catalog = gth_catalog_load_from_file (catalog_file);
-		if (catalog == NULL)
-			catalog = gth_catalog_new ();
-		gth_catalog_set_for_date (catalog, date_time);
-
-		g_hash_table_insert (self->priv->catalogs, g_strdup (key), catalog);
-
-		name = gth_datetime_strftime (date_time, "%x");
-		gtk_list_store_append (self->priv->results_liststore, &iter);
-		gtk_list_store_set (self->priv->results_liststore, &iter,
-				    KEY_COLUMN, key,
-				    NAME_COLUMN, name,
-				    CARDINALITY_COLUMN, 0,
-				    CREATE_CATALOG_COLUMN, TRUE,
-				    ICON_COLUMN, self->priv->icon_pixbuf,
-				    -1);
-		self->priv->n_catalogs++;
-
-		g_free (name);
-		g_object_unref (catalog_file);
-		gth_datetime_free (date_time);
-	}
-
-	if (catalog != NULL) {
-		GtkTreeIter iter;
-		int         n = 0;
-
-		if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->priv->results_liststore), &iter)) {
-			do {
-				char *k;
-
-				gtk_tree_model_get (GTK_TREE_MODEL (self->priv->results_liststore),
-						    &iter,
-						    KEY_COLUMN, &k,
-						    CARDINALITY_COLUMN, &n,
-						    -1);
-				if (g_strcmp0 (k, key) == 0) {
-					gtk_list_store_set (self->priv->results_liststore, &iter,
-							    CARDINALITY_COLUMN, n + 1,
-							    -1);
-					self->priv->n_files++;
-
-					g_free (k);
-					break;
-				}
-
-				g_free (k);
+	case GTH_GROUP_POLICY_TAG:
+	case GTH_GROUP_POLICY_TAG_EMBEDDED:
+		if (self->priv->group_policy == GTH_GROUP_POLICY_TAG)
+			categories = (GthStringList *) g_file_info_get_attribute_object (file_data->info, "comment::categories");
+		else
+			categories = (GthStringList *) g_file_info_get_attribute_object (file_data->info, "general::tags");
+		if (categories != NULL) {
+			GList *list;
+			GList *scan;
+
+			list = gth_string_list_get_list (categories);
+			for (scan = list; scan; scan = scan->next) {
+				char *tag = (char *) scan->data;
+
+				catalog_key = g_strdup (tag);
+				catalog = add_catalog_for_tag (self, catalog_key, tag);
+				add_file_to_catalog (self, catalog, catalog_key, file_data);
 			}
-			while (gtk_tree_model_iter_next (GTK_TREE_MODEL (self->priv->results_liststore), &iter));
 		}
-
-		gth_catalog_insert_file (catalog, file_data->file, -1);
+		break;
 	}
 
+	g_free (catalog_key);
 	g_object_unref (file_data);
-	g_free (key);
 }
 
 
@@ -349,15 +503,22 @@ gth_organize_task_exec (GthTask *base)
 	self->priv->n_catalogs = 0;
 	self->priv->n_files = 0;
 	gtk_list_store_clear (self->priv->results_liststore);
+
 	switch (self->priv->group_policy) {
 	case GTH_GROUP_POLICY_DIGITALIZED_DATE:
 		attributes = "standard::name,standard::type,time::modified,time::modified-usec,Embedded::Photo::DateTimeOriginal";
 		break;
 	case GTH_GROUP_POLICY_MODIFIED_DATE:
-	default:
 		attributes = "standard::name,standard::type,time::modified,time::modified-usec";
 		break;
+	case GTH_GROUP_POLICY_TAG:
+		attributes = "standard::name,standard::type,time::modified,time::modified-usec,comment::categories";
+		break;
+	case GTH_GROUP_POLICY_TAG_EMBEDDED:
+		attributes = "standard::name,standard::type,time::modified,time::modified-usec,general::tags";
+		break;
 	}
+
 	g_directory_foreach_child (self->priv->folder,
 				   self->priv->recursive,
 				   TRUE,
@@ -382,7 +543,6 @@ gth_organize_task_exec (GthTask *base)
 static void
 gth_organize_task_cancelled (GthTask *base)
 {
-	/* FIXME */
 }
 
 
@@ -584,6 +744,7 @@ gth_organize_task_init (GthOrganizeTask *self)
 	self->priv->builder = _gtk_builder_new_from_file ("organize-files-task.ui", "catalogs");
 	self->priv->results_liststore = (GtkListStore *) gtk_builder_get_object (self->priv->builder, "results_liststore");
 	self->priv->catalogs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+	self->priv->filter = gth_main_get_general_filter ();
 
 	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self->priv->results_liststore), KEY_COLUMN, GTK_SORT_ASCENDING);
 	g_object_set (GET_WIDGET ("catalog_name_cellrenderertext"), "editable", TRUE, NULL);
diff --git a/extensions/catalogs/gth-organize-task.h b/extensions/catalogs/gth-organize-task.h
index 6b88f7e..48271f2 100644
--- a/extensions/catalogs/gth-organize-task.h
+++ b/extensions/catalogs/gth-organize-task.h
@@ -28,7 +28,9 @@
 
 typedef enum {
 	GTH_GROUP_POLICY_DIGITALIZED_DATE,
-	GTH_GROUP_POLICY_MODIFIED_DATE
+	GTH_GROUP_POLICY_MODIFIED_DATE,
+	GTH_GROUP_POLICY_TAG,
+	GTH_GROUP_POLICY_TAG_EMBEDDED
 } GthGroupPolicy;
 
 #define GTH_TYPE_ORGANIZE_TASK         (gth_organize_task_get_type ())
diff --git a/extensions/importer/gth-import-task.c b/extensions/importer/gth-import-task.c
index 944a0e4..eca93fd 100644
--- a/extensions/importer/gth-import-task.c
+++ b/extensions/importer/gth-import-task.c
@@ -158,11 +158,12 @@ catalog_imported_file (GthImportTask *self)
 		date_time = gth_datetime_new ();
 		gth_datetime_from_timeval (date_time, &timeval);
 
-		catalog_file = gth_catalog_get_file_for_date (date_time);
+		catalog_file = gth_catalog_get_file_for_date (date_time, ".catalog");
 		catalog = gth_catalog_load_from_file (catalog_file);
 		if (catalog == NULL)
 			catalog = gth_catalog_new ();
-		gth_catalog_set_for_date (catalog, date_time);
+		gth_catalog_set_date (catalog, date_time);
+		gth_catalog_set_file (catalog, catalog_file);
 
 		g_hash_table_insert (self->priv->catalogs, g_strdup (key), catalog);
 
diff --git a/gthumb/gth-info-bar.c b/gthumb/gth-info-bar.c
index f67d0ae..a11e5f0 100644
--- a/gthumb/gth-info-bar.c
+++ b/gthumb/gth-info-bar.c
@@ -151,6 +151,13 @@ gth_info_bar_new (const char *icon_stock_id,
 }
 
 
+GtkWidget *
+gth_info_bar_get_primary_label (GthInfoBar *dialog)
+{
+	return dialog->priv->primary_text_label;
+}
+
+
 void
 gth_info_bar_set_icon (GthInfoBar *self,
 		       const char *icon_stock_id)
diff --git a/gthumb/gth-info-bar.h b/gthumb/gth-info-bar.h
index f578b7f..5a9ea31 100644
--- a/gthumb/gth-info-bar.h
+++ b/gthumb/gth-info-bar.h
@@ -54,6 +54,7 @@ GType         gth_info_bar_get_type           (void) G_GNUC_CONST;
 GtkWidget *   gth_info_bar_new                (const char *icon_stock_id,
 					       const char *primary_text,
 					       const char *secondary_text);
+GtkWidget *   gth_info_bar_get_primary_label  (GthInfoBar *dialog);
 void          gth_info_bar_set_icon           (GthInfoBar *dialog,
 					       const char *icon_stock_id);
 void          gth_info_bar_set_gicon          (GthInfoBar *dialog,
diff --git a/gthumb/gth-test-category.c b/gthumb/gth-test-category.c
index 195f8a1..740cdd2 100644
--- a/gthumb/gth-test-category.c
+++ b/gthumb/gth-test-category.c
@@ -467,3 +467,15 @@ gth_test_category_get_type (void)
 
         return type;
 }
+
+
+void
+gth_test_category_set (GthTestCategory *self,
+		       GthTestOp        op,
+		       gboolean         negative,
+		       const char      *value)
+{
+	self->priv->op = op;
+	self->priv->negative = negative;
+	gth_test_category_set_category (self, value);
+}
diff --git a/gthumb/gth-test-category.h b/gthumb/gth-test-category.h
index 1c6a22c..8897718 100644
--- a/gthumb/gth-test-category.h
+++ b/gthumb/gth-test-category.h
@@ -49,5 +49,9 @@ struct _GthTestCategoryClass
 };
 
 GType  gth_test_category_get_type  (void) G_GNUC_CONST;
+void   gth_test_category_set       (GthTestCategory *self,
+				    GthTestOp        op,
+				    gboolean         negative,
+				    const char      *value);
 
 #endif /* GTH_TEST_CATEGORY_H */
diff --git a/gthumb/gth-test-simple.c b/gthumb/gth-test-simple.c
index 101460c..9e6df3a 100644
--- a/gthumb/gth-test-simple.c
+++ b/gthumb/gth-test-simple.c
@@ -145,50 +145,6 @@ _gth_test_simple_free_data (GthTestSimple *test)
 
 
 static void
-_gth_test_simple_set_data_as_string (GthTestSimple *test,
-			             const char    *s)
-{
-	_gth_test_simple_free_data (test);
-	test->priv->data_type = GTH_TEST_DATA_TYPE_STRING;
-	test->priv->data.s = g_strdup (s);
-}
-
-
-static void
-_gth_test_simple_set_data_as_int (GthTestSimple *test,
-			          guint64        i)
-{
-	_gth_test_simple_free_data (test);
-	test->priv->data_type = GTH_TEST_DATA_TYPE_INT;
-	test->priv->data.i = i;
-}
-
-
-static void
-_gth_test_simple_set_data_as_size (GthTestSimple *test,
-			           guint64        i)
-{
-	_gth_test_simple_free_data (test);
-	test->priv->data_type = GTH_TEST_DATA_TYPE_SIZE;
-	test->priv->data.i = i;
-}
-
-
-static void
-_gth_test_simple_set_data_as_date (GthTestSimple *test,
-				   GDate         *date)
-{
-	_gth_test_simple_free_data (test);
-	test->priv->data_type = GTH_TEST_DATA_TYPE_DATE;
-	test->priv->data.date = g_date_new ();
-	if (date != NULL)
-		*test->priv->data.date = *date;
-	else
-		g_date_clear (test->priv->data.date, 1);
-}
-
-
-static void
 gth_test_simple_finalize (GObject *object)
 {
 	GthTestSimple *test;
@@ -796,15 +752,15 @@ gth_test_simple_real_load_from_element (DomDomizable *base,
 
 	switch (self->priv->data_type) {
 	case GTH_TEST_DATA_TYPE_INT:
-		_gth_test_simple_set_data_as_int (self, atol (value));
+		gth_test_simple_set_data_as_int (self, atol (value));
 		break;
 
 	case GTH_TEST_DATA_TYPE_SIZE:
-		_gth_test_simple_set_data_as_size (self, atol (value));
+		gth_test_simple_set_data_as_size (self, atol (value));
 		break;
 
 	case GTH_TEST_DATA_TYPE_STRING:
-		_gth_test_simple_set_data_as_string (self, value);
+		gth_test_simple_set_data_as_string (self, value);
 		break;
 
 	case GTH_TEST_DATA_TYPE_DATE:
@@ -813,7 +769,7 @@ gth_test_simple_real_load_from_element (DomDomizable *base,
 
 			dt = gth_datetime_new ();
 			gth_datetime_from_exif_date (dt, value);
-			_gth_test_simple_set_data_as_date (self, dt->date);
+			gth_test_simple_set_data_as_date (self, dt->date);
 
 			gth_datetime_free (dt);
 		}
@@ -834,7 +790,7 @@ update_from_control_for_integer (GthTestSimple  *self,
 	op_data = int_op_data[gtk_combo_box_get_active (GTK_COMBO_BOX (self->priv->text_op_combo_box))];
 	self->priv->op = op_data.op;
 	self->priv->negative = op_data.negative;
-	_gth_test_simple_set_data_as_int (self, atol (gtk_entry_get_text (GTK_ENTRY (self->priv->text_entry))));
+	gth_test_simple_set_data_as_int (self, atol (gtk_entry_get_text (GTK_ENTRY (self->priv->text_entry))));
 
 	if (self->priv->data.i == 0) {
 		if (error != NULL)
@@ -860,7 +816,7 @@ update_from_control_for_size (GthTestSimple  *self,
 
 	value = atol (gtk_entry_get_text (GTK_ENTRY (self->priv->text_entry)));
 	size = value * size_data[gtk_combo_box_get_active (GTK_COMBO_BOX (self->priv->size_combo_box))].size;
-	_gth_test_simple_set_data_as_size (self, size);
+	gth_test_simple_set_data_as_size (self, size);
 
 	if ((self->priv->data.i == 0) && (self->priv->op == GTH_TEST_OP_LOWER)) {
 		if (error != NULL)
@@ -881,7 +837,7 @@ update_from_control_for_string (GthTestSimple  *self,
 	op_data = text_op_data[gtk_combo_box_get_active (GTK_COMBO_BOX (self->priv->text_op_combo_box))];
 	self->priv->op = op_data.op;
 	self->priv->negative = op_data.negative;
-	_gth_test_simple_set_data_as_string (self, gtk_entry_get_text (GTK_ENTRY (self->priv->text_entry)));
+	gth_test_simple_set_data_as_string (self, gtk_entry_get_text (GTK_ENTRY (self->priv->text_entry)));
 
 	if (g_strcmp0 (self->priv->data.s, "") == 0) {
 		if (error != NULL)
@@ -906,7 +862,7 @@ update_from_control_for_date (GthTestSimple  *self,
 
 	dt = gth_datetime_new ();
 	gth_time_selector_get_value (GTH_TIME_SELECTOR (self->priv->time_selector), dt);
-	_gth_test_simple_set_data_as_date (self, dt->date);
+	gth_test_simple_set_data_as_date (self, dt->date);
 	gth_datetime_free (dt);
 
 	if (! g_date_valid (self->priv->data.date)) {
@@ -973,19 +929,19 @@ gth_test_simple_real_duplicate (GthDuplicable *duplicable)
 		break;
 
 	case GTH_TEST_DATA_TYPE_INT:
-		_gth_test_simple_set_data_as_int (new_test, test->priv->data.i);
+		gth_test_simple_set_data_as_int (new_test, test->priv->data.i);
 		break;
 
 	case GTH_TEST_DATA_TYPE_SIZE:
-		_gth_test_simple_set_data_as_size (new_test, test->priv->data.i);
+		gth_test_simple_set_data_as_size (new_test, test->priv->data.i);
 		break;
 
 	case GTH_TEST_DATA_TYPE_STRING:
-		_gth_test_simple_set_data_as_string (new_test, test->priv->data.s);
+		gth_test_simple_set_data_as_string (new_test, test->priv->data.s);
 		break;
 
 	case GTH_TEST_DATA_TYPE_DATE:
-		_gth_test_simple_set_data_as_date (new_test, test->priv->data.date);
+		gth_test_simple_set_data_as_date (new_test, test->priv->data.date);
 		break;
 	}
 
@@ -1227,3 +1183,47 @@ gth_test_simple_get_type (void)
 
         return type;
 }
+
+
+void
+gth_test_simple_set_data_as_string (GthTestSimple *test,
+			            const char    *s)
+{
+	_gth_test_simple_free_data (test);
+	test->priv->data_type = GTH_TEST_DATA_TYPE_STRING;
+	test->priv->data.s = g_strdup (s);
+}
+
+
+void
+gth_test_simple_set_data_as_int (GthTestSimple *test,
+			         guint64        i)
+{
+	_gth_test_simple_free_data (test);
+	test->priv->data_type = GTH_TEST_DATA_TYPE_INT;
+	test->priv->data.i = i;
+}
+
+
+void
+gth_test_simple_set_data_as_size (GthTestSimple *test,
+			          guint64        i)
+{
+	_gth_test_simple_free_data (test);
+	test->priv->data_type = GTH_TEST_DATA_TYPE_SIZE;
+	test->priv->data.i = i;
+}
+
+
+void
+gth_test_simple_set_data_as_date (GthTestSimple *test,
+				  GDate         *date)
+{
+	_gth_test_simple_free_data (test);
+	test->priv->data_type = GTH_TEST_DATA_TYPE_DATE;
+	test->priv->data.date = g_date_new ();
+	if (date != NULL)
+		*test->priv->data.date = *date;
+	else
+		g_date_clear (test->priv->data.date, 1);
+}
diff --git a/gthumb/gth-test-simple.h b/gthumb/gth-test-simple.h
index 152192d..7ec222c 100644
--- a/gthumb/gth-test-simple.h
+++ b/gthumb/gth-test-simple.h
@@ -65,7 +65,15 @@ struct _GthTestSimpleClass
 	GthTestClass __parent_class;
 };
 
-GType  gth_test_simple_get_type  (void) G_GNUC_CONST;
+GType  gth_test_simple_get_type           (void) G_GNUC_CONST;
+void   gth_test_simple_set_data_as_string (GthTestSimple *test,
+					   const char    *s);
+void   gth_test_simple_set_data_as_int    (GthTestSimple *test,
+					   guint64        i);
+void   gth_test_simple_set_data_as_size   (GthTestSimple *test,
+					   guint64        i);
+void   gth_test_simple_set_data_as_date   (GthTestSimple *test,
+				   	   GDate         *date);
 
 G_END_DECLS
 
diff --git a/gthumb/gth-time-selector.c b/gthumb/gth-time-selector.c
index f9751c1..d99b71d 100644
--- a/gthumb/gth-time-selector.c
+++ b/gthumb/gth-time-selector.c
@@ -26,6 +26,7 @@
 #include <glib/gi18n.h>
 #include <gdk/gdkkeysyms.h>
 #include <gtk/gtk.h>
+#include "glib-utils.h"
 #include "gth-time-selector.h"
 
 
@@ -217,9 +218,11 @@ update_view_from_data (GthTimeSelector *self)
 	}
 
 	if (g_date_valid (self->priv->date_time->date)) {
-		char *text;
+		struct tm  tm;
+		char      *text;
 
-		text = gth_datetime_strftime (self->priv->date_time, "%x");
+		g_date_to_struct_tm (self->priv->date_time->date, &tm);
+		text = struct_tm_strftime (&tm, "%x");
 		gtk_entry_set_text (GTK_ENTRY (self->priv->date_entry), text);
 
 		if (gth_datetime_valid (self->priv->date_time)) {
diff --git a/gthumb/gth-time.c b/gthumb/gth-time.c
index bc09221..ed2c70e 100644
--- a/gthumb/gth-time.c
+++ b/gthumb/gth-time.c
@@ -285,14 +285,19 @@ gth_datetime_to_exif_date (GthDateTime *dt)
 }
 
 
-void
+gboolean
 gth_datetime_to_struct_tm (GthDateTime *dt,
 		           struct tm   *tm)
 {
+	if (! gth_datetime_valid (dt))
+		return FALSE;
+
 	g_date_to_struct_tm (dt->date, tm);
 	tm->tm_hour = dt->time->hour;
 	tm->tm_min = dt->time->min;
 	tm->tm_sec = dt->time->sec;
+
+	return TRUE;
 }
 
 
@@ -318,6 +323,8 @@ gth_datetime_strftime (GthDateTime *dt,
 {
 	struct  tm tm;
 
-	gth_datetime_to_struct_tm (dt, &tm);
-	return struct_tm_strftime (&tm, format);
+	if (gth_datetime_to_struct_tm (dt, &tm))
+		return struct_tm_strftime (&tm, format);
+	else
+		return g_strdup ("");
 }
diff --git a/gthumb/gth-time.h b/gthumb/gth-time.h
index 3bc276a..b9ff775 100644
--- a/gthumb/gth-time.h
+++ b/gthumb/gth-time.h
@@ -64,7 +64,7 @@ void          gth_datetime_from_struct_tm  (GthDateTime *dt,
 void          gth_datetime_from_gdate      (GthDateTime *dt,
 			 	 	    GDate       *date);
 char *        gth_datetime_to_exif_date    (GthDateTime *dt);
-void          gth_datetime_to_struct_tm    (GthDateTime *dt,
+gboolean      gth_datetime_to_struct_tm    (GthDateTime *dt,
 					    struct tm   *tm);
 gboolean      gth_datetime_to_timeval      (GthDateTime *dt,
 					    GTimeVal    *tv);



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