[gthumb] added ability to add a tag to the selected files with the context menu
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] added ability to add a tag to the selected files with the context menu
- Date: Wed, 30 Jun 2010 20:41:37 +0000 (UTC)
commit 70b2cec293e2432c478e51d711b469aed19b8f44
Author: Paolo Bacchilega <paobac src gnome org>
Date: Wed Jun 30 22:34:19 2010 +0200
added ability to add a tag to the selected files with the context menu
extensions/edit_metadata/Makefile.am | 4 +
extensions/edit_metadata/actions.c | 62 ++++
extensions/edit_metadata/actions.h | 1 +
extensions/edit_metadata/callbacks.c | 152 +++++++++-
extensions/edit_metadata/callbacks.h | 8 +-
extensions/edit_metadata/data/ui/Makefile.am | 2 +-
extensions/edit_metadata/data/ui/tag-chooser.ui | 131 ++++++++
extensions/edit_metadata/gth-tag-chooser-dialog.c | 339 +++++++++++++++++++++
extensions/edit_metadata/gth-tag-chooser-dialog.h | 59 ++++
extensions/edit_metadata/gth-tag-task.c | 206 +++++++++++++
extensions/edit_metadata/gth-tag-task.h | 57 ++++
extensions/edit_metadata/main.c | 3 +-
gthumb/gth-main.c | 3 +-
gthumb/gth-string-list.c | 12 +
gthumb/gth-string-list.h | 2 +
15 files changed, 1032 insertions(+), 9 deletions(-)
---
diff --git a/extensions/edit_metadata/Makefile.am b/extensions/edit_metadata/Makefile.am
index a77c10c..3e41b4c 100644
--- a/extensions/edit_metadata/Makefile.am
+++ b/extensions/edit_metadata/Makefile.am
@@ -14,6 +14,10 @@ libedit_metadata_la_SOURCES = \
gth-edit-comment-page.h \
gth-edit-metadata-dialog.c \
gth-edit-metadata-dialog.h \
+ gth-tag-chooser-dialog.c \
+ gth-tag-chooser-dialog.h \
+ gth-tag-task.c \
+ gth-tag-task.h \
main.c
libedit_metadata_la_CFLAGS = $(GTHUMB_CFLAGS) -I$(top_srcdir) -I$(top_builddir)/gthumb
diff --git a/extensions/edit_metadata/actions.c b/extensions/edit_metadata/actions.c
index 0219cfd..333df2b 100644
--- a/extensions/edit_metadata/actions.c
+++ b/extensions/edit_metadata/actions.c
@@ -24,6 +24,8 @@
#include <config.h>
#include <gthumb.h>
#include "dlg-edit-metadata.h"
+#include "gth-tag-chooser-dialog.h"
+#include "gth-tag-task.h"
void
@@ -43,3 +45,63 @@ gth_browser_activate_action_edit_metadata (GtkAction *action,
_g_object_list_unref (file_data_list);
_gtk_tree_path_list_free (items);
}
+
+
+static void
+tag_chooser_dialog_response_cb (GtkDialog *dialog,
+ int response_id,
+ gpointer user_data)
+{
+ GthBrowser *browser = user_data;
+
+ switch (response_id) {
+ case GTK_RESPONSE_HELP:
+ show_help_dialog (GTK_WINDOW (browser), "assign-tags");
+ break;
+
+ case GTK_RESPONSE_OK:
+ {
+ GList *items;
+ GList *file_data_list;
+ GList *file_list;
+ char **tags;
+ GthTask *task;
+
+ items = gth_file_selection_get_selected (GTH_FILE_SELECTION (gth_browser_get_file_list_view (browser)));
+ file_data_list = gth_file_list_get_files (GTH_FILE_LIST (gth_browser_get_file_list (browser)), items);
+ file_list = gth_file_data_list_to_file_list (file_data_list);
+ tags = gth_tag_chooser_dialog_get_tags (GTH_TAG_CHOOSER_DIALOG (dialog));
+ task = gth_tag_task_new (file_list, tags);
+ gth_browser_exec_task (browser, task, FALSE);
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+
+ g_object_unref (task);
+ g_strfreev (tags);
+ _g_object_list_unref (file_list);
+ _g_object_list_unref (file_data_list);
+ _gtk_tree_path_list_free (items);
+ }
+ break;
+
+ case GTK_RESPONSE_DELETE_EVENT:
+ case GTK_RESPONSE_CANCEL:
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ break;
+ }
+}
+
+
+void
+gth_browser_activate_action_edit_tag_files (GtkAction *action,
+ GthBrowser *browser)
+{
+ GtkWidget *dialog;
+
+ dialog = gth_tag_chooser_dialog_new ();
+ g_signal_connect (dialog,
+ "response",
+ G_CALLBACK (tag_chooser_dialog_response_cb),
+ browser);
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (browser));
+ gtk_window_present (GTK_WINDOW (dialog));
+}
diff --git a/extensions/edit_metadata/actions.h b/extensions/edit_metadata/actions.h
index 96777e2..270bd61 100644
--- a/extensions/edit_metadata/actions.h
+++ b/extensions/edit_metadata/actions.h
@@ -28,5 +28,6 @@
#define DEFINE_ACTION(x) void x (GtkAction *action, gpointer data);
DEFINE_ACTION(gth_browser_activate_action_edit_metadata)
+DEFINE_ACTION(gth_browser_activate_action_edit_tag_files)
#endif /* ACTIONS_H */
diff --git a/extensions/edit_metadata/callbacks.c b/extensions/edit_metadata/callbacks.c
index 8cd5b80..9072185 100644
--- a/extensions/edit_metadata/callbacks.c
+++ b/extensions/edit_metadata/callbacks.c
@@ -26,6 +26,7 @@
#include <glib-object.h>
#include <gthumb.h>
#include "actions.h"
+#include "gth-tag-task.h"
#define BROWSER_DATA_KEY "edit-metadata-data"
@@ -52,11 +53,19 @@ static const char *fixed_ui_info =
" </toolbar>"
" <popup name='FileListPopup'>"
" <placeholder name='File_LastActions'>"
+" <menu action='Edit_QuickTag'>"
+" <separator name='TagListSeparator'/>"
+" <menuitem action='Edit_QuickTagOther'/>"
+" </menu>"
" <menuitem action='Edit_Metadata'/>"
" </placeholder>"
" </popup>"
" <popup name='FilePopup'>"
" <placeholder name='File_LastActions'>"
+" <menu action='Edit_QuickTag'>"
+" <separator name='TagListSeparator'/>"
+" <menuitem action='Edit_QuickTagOther'/>"
+" </menu>"
" <menuitem action='Edit_Metadata'/>"
" </placeholder>"
" </popup>"
@@ -86,10 +95,17 @@ static const char *viewer_ui_info =
static GtkActionEntry edit_metadata_action_entries[] = {
+ { "Edit_QuickTag", "tag", N_("T_ags") },
+
{ "Edit_Metadata", GTK_STOCK_EDIT,
N_("Comment"), "<control>M",
N_("Edit the comment an other information of the selected files"),
- G_CALLBACK (gth_browser_activate_action_edit_metadata) }
+ G_CALLBACK (gth_browser_activate_action_edit_metadata) },
+
+ { "Edit_QuickTagOther", NULL,
+ N_("Other..."), NULL,
+ N_("Choose another tag"),
+ G_CALLBACK (gth_browser_activate_action_edit_tag_files) }
};
@@ -98,16 +114,30 @@ typedef struct {
GtkActionGroup *actions;
guint browser_ui_merge_id;
guint viewer_ui_merge_id;
+ gboolean tag_menu_loaded;
+ guint monitor_events;
} BrowserData;
static void
browser_data_free (BrowserData *data)
{
+ if (data->monitor_events != 0) {
+ g_signal_handler_disconnect (gth_main_get_default_monitor (), data->monitor_events);
+ data->monitor_events = 0;
+ }
g_free (data);
}
+static void
+monitor_tags_changed_cb (GthMonitor *monitor,
+ BrowserData *data)
+{
+ data->tag_menu_loaded = FALSE;
+}
+
+
void
edit_metadata__gth_browser_construct_cb (GthBrowser *browser)
{
@@ -134,6 +164,11 @@ edit_metadata__gth_browser_construct_cb (GthBrowser *browser)
gtk_tool_item_set_is_important (GTK_TOOL_ITEM (gtk_ui_manager_get_widget (gth_browser_get_ui_manager (browser), "/Fullscreen_ToolBar/Edit_Actions/Edit_Metadata")), TRUE);
+ data->monitor_events = g_signal_connect (gth_main_get_default_monitor (),
+ "tags-changed",
+ G_CALLBACK (monitor_tags_changed_cb),
+ data);
+
g_object_set_data_full (G_OBJECT (browser), BROWSER_DATA_KEY, data, (GDestroyNotify) browser_data_free);
}
@@ -176,7 +211,6 @@ edit_metadata__gth_browser_set_current_page_cb (GthBrowser *browser)
g_clear_error (&error);
}
gtk_tool_item_set_is_important (GTK_TOOL_ITEM (gtk_ui_manager_get_widget (gth_browser_get_ui_manager (browser), "/ViewerToolBar/Edit_Actions/Edit_Metadata")), TRUE);
-
break;
default:
@@ -202,3 +236,117 @@ edit_metadata__gth_browser_update_sensitivity_cb (GthBrowser *browser)
sensitive = (n_selected > 0);
g_object_set (action, "sensitive", sensitive, NULL);
}
+
+
+static void
+tag_item_activate_cb (GtkMenuItem *menuitem,
+ gpointer user_data)
+{
+ GthBrowser *browser = user_data;
+ GList *items;
+ GList *file_data_list;
+ GList *file_list;
+ char *tag;
+ char **tags;
+ GthTask *task;
+
+ if (gtk_menu_item_get_submenu (menuitem) != NULL)
+ return;
+
+ items = gth_file_selection_get_selected (GTH_FILE_SELECTION (gth_browser_get_file_list_view (browser)));
+ file_data_list = gth_file_list_get_files (GTH_FILE_LIST (gth_browser_get_file_list (browser)), items);
+ file_list = gth_file_data_list_to_file_list (file_data_list);
+
+ tag = g_object_get_data (G_OBJECT (menuitem), "tag");
+ tags = g_new0 (char *, 2);
+ tags[0] = g_strdup (tag);
+ tags[1] = NULL;
+
+ task = gth_tag_task_new (file_list, tags);
+ gth_browser_exec_task (browser, task, FALSE);
+
+ g_object_unref (task);
+ g_strfreev (tags);
+ _g_object_list_unref (file_list);
+ _g_object_list_unref (file_data_list);
+ _gtk_tree_path_list_free (items);
+}
+
+
+static void
+insert_tag_menu_item (BrowserData *data,
+ GtkWidget *menu,
+ const char *tag,
+ int pos)
+{
+ GtkWidget *item;
+ GtkWidget *image;
+
+ item = gtk_image_menu_item_new_with_label (tag);
+ /*gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (item), TRUE);*/
+
+ image = gtk_image_new_from_icon_name ("tag", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ gtk_widget_show (item);
+ gtk_menu_shell_insert (GTK_MENU_SHELL (menu), item, pos);
+ g_object_set_data_full (G_OBJECT (item), "tag", g_strdup (tag), g_free);
+ g_signal_connect (item, "activate", G_CALLBACK (tag_item_activate_cb), data->browser);
+}
+
+
+static void
+update_tag_menu (BrowserData *data)
+{
+ GtkWidget *list_menu;
+ GtkWidget *file_menu;
+ GtkWidget *separator;
+ char **tags;
+ int i;
+
+ list_menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (gtk_ui_manager_get_widget (gth_browser_get_ui_manager (data->browser), "/FileListPopup/File_LastActions/Edit_QuickTag")));
+ separator = gtk_ui_manager_get_widget (gth_browser_get_ui_manager (data->browser), "/FileListPopup/File_LastActions/Edit_QuickTag/TagListSeparator");
+ _gtk_container_remove_children (GTK_CONTAINER (list_menu), NULL, separator);
+
+ file_menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (gtk_ui_manager_get_widget (gth_browser_get_ui_manager (data->browser), "/FilePopup/File_LastActions/Edit_QuickTag")));
+ separator = gtk_ui_manager_get_widget (gth_browser_get_ui_manager (data->browser), "/FilePopup/File_LastActions/Edit_QuickTag/TagListSeparator");
+ _gtk_container_remove_children (GTK_CONTAINER (file_menu), NULL, separator);
+
+ tags = g_strdupv (gth_tags_file_get_tags (gth_main_get_default_tag_file ()));
+ for (i = 0; tags[i] != NULL; i++) {
+ insert_tag_menu_item (data, list_menu, tags[i], i);
+ insert_tag_menu_item (data, file_menu, tags[i], i);
+ }
+
+ g_strfreev (tags);
+}
+
+
+void
+edit_metadata__gth_browser_file_list_popup_before_cb (GthBrowser *browser)
+{
+ BrowserData *data;
+
+ data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY);
+ g_return_if_fail (data != NULL);
+
+ if (! data->tag_menu_loaded) {
+ data->tag_menu_loaded = TRUE;
+ update_tag_menu (data);
+ }
+}
+
+
+void
+edit_metadata__gth_browser_file_popup_before_cb (GthBrowser *browser)
+{
+ BrowserData *data;
+
+ data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY);
+ g_return_if_fail (data != NULL);
+
+ if (! data->tag_menu_loaded) {
+ data->tag_menu_loaded = TRUE;
+ update_tag_menu (data);
+ }
+}
diff --git a/extensions/edit_metadata/callbacks.h b/extensions/edit_metadata/callbacks.h
index 2a6e334..e387287 100644
--- a/extensions/edit_metadata/callbacks.h
+++ b/extensions/edit_metadata/callbacks.h
@@ -25,8 +25,10 @@
#include <gthumb.h>
-void edit_metadata__gth_browser_construct_cb (GthBrowser *browser);
-void edit_metadata__gth_browser_set_current_page_cb (GthBrowser *browser);
-void edit_metadata__gth_browser_update_sensitivity_cb (GthBrowser *browser);
+void edit_metadata__gth_browser_construct_cb (GthBrowser *browser);
+void edit_metadata__gth_browser_set_current_page_cb (GthBrowser *browser);
+void edit_metadata__gth_browser_update_sensitivity_cb (GthBrowser *browser);
+void edit_metadata__gth_browser_file_list_popup_before_cb (GthBrowser *browser);
+void edit_metadata__gth_browser_file_popup_before_cb (GthBrowser *browser);
#endif /* CALLBACKS_H */
diff --git a/extensions/edit_metadata/data/ui/Makefile.am b/extensions/edit_metadata/data/ui/Makefile.am
index 7f637c1..57b099a 100644
--- a/extensions/edit_metadata/data/ui/Makefile.am
+++ b/extensions/edit_metadata/data/ui/Makefile.am
@@ -1,5 +1,5 @@
uidir = $(pkgdatadir)/ui
-ui_DATA = edit-comment-page.ui
+ui_DATA = edit-comment-page.ui tag-chooser.ui
EXTRA_DIST = $(ui_DATA)
-include $(top_srcdir)/git.mk
diff --git a/extensions/edit_metadata/data/ui/tag-chooser.ui b/extensions/edit_metadata/data/ui/tag-chooser.ui
new file mode 100644
index 0000000..8cb6897
--- /dev/null
+++ b/extensions/edit_metadata/data/ui/tag-chooser.ui
@@ -0,0 +1,131 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.14"/>
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkListStore" id="tags_liststore">
+ <columns>
+ <!-- column-name name -->
+ <column type="gchararray"/>
+ <!-- column-name selected -->
+ <column type="gboolean"/>
+ </columns>
+ </object>
+ <object class="GtkVBox" id="content">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="tag_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">T_ags:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">tags_treeview</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox3">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkScrolledWindow" id="tags_scrolledwindow">
+ <property name="width_request">250</property>
+ <property name="height_request">300</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">etched-in</property>
+ <child>
+ <object class="GtkTreeView" id="tags_treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">tags_liststore</property>
+ <property name="headers_visible">False</property>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+ <child>
+ <object class="GtkCellRendererToggle" id="selected_cellrenderertoggle"/>
+ <attributes>
+ <attribute name="active">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn2">
+ <property name="title">column</property>
+ <property name="sort_column_id">1</property>
+ <child>
+ <object class="GtkCellRendererPixbuf" id="cellrendererpixbuf2">
+ <property name="icon_name">tag</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkCellRendererText" id="name_cellrenderertext">
+ <property name="editable">True</property>
+ </object>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVButtonBox" id="vbuttonbox3">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <property name="layout_style">start</property>
+ <child>
+ <object class="GtkButton" id="new_button">
+ <property name="label">gtk-new</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>
+ <child>
+ <object class="GtkButton" id="delete_button">
+ <property name="label">gtk-remove</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>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/extensions/edit_metadata/gth-tag-chooser-dialog.c b/extensions/edit_metadata/gth-tag-chooser-dialog.c
new file mode 100644
index 0000000..d1f51dc
--- /dev/null
+++ b/extensions/edit_metadata/gth-tag-chooser-dialog.c
@@ -0,0 +1,339 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2010 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/gi18n.h>
+#include "gth-tag-chooser-dialog.h"
+
+#define GTH_TAG_CHOOSER_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTH_TYPE_TAG_CHOOSER_DIALOG, GthTagChooserDialogPrivate))
+#define GET_WIDGET(name) _gtk_builder_get_widget (self->priv->builder, (name))
+
+
+enum {
+ NAME_COLUMN = 0,
+ SELECTED_COLUMN
+};
+
+
+static gpointer parent_class = NULL;
+
+
+struct _GthTagChooserDialogPrivate {
+ GtkBuilder *builder;
+};
+
+
+static void
+gth_tag_chooser_dialog_finalize (GObject *object)
+{
+ GthTagChooserDialog *self;
+
+ self = GTH_TAG_CHOOSER_DIALOG (object);
+
+ _g_object_unref (self->priv->builder);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gth_tag_chooser_dialog_class_init (GthTagChooserDialogClass *klass)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (klass, sizeof (GthTagChooserDialogPrivate));
+
+ object_class = (GObjectClass*) klass;
+ object_class->finalize = gth_tag_chooser_dialog_finalize;
+}
+
+
+static void
+new_button_clicked_cb (GtkButton *button,
+ gpointer user_data)
+{
+ GthTagChooserDialog *self = user_data;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ gtk_list_store_append (GTK_LIST_STORE (GET_WIDGET ("tags_liststore")), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (GET_WIDGET ("tags_liststore")), &iter,
+ SELECTED_COLUMN, TRUE,
+ NAME_COLUMN, _("New tag"),
+ -1);
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (GET_WIDGET ("tags_liststore")), &iter);
+ gtk_tree_view_set_cursor_on_cell (GTK_TREE_VIEW (GET_WIDGET ("tags_treeview")),
+ path,
+ GTK_TREE_VIEW_COLUMN (GET_WIDGET ("treeviewcolumn2")),
+ GTK_CELL_RENDERER (GET_WIDGET ("name_cellrenderertext")),
+ TRUE);
+
+ gtk_tree_path_free (path);
+}
+
+
+static void
+delete_button_clicked_cb (GtkButton *button,
+ gpointer user_data)
+{
+ GthTagChooserDialog *self = user_data;
+ GtkTreeIter iter;
+ char *selected_tag;
+ GthTagsFile *tags;
+
+ if (! gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (GET_WIDGET ("tags_treeview"))), NULL, &iter))
+ return;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (GET_WIDGET ("tags_liststore")), &iter,
+ NAME_COLUMN, &selected_tag,
+ -1);
+
+ tags = gth_main_get_default_tag_file ();
+ gth_tags_file_remove (tags, selected_tag);
+ gth_main_tags_changed ();
+
+ gtk_list_store_remove (GTK_LIST_STORE (GET_WIDGET ("tags_liststore")), &iter);
+
+ g_free (selected_tag);
+}
+
+
+static void
+selected_cellrenderertoggle_toggled_cb (GtkCellRendererToggle *cell_renderer,
+ char *path,
+ gpointer user_data)
+{
+ GthTagChooserDialog *self = user_data;
+ GtkTreePath *tpath;
+ GtkTreeIter iter;
+
+ tpath = gtk_tree_path_new_from_string (path);
+ if (tpath == NULL)
+ return;
+
+ if (gtk_tree_model_get_iter (GTK_TREE_MODEL (GET_WIDGET ("tags_liststore")), &iter, tpath)) {
+ gboolean selected;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (GET_WIDGET ("tags_liststore")), &iter,
+ SELECTED_COLUMN, &selected,
+ -1);
+ gtk_list_store_set (GTK_LIST_STORE (GET_WIDGET ("tags_liststore")), &iter,
+ SELECTED_COLUMN, ! selected,
+ -1);
+ }
+
+ gtk_tree_path_free (tpath);
+}
+
+
+static void
+name_cellrenderertext_edited_cb (GtkCellRendererText *renderer,
+ char *path,
+ char *new_text,
+ gpointer user_data)
+{
+ GthTagChooserDialog *self = user_data;
+ GtkTreePath *tree_path;
+ GtkTreeIter iter;
+ char *old_text;
+ GthTagsFile *tags;
+
+ tree_path = gtk_tree_path_new_from_string (path);
+ if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (GET_WIDGET ("tags_liststore")),
+ &iter,
+ tree_path))
+ {
+ gtk_tree_path_free (tree_path);
+ return;
+ }
+ gtk_tree_path_free (tree_path);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (GET_WIDGET ("tags_liststore")),
+ &iter,
+ NAME_COLUMN, &old_text,
+ -1);
+
+ tags = gth_main_get_default_tag_file ();
+ if (old_text != NULL)
+ gth_tags_file_remove (tags, old_text);
+ if (new_text != NULL)
+ gth_tags_file_add (tags, new_text);
+ gth_main_tags_changed ();
+
+ gtk_list_store_set (GTK_LIST_STORE (GET_WIDGET ("tags_liststore")),
+ &iter,
+ NAME_COLUMN, new_text,
+ -1);
+
+ g_free (old_text);
+}
+
+
+static int
+tags_liststore_sort_func (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ char *name_a;
+ char *name_b;
+ int result;
+
+ gtk_tree_model_get (model, a, NAME_COLUMN, &name_a, -1);
+ gtk_tree_model_get (model, b, NAME_COLUMN, &name_b, -1);
+ result = g_utf8_collate (name_a, name_b);
+
+ g_free (name_a);
+ g_free (name_b);
+
+ return result;
+}
+
+
+static void
+gth_tag_chooser_dialog_init (GthTagChooserDialog *self)
+{
+ GtkWidget *content;
+ char **tags;
+ int i;
+
+ self->priv = GTH_TAG_CHOOSER_DIALOG_GET_PRIVATE (self);
+ self->priv->builder = _gtk_builder_new_from_file ("tag-chooser.ui", "edit_metadata");
+
+ gtk_window_set_title (GTK_WINDOW (self), _("Assign Tags"));
+ gtk_window_set_resizable (GTK_WINDOW (self), FALSE);
+ gtk_dialog_set_has_separator (GTK_DIALOG (self), FALSE);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), 5);
+ gtk_container_set_border_width (GTK_CONTAINER (self), 5);
+
+ gtk_dialog_add_button (GTK_DIALOG (self), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+ gtk_dialog_add_button (GTK_DIALOG (self), GTK_STOCK_OK, GTK_RESPONSE_OK);
+ gtk_dialog_add_button (GTK_DIALOG (self), GTK_STOCK_HELP, GTK_RESPONSE_HELP);
+
+ content = _gtk_builder_get_widget (self->priv->builder, "content");
+ gtk_container_set_border_width (GTK_CONTAINER (content), 5);
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), content, TRUE, TRUE, 0);
+
+ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (GET_WIDGET ("tags_liststore")), tags_liststore_sort_func, self, NULL);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GET_WIDGET ("tags_liststore")), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
+
+ g_signal_connect (GET_WIDGET ("selected_cellrenderertoggle"),
+ "toggled",
+ G_CALLBACK (selected_cellrenderertoggle_toggled_cb),
+ self);
+ g_signal_connect (GET_WIDGET ("name_cellrenderertext"),
+ "edited",
+ G_CALLBACK (name_cellrenderertext_edited_cb),
+ self);
+ g_signal_connect (GET_WIDGET ("new_button"),
+ "clicked",
+ G_CALLBACK (new_button_clicked_cb),
+ self);
+ g_signal_connect (GET_WIDGET ("delete_button"),
+ "clicked",
+ G_CALLBACK (delete_button_clicked_cb),
+ self);
+
+ tags = g_strdupv (gth_tags_file_get_tags (gth_main_get_default_tag_file ()));
+ for (i = 0; tags[i] != NULL; i++) {
+ GtkTreeIter iter;
+
+ gtk_list_store_append (GTK_LIST_STORE (GET_WIDGET ("tags_liststore")), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (GET_WIDGET ("tags_liststore")), &iter,
+ NAME_COLUMN, tags[i],
+ SELECTED_COLUMN, 0,
+ -1);
+ }
+
+ g_strfreev (tags);
+}
+
+
+GType
+gth_tag_chooser_dialog_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0) {
+ static const GTypeInfo g_define_type_info = {
+ sizeof (GthTagChooserDialogClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gth_tag_chooser_dialog_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL,
+ sizeof (GthTagChooserDialog),
+ 0,
+ (GInstanceInitFunc) gth_tag_chooser_dialog_init,
+ NULL
+ };
+ type = g_type_register_static (GTK_TYPE_DIALOG,
+ "GthTagChooserDialog",
+ &g_define_type_info,
+ 0);
+ }
+
+ return type;
+}
+
+
+GtkWidget *
+gth_tag_chooser_dialog_new (void)
+{
+ return (GtkWidget *) g_object_new (GTH_TYPE_TAG_CHOOSER_DIALOG, NULL);
+}
+
+
+char **
+gth_tag_chooser_dialog_get_tags (GthTagChooserDialog *self)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GList *tag_list;
+ char **tags;
+
+ tag_list = NULL;
+ model = GTK_TREE_MODEL (GET_WIDGET ("tags_liststore"));
+ if (gtk_tree_model_get_iter_first (model, &iter)) {
+ do {
+ gboolean selected;
+ char *name;
+
+ gtk_tree_model_get (model, &iter,
+ SELECTED_COLUMN, &selected,
+ NAME_COLUMN, &name,
+ -1);
+ if (selected)
+ tag_list = g_list_append (tag_list, name);
+ else
+ g_free (name);
+ }
+ while (gtk_tree_model_iter_next (model, &iter));
+ }
+
+ tags = _g_string_list_to_strv (tag_list);
+ _g_string_list_free (tag_list);
+
+ return tags;
+}
diff --git a/extensions/edit_metadata/gth-tag-chooser-dialog.h b/extensions/edit_metadata/gth-tag-chooser-dialog.h
new file mode 100644
index 0000000..2215fe0
--- /dev/null
+++ b/extensions/edit_metadata/gth-tag-chooser-dialog.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2010 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_TAG_CHOOSER_DIALOG_H
+#define GTH_TAG_CHOOSER_DIALOG_H
+
+#include <gtk/gtk.h>
+#include <gthumb.h>
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_TAG_CHOOSER_DIALOG (gth_tag_chooser_dialog_get_type ())
+#define GTH_TAG_CHOOSER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_TAG_CHOOSER_DIALOG, GthTagChooserDialog))
+#define GTH_TAG_CHOOSER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_TAG_CHOOSER_DIALOG, GthTagChooserDialogClass))
+#define GTH_IS_TAG_CHOOSER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_TAG_CHOOSER_DIALOG))
+#define GTH_IS_TAG_CHOOSER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_TAG_CHOOSER_DIALOG))
+#define GTH_TAG_CHOOSER_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTH_TYPE_TAG_CHOOSER_DIALOG, GthTagChooserDialogClass))
+
+typedef struct _GthTagChooserDialog GthTagChooserDialog;
+typedef struct _GthTagChooserDialogClass GthTagChooserDialogClass;
+typedef struct _GthTagChooserDialogPrivate GthTagChooserDialogPrivate;
+
+struct _GthTagChooserDialog {
+ GtkDialog parent_instance;
+ GthTagChooserDialogPrivate *priv;
+};
+
+struct _GthTagChooserDialogClass {
+ GtkDialogClass parent_class;
+};
+
+/* GthTagChooserDialog */
+
+GType gth_tag_chooser_dialog_get_type (void);
+GtkWidget * gth_tag_chooser_dialog_new (void);
+char ** gth_tag_chooser_dialog_get_tags (GthTagChooserDialog *dialog);
+
+G_END_DECLS
+
+#endif /* GTH_TAG_CHOOSER_DIALOG_H */
diff --git a/extensions/edit_metadata/gth-tag-task.c b/extensions/edit_metadata/gth-tag-task.c
new file mode 100644
index 0000000..d27035f
--- /dev/null
+++ b/extensions/edit_metadata/gth-tag-task.c
@@ -0,0 +1,206 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2010 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 "gth-tag-task.h"
+
+
+struct _GthTagTaskPrivate {
+ GList *file_list;
+ GList *file_data_list;
+ GthStringList *tags;
+};
+
+
+static gpointer parent_class = NULL;
+
+
+static void
+gth_tag_task_finalize (GObject *object)
+{
+ GthTagTask *self;
+
+ self = GTH_TAG_TASK (object);
+
+ _g_object_unref (self->priv->tags);
+ _g_object_list_unref (self->priv->file_list);
+ _g_object_list_unref (self->priv->file_data_list);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+write_metadata_ready_cb (GError *error,
+ gpointer user_data)
+{
+ GthTagTask *self = user_data;
+ GthMonitor *monitor;
+ GList *scan;
+
+ if (error != NULL) {
+ gth_task_completed (GTH_TASK (self), error);
+ return;
+ }
+
+ monitor = gth_main_get_default_monitor ();
+ for (scan = self->priv->file_data_list; scan; scan = scan->next) {
+ GthFileData *file_data = scan->data;
+ GFile *parent;
+ GList *files;
+
+ parent = g_file_get_parent (file_data->file);
+ files = g_list_prepend (NULL, g_object_ref (file_data->file));
+ gth_monitor_folder_changed (monitor, parent, files, GTH_MONITOR_EVENT_CHANGED);
+ gth_monitor_metadata_changed (monitor, file_data);
+
+ _g_object_list_unref (files);
+ g_object_unref (parent);
+ }
+
+ gth_task_completed (GTH_TASK (self), NULL);
+}
+
+
+static void
+info_ready_cb (GList *files,
+ GError *error,
+ gpointer user_data)
+{
+ GthTagTask *self = user_data;
+ GList *scan;
+
+ if (error != NULL) {
+ gth_task_completed (GTH_TASK (self), error);
+ return;
+ }
+
+ self->priv->file_data_list = _g_object_list_ref (files);
+ for (scan = self->priv->file_data_list; scan; scan = scan->next) {
+ GthFileData *file_data = scan->data;
+ GthStringList *original_tags;
+ GthStringList *new_tags;
+
+ original_tags = (GthStringList *) g_file_info_get_attribute_object (file_data->info, "general::tags");
+
+ new_tags = gth_string_list_new (NULL);
+ gth_string_list_append (new_tags, original_tags);
+ gth_string_list_append (new_tags, self->priv->tags);
+
+ g_file_info_set_attribute_object (file_data->info, "general::tags", G_OBJECT (new_tags));
+
+ g_object_unref (new_tags);
+ }
+
+ gth_task_progress (GTH_TASK (self), _("Assigning tags to the selected files"), _("Writing files"), TRUE, 0.0);
+ _g_write_metadata_async (self->priv->file_data_list,
+ "general::tags",
+ gth_task_get_cancellable (GTH_TASK (self)),
+ write_metadata_ready_cb,
+ self);
+}
+
+
+static void
+gth_tag_task_exec (GthTask *task)
+{
+ GthTagTask *self;
+
+ self = GTH_TAG_TASK (task);
+
+ gth_task_progress (task, _("Assigning tags to the selected files"), _("Reading files"), TRUE, 0.0);
+ _g_query_all_metadata_async (self->priv->file_list,
+ FALSE,
+ TRUE,
+ "*",
+ NULL,
+ info_ready_cb,
+ self);
+}
+
+
+static void
+gth_tag_task_class_init (GthTagTaskClass *klass)
+{
+ GObjectClass *object_class;
+ GthTaskClass *task_class;
+
+ parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (klass, sizeof (GthTagTaskPrivate));
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = gth_tag_task_finalize;
+
+ task_class = GTH_TASK_CLASS (klass);
+ task_class->exec = gth_tag_task_exec;
+}
+
+
+static void
+gth_tag_task_init (GthTagTask *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_TAG_TASK, GthTagTaskPrivate);
+ self->priv->file_list = NULL;
+ self->priv->file_data_list = NULL;
+}
+
+
+GType
+gth_tag_task_get_type (void)
+{
+ static GType type = 0;
+
+ if (! type) {
+ GTypeInfo type_info = {
+ sizeof (GthTagTaskClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gth_tag_task_class_init,
+ NULL,
+ NULL,
+ sizeof (GthTagTask),
+ 0,
+ (GInstanceInitFunc) gth_tag_task_init
+ };
+
+ type = g_type_register_static (GTH_TYPE_TASK,
+ "GthTagTask",
+ &type_info,
+ 0);
+ }
+
+ return type;
+}
+
+
+GthTask *
+gth_tag_task_new (GList *file_list,
+ char **tags)
+{
+ GthTagTask *self;
+
+ self = GTH_TAG_TASK (g_object_new (GTH_TYPE_TAG_TASK, NULL));
+ self->priv->file_list = _g_object_list_ref (file_list);
+ self->priv->tags = gth_string_list_new_from_strv (tags);
+
+ return (GthTask *) self;
+}
diff --git a/extensions/edit_metadata/gth-tag-task.h b/extensions/edit_metadata/gth-tag-task.h
new file mode 100644
index 0000000..71c7441
--- /dev/null
+++ b/extensions/edit_metadata/gth-tag-task.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2010 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 GTH_TAG_TASK_H
+#define GTH_TAG_TASK_H
+
+#include <glib.h>
+#include <gthumb.h>
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_TAG_TASK (gth_tag_task_get_type ())
+#define GTH_TAG_TASK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_TAG_TASK, GthTagTask))
+#define GTH_TAG_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_TAG_TASK, GthTagTaskClass))
+#define GTH_IS_TAG_TASK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_TAG_TASK))
+#define GTH_IS_TAG_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_TAG_TASK))
+#define GTH_TAG_TASK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTH_TYPE_TAG_TASK, GthTagTaskClass))
+
+typedef struct _GthTagTask GthTagTask;
+typedef struct _GthTagTaskClass GthTagTaskClass;
+typedef struct _GthTagTaskPrivate GthTagTaskPrivate;
+
+struct _GthTagTask {
+ GthTask __parent;
+ GthTagTaskPrivate *priv;
+};
+
+struct _GthTagTaskClass {
+ GthTaskClass __parent;
+};
+
+GType gth_tag_task_get_type (void);
+GthTask * gth_tag_task_new (GList *files, /* GFile */
+ char **tags);
+
+G_END_DECLS
+
+#endif /* GTH_TAG_TASK_H */
diff --git a/extensions/edit_metadata/main.c b/extensions/edit_metadata/main.c
index 972bf3a..e3bd1c3 100644
--- a/extensions/edit_metadata/main.c
+++ b/extensions/edit_metadata/main.c
@@ -35,7 +35,8 @@ gthumb_extension_activate (void)
gth_hook_add_callback ("gth-browser-construct", 5, G_CALLBACK (edit_metadata__gth_browser_construct_cb), NULL);
gth_hook_add_callback ("gth-browser-set-current-page", 5, G_CALLBACK (edit_metadata__gth_browser_set_current_page_cb), NULL);
gth_hook_add_callback ("gth-browser-update-sensitivity", 10, G_CALLBACK (edit_metadata__gth_browser_update_sensitivity_cb), NULL);
-
+ gth_hook_add_callback ("gth-browser-file-list-popup-before", 5, G_CALLBACK (edit_metadata__gth_browser_file_list_popup_before_cb), NULL);
+ gth_hook_add_callback ("gth-browser-file-popup-before", 5, G_CALLBACK (edit_metadata__gth_browser_file_popup_before_cb), NULL);
}
diff --git a/gthumb/gth-main.c b/gthumb/gth-main.c
index ffee3a5..59bbeb1 100644
--- a/gthumb/gth-main.c
+++ b/gthumb/gth-main.c
@@ -1151,10 +1151,9 @@ gth_main_tags_changed (void)
gth_user_dir_make_dir_for_file (GTH_DIR_CONFIG, GTHUMB_DIR, TAGS_FILE, NULL);
filename = gth_user_dir_get_file (GTH_DIR_CONFIG, GTHUMB_DIR, TAGS_FILE, NULL);
gth_tags_file_to_file (Main->priv->tags, filename, NULL);
+ gth_monitor_tags_changed (gth_main_get_default_monitor ());
g_free (filename);
-
- gth_monitor_tags_changed (gth_main_get_default_monitor ());
}
diff --git a/gthumb/gth-string-list.c b/gthumb/gth-string-list.c
index d17b33d..e159403 100644
--- a/gthumb/gth-string-list.c
+++ b/gthumb/gth-string-list.c
@@ -182,3 +182,15 @@ gth_string_list_equal (GthStringList *list1,
return TRUE;
}
+
+
+void
+gth_string_list_append (GthStringList *list1,
+ GthStringList *list2)
+{
+ GList *scan;
+
+ for (scan = list2->priv->list; scan; scan = scan->next)
+ if (! g_list_find_custom (list1->priv->list, scan->data, (GCompareFunc) strcmp))
+ list1->priv->list = g_list_append (list1->priv->list, g_strdup (scan->data));
+}
diff --git a/gthumb/gth-string-list.h b/gthumb/gth-string-list.h
index 125c63a..fa36441 100644
--- a/gthumb/gth-string-list.h
+++ b/gthumb/gth-string-list.h
@@ -57,6 +57,8 @@ char * gth_string_list_join (GthStringList *list,
const char *separator);
gboolean gth_string_list_equal (GthStringList *list1,
GthStringList *list2);
+void gth_string_list_append (GthStringList *list1,
+ GthStringList *list2);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]