[gthumb/ext: 8/15] started work on the organize task
- From: Paolo Bacchilega <paobac src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gthumb/ext: 8/15] started work on the organize task
- Date: Tue, 15 Dec 2009 19:40:09 +0000 (UTC)
commit 189074ff5702f3681f98f457b0ad94e6e680c891
Author: Paolo Bacchilega <paobac src gnome org>
Date: Sun Dec 13 22:37:50 2009 +0100
started work on the organize task
extensions/catalogs/Makefile.am | 4 +
extensions/catalogs/callbacks.c | 26 ++-
extensions/catalogs/data/ui/Makefile.am | 5 +-
extensions/catalogs/data/ui/organize-files-task.ui | 248 ++++++++++++
extensions/catalogs/data/ui/organize-files.ui | 275 +++++++++++++
extensions/catalogs/dlg-organize-files.c | 116 ++++++
extensions/catalogs/dlg-organize-files.h | 31 ++
extensions/catalogs/gth-catalog.c | 8 +
extensions/catalogs/gth-catalog.h | 2 +
extensions/catalogs/gth-organize-task.c | 426 ++++++++++++++++++++
extensions/catalogs/gth-organize-task.h | 67 +++
gthumb/gio-utils.c | 153 ++++++--
gthumb/glib-utils.c | 36 ++-
gthumb/glib-utils.h | 3 +
gthumb/gth-embedded-dialog.c | 1 +
gthumb/gth-main.c | 2 +-
16 files changed, 1364 insertions(+), 39 deletions(-)
---
diff --git a/extensions/catalogs/Makefile.am b/extensions/catalogs/Makefile.am
index 46219ad..aea69f3 100644
--- a/extensions/catalogs/Makefile.am
+++ b/extensions/catalogs/Makefile.am
@@ -12,10 +12,14 @@ libcatalogs_la_SOURCES = \
dlg-add-to-catalog.h \
dlg-catalog-properties.c \
dlg-catalog-properties.h \
+ dlg-organize-files.c \
+ dlg-organize-files.h \
gth-catalog.c \
gth-catalog.h \
gth-file-source-catalogs.c \
gth-file-source-catalogs.h \
+ gth-organize-task.c \
+ gth-organize-task.h \
main.c
libcatalogs_la_CFLAGS = $(GTHUMB_CFLAGS) $(WARNINGS) -I$(top_srcdir) -I$(top_builddir)/gthumb
diff --git a/extensions/catalogs/callbacks.c b/extensions/catalogs/callbacks.c
index a6f6de6..5702f30 100644
--- a/extensions/catalogs/callbacks.c
+++ b/extensions/catalogs/callbacks.c
@@ -27,6 +27,7 @@
#include <gthumb.h>
#include <gth-catalog.h>
#include "dlg-catalog-properties.h"
+#include "dlg-organize-files.h"
#include "gth-file-source-catalogs.h"
#include "actions.h"
@@ -153,6 +154,7 @@ typedef struct {
gboolean catalog_menu_loaded;
guint monitor_events;
GtkWidget *properties_button;
+ GtkWidget *organize_button;
} BrowserData;
@@ -578,6 +580,14 @@ properties_button_clicked_cb (GtkButton *button,
}
+static void
+organize_button_clicked_cb (GtkButton *button,
+ GthBrowser *browser)
+{
+ dlg_organize_files (browser, gth_browser_get_location (browser));
+}
+
+
void
catalogs__gth_browser_load_location_after_cb (GthBrowser *browser,
GthFileData *location_data,
@@ -655,6 +665,18 @@ catalogs__gth_browser_update_extra_widget_cb (GthBrowser *browser)
browser);
}
}
- else if (GTH_IS_FILE_SOURCE_VFS (gth_browser_get_location_source (browser)))
- gedit_message_area_add_button (GEDIT_MESSAGE_AREA (gth_browser_get_list_extra_widget (browser)), _("Organize"), _RESPONSE_ORGANIZE);
+ else if (GTH_IS_FILE_SOURCE_VFS (gth_browser_get_location_source (browser))) {
+ if (data->organize_button == NULL) {
+ data->organize_button = gtk_button_new ();
+ gtk_container_add (GTK_CONTAINER (data->organize_button), gtk_label_new (_("Organize")));
+ g_object_add_weak_pointer (G_OBJECT (data->organize_button), (gpointer *)&data->organize_button);
+ gtk_button_set_relief (GTK_BUTTON (data->organize_button), GTK_RELIEF_NONE);
+ gtk_widget_show_all (data->organize_button);
+ gedit_message_area_add_action_widget (GEDIT_MESSAGE_AREA (gth_browser_get_list_extra_widget (browser)), data->organize_button, _RESPONSE_ORGANIZE);
+ g_signal_connect (data->organize_button,
+ "clicked",
+ G_CALLBACK (organize_button_clicked_cb),
+ browser);
+ }
+ }
}
diff --git a/extensions/catalogs/data/ui/Makefile.am b/extensions/catalogs/data/ui/Makefile.am
index 4b3c318..75fa8a5 100644
--- a/extensions/catalogs/data/ui/Makefile.am
+++ b/extensions/catalogs/data/ui/Makefile.am
@@ -1,5 +1,8 @@
uidir = $(datadir)/gthumb-2.0/ui
-ui_DATA = add-to-catalog.ui catalog-properties.ui
+ui_DATA = \
+ add-to-catalog.ui \
+ catalog-properties.ui \
+ organize-files.ui
EXTRA_DIST = $(ui_DATA)
-include $(top_srcdir)/git.mk
diff --git a/extensions/catalogs/data/ui/organize-files-task.ui b/extensions/catalogs/data/ui/organize-files-task.ui
new file mode 100644
index 0000000..e961f5a
--- /dev/null
+++ b/extensions/catalogs/data/ui/organize-files-task.ui
@@ -0,0 +1,248 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkListStore" id="results_liststore">
+ <columns>
+ <!-- column-name catalog -->
+ <column type="gchararray"/>
+ <!-- column-name cardinality -->
+ <column type="gint"/>
+ <!-- column-name create -->
+ <column type="gboolean"/>
+ </columns>
+ </object>
+ <object class="GtkDialog" id="organize_files_dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Organize Files</property>
+ <property name="type_hint">normal</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox3">
+ <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="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ <property name="top_padding">1</property>
+ <child>
+ <object class="GtkImage" id="icon_image">
+ <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>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Organizing files</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ <attribute name="size" value="11000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="progress_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Searching in...</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Organization:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="n_catalogs_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox4">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="width_request">300</property>
+ <property name="height_request">150</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="treeview1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">results_liststore</property>
+ <property name="headers_clickable">False</property>
+ <property name="search_column">0</property>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+ <property name="title">Date</property>
+ <property name="expand">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext1"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn2">
+ <property name="title">Files</property>
+ <property name="expand">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext2"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn3">
+ <property name="title">Create Catalog</property>
+ <child>
+ <object class="GtkCellRendererToggle" id="cellrenderertoggle2"/>
+ <attributes>
+ <attribute name="active">2</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area3">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="cancel_button">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="0">cancel_button</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/extensions/catalogs/data/ui/organize-files.ui b/extensions/catalogs/data/ui/organize-files.ui
new file mode 100644
index 0000000..8c34484
--- /dev/null
+++ b/extensions/catalogs/data/ui/organize-files.ui
@@ -0,0 +1,275 @@
+<?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="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">
+ <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>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <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">
+ <property name="visible">True</property>
+ <property name="bottom_padding">6</property>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">A catalog will be created for each group.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox6">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Group by:</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="group_by_combobox">
+ <property name="visible">True</property>
+ <property name="model">group_by_liststore</property>
+ <property name="active">0</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext1"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="include_subfolders_checkbutton">
+ <property name="label" translatable="yes">_Include sub-folders</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="create_singletons_checkbutton">
+ <property name="label" translatable="yes">Do not create catalogs with a single file</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="use_singletons_catalog_checkbutton">
+ <property name="label" translatable="yes">Put single files in the catalog:</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="inconsistent">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="single_catalog_entry">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ <property name="text" translatable="yes">Singles</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="help_button">
+ <property name="label">gtk-help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel_button">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="start_button">
+ <property name="label">gtk-execute</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="0">help_button</action-widget>
+ <action-widget response="0">cancel_button</action-widget>
+ <action-widget response="0">start_button</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkListStore" id="group_by_liststore">
+ <columns>
+ <!-- column-name type -->
+ <column type="gint"/>
+ <!-- column-name name -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0">0</col>
+ <col id="1" translatable="yes">date photo was taken</col>
+ </row>
+ <row>
+ <col id="0">1</col>
+ <col id="1" translatable="yes">file modified date</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-execute</property>
+ </object>
+</interface>
diff --git a/extensions/catalogs/dlg-organize-files.c b/extensions/catalogs/dlg-organize-files.c
new file mode 100644
index 0000000..8d7b712
--- /dev/null
+++ b/extensions/catalogs/dlg-organize-files.c
@@ -0,0 +1,116 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2009 The 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 <gtk/gtk.h>
+#include "dlg-organize-files.h"
+#include "gth-organize-task.h"
+
+
+#define GET_WIDGET(name) _gtk_builder_get_widget (data->builder, (name))
+
+
+typedef struct {
+ GthBrowser *browser;
+ GtkBuilder *builder;
+ GtkWidget *dialog;
+ GFile *folder;
+} DialogData;
+
+
+static void
+destroy_cb (GtkWidget *widget,
+ DialogData *data)
+{
+ g_object_ref (data->folder);
+ g_object_unref (data->builder);
+ g_free (data);
+}
+
+
+static void
+start_button_clicked_cb (GtkWidget *widget,
+ DialogData *data)
+{
+ GthTask *task;
+
+ task = gth_organize_task_new (data->browser, data->folder, gtk_combo_box_get_active (GTK_COMBO_BOX (GET_WIDGET ("group_by_combobox"))));
+ gth_organize_task_set_recursive (GTH_ORGANIZE_TASK (task), gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("include_subfolders_checkbutton"))));
+ gth_organize_task_set_create_singletons (GTH_ORGANIZE_TASK (task), gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("create_singletons_checkbutton"))));
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("use_singletons_catalog_checkbutton"))))
+ gth_organize_task_set_singletons_catalog (GTH_ORGANIZE_TASK (task), gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("single_catalog_entry"))));
+ gth_browser_exec_task (data->browser, task, FALSE);
+
+ gtk_widget_destroy (data->dialog);
+ g_object_unref (task);
+}
+
+
+static void
+help_button_clicked_cb (GtkWidget *widget,
+ DialogData *data)
+{
+ show_help_dialog (GTK_WINDOW (data->dialog), "organize-files");
+}
+
+
+void
+dlg_organize_files (GthBrowser *browser,
+ GFile *folder)
+{
+ DialogData *data;
+
+ g_return_if_fail (folder != NULL);
+
+ data = g_new0 (DialogData, 1);
+ data->browser = browser;
+ data->folder = g_file_dup (folder);
+ data->builder = _gtk_builder_new_from_file ("organize-files.ui", "catalogs");
+ data->dialog = GET_WIDGET ("organize_files_dialog");
+
+ /*gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (GET_WIDGET ("start_at_filechooserbutton")), data->folder, NULL); FIXME */
+
+ /* Set the signals handlers. */
+
+ g_signal_connect (G_OBJECT (data->dialog),
+ "destroy",
+ G_CALLBACK (destroy_cb),
+ data);
+ g_signal_connect_swapped (G_OBJECT (GET_WIDGET ("cancel_button")),
+ "clicked",
+ G_CALLBACK (gtk_widget_destroy),
+ data->dialog);
+ g_signal_connect (G_OBJECT (GET_WIDGET ("help_button")),
+ "clicked",
+ G_CALLBACK (help_button_clicked_cb),
+ data);
+ g_signal_connect (G_OBJECT (GET_WIDGET ("start_button")),
+ "clicked",
+ G_CALLBACK (start_button_clicked_cb),
+ data);
+
+ /* run dialog. */
+
+ gtk_window_set_transient_for (GTK_WINDOW (data->dialog), GTK_WINDOW (browser));
+ gtk_window_set_modal (GTK_WINDOW (data->dialog), TRUE);
+ gtk_widget_show (data->dialog);
+}
diff --git a/extensions/catalogs/dlg-organize-files.h b/extensions/catalogs/dlg-organize-files.h
new file mode 100644
index 0000000..fba64c9
--- /dev/null
+++ b/extensions/catalogs/dlg-organize-files.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2009 The 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 DLG_ORGANIZE_FILES_H
+#define DLG_ORGANIZE_FILES_H
+
+#include <gthumb.h>
+
+void dlg_organize_files (GthBrowser *browser,
+ GFile *folder);
+
+#endif /* DLG_ORGANIZE_FILES_H */
diff --git a/extensions/catalogs/gth-catalog.c b/extensions/catalogs/gth-catalog.c
index b6c84f8..91bf1c3 100644
--- a/extensions/catalogs/gth-catalog.c
+++ b/extensions/catalogs/gth-catalog.c
@@ -392,6 +392,14 @@ gth_catalog_insert_file (GthCatalog *catalog,
}
+void
+gth_catalog_append_file (GthCatalog *catalog,
+ GFile *file)
+{
+ catalog->priv->file_list = g_list_append (catalog->priv->file_list, g_file_dup (file));
+}
+
+
int
gth_catalog_remove_file (GthCatalog *catalog,
GFile *file)
diff --git a/extensions/catalogs/gth-catalog.h b/extensions/catalogs/gth-catalog.h
index a60bd94..170985c 100644
--- a/extensions/catalogs/gth-catalog.h
+++ b/extensions/catalogs/gth-catalog.h
@@ -93,6 +93,8 @@ GList * gth_catalog_get_file_list (GthCatalog *catalog);
gboolean gth_catalog_insert_file (GthCatalog *catalog,
int pos,
GFile *file);
+void gth_catalog_append_file (GthCatalog *catalog,
+ GFile *file);
int gth_catalog_remove_file (GthCatalog *catalog,
GFile *file);
void gth_catalog_set_date (GthCatalog *catalog,
diff --git a/extensions/catalogs/gth-organize-task.c b/extensions/catalogs/gth-organize-task.c
new file mode 100644
index 0000000..e15afaf
--- /dev/null
+++ b/extensions/catalogs/gth-organize-task.c
@@ -0,0 +1,426 @@
+/* -*- 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 <glib.h>
+#include <glib/gi18n.h>
+#include <gthumb.h>
+#include "gth-catalog.h"
+#include "gth-organize-task.h"
+
+
+#define GET_WIDGET(name) _gtk_builder_get_widget (self->priv->builder, (name))
+
+
+enum {
+ NAME_COLUMN = 0,
+ CARDINALITY_COLUMN,
+ CREATE_CATALOG_COLUMN
+};
+
+
+struct _GthOrganizeTaskPrivate
+{
+ GthBrowser *browser;
+ GFile *folder;
+ GthGroupPolicy group_policy;
+ gboolean recursive;
+ gboolean create_singletons;
+ GthCatalog *singletons_catalog;
+ GtkBuilder *builder;
+ GtkListStore *results_liststore;
+ GHashTable *catalogs;
+};
+
+
+static gpointer parent_class = NULL;
+
+
+static void
+gth_organize_task_finalize (GObject *object)
+{
+ GthOrganizeTask *self;
+
+ self = GTH_ORGANIZE_TASK (object);
+
+ g_object_unref (self->priv->folder);
+ _g_object_unref (self->priv->singletons_catalog);
+ g_object_unref (self->priv->builder);
+ g_hash_table_destroy (self->priv->catalogs);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+save_catalog (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ GthOrganizeTask *self = user_data;
+ GthCatalog *catalog = value;
+ GFile *gio_file;
+ char *data;
+ gsize size;
+ GError *error = NULL;
+
+ if (! self->priv->create_singletons) {
+ GList *file_list = gth_catalog_get_file_list (catalog);
+ if ((file_list == NULL) || (file_list->next == NULL))
+ return;
+ }
+
+ gio_file = gth_catalog_file_to_gio_file (gth_catalog_get_file (catalog));
+ data = gth_catalog_to_data (catalog, &size);
+ if (! g_write_file (gio_file,
+ FALSE,
+ G_FILE_CREATE_NONE,
+ data,
+ size,
+ gth_task_get_cancellable (GTH_TASK (self)),
+ &error))
+ {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ }
+
+ g_free (data);
+ g_object_unref (gio_file);
+}
+
+
+static void
+create_singletons_catalog (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ GthOrganizeTask *self = user_data;
+ GthCatalog *catalog = value;
+ GList *file_list;
+
+ file_list = gth_catalog_get_file_list (catalog);
+ if ((file_list != NULL) && (file_list->next == NULL))
+ gth_catalog_append_file (self->priv->singletons_catalog, (GFile *) file_list->data);
+}
+
+
+static void
+done_func (GError *error,
+ gpointer user_data)
+{
+ GthOrganizeTask *self = user_data;
+
+ if (error != NULL) {
+ gth_task_completed (GTH_TASK (self), error);
+ return;
+ }
+
+ g_hash_table_foreach (self->priv->catalogs, save_catalog, self);
+
+ if (! self->priv->create_singletons && (self->priv->singletons_catalog != NULL)) {
+ GFile *gio_file;
+ char *data;
+ gsize size;
+
+ g_hash_table_foreach (self->priv->catalogs, create_singletons_catalog, self);
+
+ gio_file = gth_catalog_file_to_gio_file (gth_catalog_get_file (self->priv->singletons_catalog));
+ data = gth_catalog_to_data (self->priv->singletons_catalog, &size);
+ g_write_file (gio_file,
+ FALSE,
+ G_FILE_CREATE_NONE,
+ data,
+ size,
+ gth_task_get_cancellable (GTH_TASK (self)),
+ NULL);
+
+ g_free (data);
+ g_object_unref (gio_file);
+ }
+
+ gtk_widget_destroy (GET_WIDGET ("organize_files_dialog"));
+ gth_task_completed (GTH_TASK (self), NULL);
+}
+
+
+static GFile *
+get_catalog_file (const char *display_name)
+{
+ GFile *base;
+ char *name;
+ char *name_escaped;
+ GFile *catalog_file;
+
+ base = g_file_new_for_uri ("catalog:///");
+ name = g_strdup_printf ("%s.catalog", display_name);
+ name_escaped = _g_utf8_replace (name, "/", ".");
+ catalog_file = g_file_get_child_for_display_name (base, name_escaped, NULL);
+
+ g_free (name_escaped);
+ g_free (name);
+ g_object_unref (base);
+
+ return catalog_file;
+}
+
+
+static void
+for_each_file_func (GFile *file,
+ GFileInfo *info,
+ gpointer user_data)
+{
+ GthOrganizeTask *self = user_data;
+ GthFileData *file_data;
+ char *key;
+ 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);
+ switch (self->priv->group_policy) {
+ case GTH_GROUP_POLICY_DIGITALIZED_DATE: {
+ GObject *metadata;
+
+ metadata = g_file_info_get_attribute_object (info, "Embedded::Image::DateTime");
+ if (metadata != NULL) {
+ if (_g_time_val_from_exif_date (gth_metadata_get_raw (GTH_METADATA (metadata)), &timeval))
+ key = g_strdup (_g_time_val_strftime (&timeval, "%x"));
+ }
+ }
+ break;
+
+ case GTH_GROUP_POLICY_MODIFIED_DATE:
+ timeval = *gth_file_data_get_modification_time (file_data);
+ key = g_strdup (_g_time_val_strftime (&timeval, "%x"));
+ break;
+ }
+
+ if (key == NULL)
+ return;
+
+ catalog = g_hash_table_lookup (self->priv->catalogs, key);
+ if (catalog == NULL) {
+ GthDateTime *date_time;
+ char *exif_date;
+ GFile *catalog_file;
+ GtkTreeIter iter;
+
+ catalog = gth_catalog_new ();
+ date_time = gth_datetime_new ();
+ exif_date = _g_time_val_to_exif_date (&timeval);
+ gth_datetime_from_exif_date (date_time, exif_date);
+ gth_catalog_set_date (catalog, date_time);
+ catalog_file = get_catalog_file (key);
+ gth_catalog_set_file (catalog, catalog_file);
+ g_hash_table_insert (self->priv->catalogs, g_strdup (key), catalog);
+
+ gtk_list_store_append (self->priv->results_liststore, &iter);
+ gtk_list_store_set (self->priv->results_liststore, &iter,
+ NAME_COLUMN, key,
+ CARDINALITY_COLUMN, 0,
+ CREATE_CATALOG_COLUMN, TRUE,
+ -1);
+
+ g_object_unref (catalog_file);
+ g_free (exif_date);
+ gth_datetime_free (date_time);
+ }
+
+ if (catalog != NULL)
+ gth_catalog_append_file (catalog, file_data->file);
+
+ g_object_unref (file_data);
+ g_free (key);
+}
+
+
+static DirOp
+start_dir_func (GFile *directory,
+ GFileInfo *info,
+ GError **error,
+ gpointer user_data)
+{
+ GthOrganizeTask *self = user_data;
+ char *uri;
+ char *text;
+
+ uri = g_file_get_parse_name (directory);
+ text = g_strdup_printf ("Searching in %s", uri);
+ gtk_label_set_text (GTK_LABEL (GET_WIDGET ("progress_label")), text);
+
+ g_free (text);
+ g_free (uri);
+
+ return DIR_OP_CONTINUE;
+}
+
+
+static void
+gth_organize_task_exec (GthTask *base)
+{
+ GthOrganizeTask *self;
+ const char *attributes;
+
+ self = GTH_ORGANIZE_TASK (base);
+
+ 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::Image::DateTime";
+ break;
+ case GTH_GROUP_POLICY_MODIFIED_DATE:
+ attributes = "standard::name,standard::type,time::modified,time::modified-usec";
+ break;
+ }
+ g_directory_foreach_child (self->priv->folder,
+ self->priv->recursive,
+ TRUE,
+ attributes,
+ gth_task_get_cancellable (GTH_TASK (self)),
+ start_dir_func,
+ for_each_file_func,
+ done_func,
+ self);
+
+ gth_task_dialog (base, TRUE);
+ gtk_window_set_transient_for (GTK_WINDOW (GET_WIDGET ("organize_files_dialog")), GTK_WINDOW (self->priv->browser));
+ gtk_window_set_modal (GTK_WINDOW (GET_WIDGET ("organize_files_dialog")), TRUE);
+ gtk_widget_show (GET_WIDGET ("organize_files_dialog"));
+}
+
+
+static void
+gth_organize_task_cancelled (GthTask *base)
+{
+ /* FIXME */
+}
+
+
+static void
+gth_organize_task_class_init (GthOrganizeTaskClass *klass)
+{
+ GObjectClass *object_class;
+ GthTaskClass *task_class;
+
+ parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (klass, sizeof (GthOrganizeTaskPrivate));
+
+ object_class = (GObjectClass*) klass;
+ object_class->finalize = gth_organize_task_finalize;
+
+ task_class = (GthTaskClass*) klass;
+ task_class->exec = gth_organize_task_exec;
+ task_class->cancelled = gth_organize_task_cancelled;
+}
+
+
+static void
+gth_organize_task_init (GthOrganizeTask *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_ORGANIZE_TASK, GthOrganizeTaskPrivate);
+ 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);
+}
+
+
+GType
+gth_organize_task_get_type (void)
+{
+ static GType type = 0;
+
+ if (! type) {
+ GTypeInfo type_info = {
+ sizeof (GthOrganizeTaskClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gth_organize_task_class_init,
+ NULL,
+ NULL,
+ sizeof (GthOrganizeTask),
+ 0,
+ (GInstanceInitFunc) gth_organize_task_init
+ };
+
+ type = g_type_register_static (GTH_TYPE_TASK,
+ "GthOrganizeTask",
+ &type_info,
+ 0);
+ }
+
+ return type;
+}
+
+
+GthTask *
+gth_organize_task_new (GthBrowser *browser,
+ GFile *folder,
+ GthGroupPolicy group_policy)
+{
+ GthOrganizeTask *self;
+
+ self = (GthOrganizeTask *) g_object_new (GTH_TYPE_ORGANIZE_TASK, NULL);
+ self->priv->browser = browser;
+ self->priv->folder = g_file_dup (folder);
+ self->priv->group_policy = group_policy;
+
+ return (GthTask*) self;
+}
+
+
+void
+gth_organize_task_set_recursive (GthOrganizeTask *self,
+ gboolean recursive)
+{
+ self->priv->recursive = recursive;
+}
+
+
+void
+gth_organize_task_set_create_singletons (GthOrganizeTask *self,
+ gboolean create)
+{
+ self->priv->create_singletons = create;
+}
+
+
+void
+gth_organize_task_set_singletons_catalog (GthOrganizeTask *self,
+ const char *catalog_name)
+{
+ GFile *file;
+
+ g_object_unref (self->priv->singletons_catalog);
+ self->priv->singletons_catalog = NULL;
+ if (catalog_name == NULL)
+ return;
+
+ self->priv->singletons_catalog = gth_catalog_new ();
+ file = get_catalog_file (catalog_name);
+ gth_catalog_set_file (self->priv->singletons_catalog, file);
+
+ g_object_unref (file);
+}
diff --git a/extensions/catalogs/gth-organize-task.h b/extensions/catalogs/gth-organize-task.h
new file mode 100644
index 0000000..6b88f7e
--- /dev/null
+++ b/extensions/catalogs/gth-organize-task.h
@@ -0,0 +1,67 @@
+/* -*- 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_ORGANIZE_TASK_H
+#define GTH_ORGANIZE_TASK_H
+
+#include <glib-object.h>
+#include <gthumb.h>
+
+typedef enum {
+ GTH_GROUP_POLICY_DIGITALIZED_DATE,
+ GTH_GROUP_POLICY_MODIFIED_DATE
+} GthGroupPolicy;
+
+#define GTH_TYPE_ORGANIZE_TASK (gth_organize_task_get_type ())
+#define GTH_ORGANIZE_TASK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTH_TYPE_ORGANIZE_TASK, GthOrganizeTask))
+#define GTH_ORGANIZE_TASK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTH_TYPE_ORGANIZE_TASK, GthOrganizeTaskClass))
+#define GTH_IS_ORGANIZE_TASK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTH_TYPE_ORGANIZE_TASK))
+#define GTH_IS_ORGANIZE_TASK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTH_TYPE_ORGANIZE_TASK))
+#define GTH_ORGANIZE_TASK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GTH_TYPE_ORGANIZE_TASK, GthOrganizeTaskClass))
+
+typedef struct _GthOrganizeTask GthOrganizeTask;
+typedef struct _GthOrganizeTaskPrivate GthOrganizeTaskPrivate;
+typedef struct _GthOrganizeTaskClass GthOrganizeTaskClass;
+
+struct _GthOrganizeTask
+{
+ GthTask __parent;
+ GthOrganizeTaskPrivate *priv;
+};
+
+struct _GthOrganizeTaskClass
+{
+ GthTaskClass __parent_class;
+};
+
+GType gth_organize_task_get_type (void) G_GNUC_CONST;
+GthTask * gth_organize_task_new (GthBrowser *browser,
+ GFile *folder,
+ GthGroupPolicy group_policy);
+void gth_organize_task_set_recursive (GthOrganizeTask *self,
+ gboolean recursive);
+void gth_organize_task_set_create_singletons (GthOrganizeTask *self,
+ gboolean create);
+void gth_organize_task_set_singletons_catalog (GthOrganizeTask *self,
+ const char *catalog_name);
+
+#endif /* GTH_ORGANIZE_TASK_H */
diff --git a/gthumb/gio-utils.c b/gthumb/gio-utils.c
index 7bf16cf..a947523 100644
--- a/gthumb/gio-utils.c
+++ b/gthumb/gio-utils.c
@@ -26,6 +26,7 @@
#include <gio/gio.h>
#include "gth-file-data.h"
#include "gth-hook.h"
+#include "gth-metadata-provider.h"
#include "gth-overwrite-dialog.h"
#include "glib-utils.h"
#include "gio-utils.h"
@@ -188,6 +189,9 @@ typedef struct {
GFileEnumerator *enumerator;
GError *error;
guint source_id;
+ gboolean metadata_attributes;
+ GList *children;
+ GList *current_child;
} ForEachChildData;
@@ -311,19 +315,115 @@ for_each_child_close_enumerator (GObject *source_object,
}
+static void for_each_child_next_files_ready (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data);
+
+
+static void
+for_each_child_read_next_files (ForEachChildData *fec)
+{
+ _g_object_list_unref (fec->children);
+ fec->children = NULL;
+ g_file_enumerator_next_files_async (fec->enumerator,
+ N_FILES_PER_REQUEST,
+ G_PRIORITY_DEFAULT,
+ fec->cancellable,
+ for_each_child_next_files_ready,
+ fec);
+}
+
+
+static void for_each_child_read_current_child_metadata (ForEachChildData *fec);
+
+
+static void
+for_each_child_read_next_child_metadata (ForEachChildData *fec)
+{
+ fec->current_child = fec->current_child->next;
+ if (fec->current_child != NULL)
+ for_each_child_read_current_child_metadata (fec);
+ else
+ for_each_child_read_next_files (fec);
+}
+
+
+static void
+for_each_child_compute_child (ForEachChildData *fec,
+ GFile *file,
+ GFileInfo *info)
+{
+ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
+ char *id;
+
+ /* avoid to visit a directory more than ones */
+
+ id = g_strdup (g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILE));
+ if (id == NULL)
+ id = g_file_get_uri (file);
+
+ if (g_hash_table_lookup (fec->already_visited, id) == NULL) {
+ g_hash_table_insert (fec->already_visited, g_strdup (id), GINT_TO_POINTER (1));
+ fec->to_visit = g_list_append (fec->to_visit, child_data_new (file, info));
+ }
+
+ g_free (id);
+ }
+
+ fec->for_each_file_func (file, info, fec->user_data);
+}
+
+
+static void
+for_each_child_metadata_ready_func (GList *files,
+ GError *error,
+ gpointer user_data)
+{
+ ForEachChildData *fec = user_data;
+
+ if (error == NULL) {
+ GthFileData *child_data = files->data;
+ for_each_child_compute_child (fec, child_data->file, child_data->info);
+ }
+
+ for_each_child_read_next_child_metadata (fec);
+}
+
+
+static void
+for_each_child_read_current_child_metadata (ForEachChildData *fec)
+{
+ GFileInfo *child_info = fec->current_child->data;
+ GFile *child_file;
+ GList *file_list;
+ GthFileData *child_data;
+
+ child_file = g_file_get_child (fec->current->file, g_file_info_get_name (child_info));
+ child_data = gth_file_data_new (child_file, child_info);
+ file_list = g_list_append (NULL, child_data);
+ _g_query_metadata_async (file_list,
+ fec->attributes,
+ NULL, /* FIXME: cannot use fec->cancellable here */
+ for_each_child_metadata_ready_func,
+ fec);
+
+ _g_object_list_unref (file_list);
+ g_object_unref (child_file);
+}
+
+
static void
for_each_child_next_files_ready (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
ForEachChildData *fec = user_data;
- GList *children, *scan;
- children = g_file_enumerator_next_files_finish (fec->enumerator,
- result,
- &(fec->error));
+ fec->children = g_file_enumerator_next_files_finish (fec->enumerator,
+ result,
+ &(fec->error));
- if (children == NULL) {
+ if (fec->children == NULL) {
g_file_enumerator_close_async (fec->enumerator,
G_PRIORITY_DEFAULT,
fec->cancellable,
@@ -332,42 +432,28 @@ for_each_child_next_files_ready (GObject *source_object,
return;
}
- for (scan = children; scan; scan = scan->next) {
- GFileInfo *child_info = scan->data;
- GFile *file;
-
- file = g_file_get_child (fec->current->file, g_file_info_get_name (child_info));
-
- if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY) {
- char *id;
-
- /* avoid to visit a directory more than ones */
+ if (fec->metadata_attributes) {
+ fec->current_child = fec->children;
+ for_each_child_read_current_child_metadata (fec);
+ }
+ else {
+ GList *scan;
- id = g_strdup (g_file_info_get_attribute_string (child_info, G_FILE_ATTRIBUTE_ID_FILE));
- if (id == NULL)
- id = g_file_get_uri (file);
+ for (scan = fec->children; scan; scan = scan->next) {
+ GFileInfo *child_info = scan->data;
+ GFile *child_file;
- if (g_hash_table_lookup (fec->already_visited, id) == NULL) {
- g_hash_table_insert (fec->already_visited, g_strdup (id), GINT_TO_POINTER (1));
- fec->to_visit = g_list_append (fec->to_visit, child_data_new (file, child_info));
- }
+ child_file = g_file_get_child (fec->current->file, g_file_info_get_name (child_info));
+ for_each_child_compute_child (fec, child_file, child_info);
- g_free (id);
+ g_object_unref (child_file);
}
- fec->for_each_file_func (file, child_info, fec->user_data);
-
- g_object_unref (file);
+ for_each_child_read_next_files (fec);
}
-
- g_file_enumerator_next_files_async (fec->enumerator,
- N_FILES_PER_REQUEST,
- G_PRIORITY_DEFAULT,
- fec->cancellable,
- for_each_child_next_files_ready,
- fec);
}
+
static void
for_each_child_ready (GObject *source_object,
GAsyncResult *result,
@@ -496,6 +582,7 @@ g_directory_foreach_child (GFile *directory,
g_str_equal,
g_free,
NULL);
+ fec->metadata_attributes = ! _g_file_attributes_matches_mask (fec->attributes, GIO_ATTRIBUTES);
g_file_query_info_async (fec->base_directory,
fec->attributes,
diff --git a/gthumb/glib-utils.c b/gthumb/glib-utils.c
index 6cec036..1a7877f 100644
--- a/gthumb/glib-utils.c
+++ b/gthumb/glib-utils.c
@@ -2121,10 +2121,42 @@ attribute_matches_mask (const char *attribute,
}
-static gboolean
+gboolean
_g_file_attributes_matches_mask (const char *attributes,
const char *mask)
{
+ gboolean matches_all_mask = TRUE;
+ char **attributes_v;
+ char **mask_v;
+ int j;
+
+ attributes_v = g_strsplit (attributes, ",", -1);
+ mask_v = g_strsplit (mask, ",", -1);
+ for (j = 0; matches_all_mask && (attributes_v[j] != NULL); j++) {
+ gboolean matches = FALSE;
+ int i;
+
+ for (i = 0; ! matches && (mask_v[i] != NULL); i++) {
+ matches = attribute_matches_mask (attributes_v[j], mask_v[i]);
+#if 0
+ g_print ("attr: %s <=> mask: %s : %d\n", attributes_v[j], mask_v[i], matches);
+#endif
+ }
+
+ matches_all_mask = matches;
+ }
+
+ g_strfreev (mask_v);
+ g_strfreev (attributes_v);
+
+ return matches_all_mask;
+}
+
+
+static gboolean
+_attributes_matches_mask (const char *attributes,
+ const char *mask)
+{
gboolean matches = FALSE;
char **attributes_v;
char **mask_v;
@@ -2154,7 +2186,7 @@ gboolean
_g_file_attributes_matches (const char *attributes,
const char *mask)
{
- return _g_file_attributes_matches_mask (attributes, mask) || _g_file_attributes_matches_mask (mask, attributes);
+ return _attributes_matches_mask (attributes, mask) || _attributes_matches_mask (mask, attributes);
}
diff --git a/gthumb/glib-utils.h b/gthumb/glib-utils.h
index 65a5f70..94bb22e 100644
--- a/gthumb/glib-utils.h
+++ b/gthumb/glib-utils.h
@@ -53,6 +53,7 @@ G_BEGIN_DECLS
#define GFILE_STANDARD_ATTRIBUTES (DEFINE_STANDARD_ATTRIBUTES(""))
#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 GNOME_COPIED_FILES (gdk_atom_intern_static_string ("x-special/gnome-copied-files"))
#define IROUND(x) ((int)floor(((double)x) + 0.5))
@@ -249,6 +250,8 @@ GFile * _g_file_append_prefix (GFile *file,
const char *prefix);
GFile * _g_file_append_path (GFile *file,
const char *path);
+gboolean _g_file_attributes_matches_mask (const char *attributes,
+ const char *mask);
gboolean _g_file_attributes_matches (const char *attributes,
const char *mask);
void _g_file_info_swap_attributes (GFileInfo *info,
diff --git a/gthumb/gth-embedded-dialog.c b/gthumb/gth-embedded-dialog.c
index 3074bbb..1bb7946 100644
--- a/gthumb/gth-embedded-dialog.c
+++ b/gthumb/gth-embedded-dialog.c
@@ -120,6 +120,7 @@ gth_embedded_dialog_construct (GthEmbeddedDialog *self)
gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
gtk_misc_set_alignment (GTK_MISC (primary_label), 0, 0.5);
+ gtk_misc_set_padding (GTK_MISC (primary_label), 0, 6);
GTK_WIDGET_SET_FLAGS (primary_label, GTK_CAN_FOCUS);
gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
diff --git a/gthumb/gth-main.c b/gthumb/gth-main.c
index 9f0d1c7..269f7b5 100644
--- a/gthumb/gth-main.c
+++ b/gthumb/gth-main.c
@@ -1262,7 +1262,7 @@ attribute_list_reaload_required (const char *old_attributes,
new_attributes_len = g_strv_length (new_attributes_v);
for (i = 0; i < new_attributes_len; i++) {
- if (_g_file_attributes_matches (new_attributes_v[i], "standard::*,etag::*,id::*,access::*,mountable::*,time::*,unix::*,dos::*,owner::*,thumbnail::*,filesystem::*,gvfs::*,xattr::*,xattr-sys::*,selinux::*")) {
+ if (_g_file_attributes_matches (new_attributes_v[i], GIO_ATTRIBUTES)) {
g_free (new_attributes_v[i]);
new_attributes_v[i] = NULL;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]