[gthumb] Added missing files, oops
- From: Michael J. Chudobiak <mjc src gnome org>
- To: svn-commits-list gnome org
- Subject: [gthumb] Added missing files, oops
- Date: Tue, 19 May 2009 07:31:52 -0400 (EDT)
commit 621a80d3468817176f072546b9f166305c16a2db
Author: Michael J. Chudobiak <mjc avtechpulse com>
Date: Tue May 19 07:31:36 2009 -0400
Added missing files, oops
---
src/dlg-tags.c | 901 ++++++++++++++++++++++++++++++++++++++++
src/dlg-tags.h | 40 ++
src/gth-tag-selection-dialog.c | 479 +++++++++++++++++++++
src/gth-tag-selection-dialog.h | 62 +++
4 files changed, 1482 insertions(+), 0 deletions(-)
diff --git a/src/dlg-tags.c b/src/dlg-tags.c
new file mode 100644
index 0000000..4b0ebc3
--- /dev/null
+++ b/src/dlg-tags.c
@@ -0,0 +1,901 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2001, 2003, 2004 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 <string.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <libgnomeui/gnome-help.h>
+#include <glade/glade.h>
+
+#include "typedefs.h"
+#include "file-utils.h"
+#include "preferences.h"
+#include "main.h"
+#include "gth-utils.h"
+#include "gth-window.h"
+#include "gtk-utils.h"
+#include "gtkcellrendererthreestates.h"
+#include "gth-file-view.h"
+#include "comments.h"
+#include "dlg-tags.h"
+
+
+typedef void (*SaveFunc) (GList *file_list, gpointer data);
+
+
+#define DIALOG_NAME "tags"
+#define GLADE_FILE "gthumb_comments.glade"
+#define TAG_SEPARATOR ";"
+
+
+enum {
+ IS_EDITABLE_COLUMN,
+ HAS_THIRD_STATE_COLUMN,
+ USE_TAG_COLUMN,
+ TAG_COLUMN,
+ NUM_COLUMNS
+};
+
+
+typedef struct {
+ GladeXML *gui;
+ GList *file_list;
+ GList *default_tags_list;
+ GList **add_list;
+ GList **remove_list;
+ SaveFunc save_func;
+ gpointer save_data;
+ DoneFunc done_func;
+ gpointer done_data;
+
+ GthWindow *window;
+ GtkWidget *dialog;
+
+ GtkWidget *c_ok_button;
+ GtkWidget *keyword_entry;
+ GtkWidget *add_key_button;
+ GtkWidget *remove_key_button;
+ GtkWidget *keywords_list_view;
+ GtkListStore *keywords_list_model;
+
+ CommentData *original_cdata;
+} DialogData;
+
+
+
+static void
+free_dialog_data (DialogData *data)
+{
+ if (data->file_list != NULL) {
+ g_list_foreach (data->file_list, (GFunc) g_free, NULL);
+ g_list_free (data->file_list);
+ data->file_list = NULL;
+ }
+
+ if (data->original_cdata != NULL) {
+ comment_data_free (data->original_cdata);
+ data->original_cdata = NULL;
+ }
+}
+
+
+/* called when the main dialog is closed. */
+static void
+destroy_cb (GtkWidget *widget,
+ DialogData *data)
+{
+ if (data->window != NULL)
+ gth_window_set_tags_dlg (data->window, NULL);
+
+ g_object_unref (data->gui);
+ free_dialog_data (data);
+ path_list_free (data->default_tags_list);
+
+ if (data->done_func)
+ (*data->done_func) (data->done_data);
+
+ g_free (data);
+}
+
+
+static gboolean
+unrealize_cb (GtkWidget *widget,
+ DialogData *data)
+{
+ pref_util_save_window_geometry (GTK_WINDOW (widget), DIALOG_NAME);
+ return FALSE;
+}
+
+
+static void
+update_tag_entry (DialogData *data)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model = GTK_TREE_MODEL (data->keywords_list_model);
+ GString *tags;
+
+ if (! gtk_tree_model_get_iter_first (model, &iter)) {
+ gtk_entry_set_text (GTK_ENTRY (data->keyword_entry), "");
+ return;
+ }
+
+ tags = g_string_new (NULL);
+ do {
+ guint use_tag;
+ gtk_tree_model_get (model, &iter, USE_TAG_COLUMN, &use_tag, -1);
+ if (use_tag == 1) {
+ char *utf8_name;
+
+ gtk_tree_model_get (model, &iter,
+ TAG_COLUMN, &utf8_name,
+ -1);
+
+ if (tags->len > 0)
+ tags = g_string_append (tags, TAG_SEPARATOR " ");
+ tags = g_string_append (tags, utf8_name);
+
+ g_free (utf8_name);
+ }
+ } while (gtk_tree_model_iter_next (model, &iter));
+
+ gtk_entry_set_text (GTK_ENTRY (data->keyword_entry), tags->str);
+ g_string_free (tags, TRUE);
+}
+
+
+/* if state_to_get == -1 get all tags. */
+static GList *
+get_tags (GtkListStore *store,
+ guint state_to_get)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL (store);
+ GList *list = NULL;
+ GtkTreeIter iter;
+
+ if (! gtk_tree_model_get_iter_first (model, &iter))
+ return NULL;
+
+ do {
+ guint state;
+ char *utf8_name;
+
+ gtk_tree_model_get (model,
+ &iter,
+ USE_TAG_COLUMN, &state,
+ TAG_COLUMN, &utf8_name,
+ -1);
+ if ((state_to_get == -1) || (state == state_to_get))
+ list = g_list_prepend (list, utf8_name);
+ else
+ g_free (utf8_name);
+
+ } while (gtk_tree_model_iter_next (model, &iter));
+
+ return g_list_reverse (list);
+}
+
+
+static gboolean
+tag_present (DialogData *data,
+ char *tag)
+{
+ GList *all_tags;
+ GList *scan;
+ gboolean present = FALSE;
+
+ all_tags = get_tags (data->keywords_list_model, -1);
+ for (scan = all_tags; scan; scan = scan->next) {
+ char *tag2 = scan->data;
+ if (strcmp (tag2, tag) == 0)
+ present = TRUE;
+ }
+ path_list_free (all_tags);
+
+ return present;
+}
+
+
+static gboolean
+tag_name_is_valid (const char *name)
+{
+ gboolean valid = TRUE;
+ if (strchr (name, ',') != NULL)
+ valid = FALSE;
+ return valid;
+}
+
+
+/* called when the "add tag" button is pressed. */
+static void
+add_tag_cb (GtkWidget *widget,
+ DialogData *data)
+{
+ GtkTreeIter iter;
+ char *new_tag;
+
+ new_tag = _gtk_request_dialog_run (GTK_WINDOW (data->dialog),
+ GTK_DIALOG_MODAL,
+ _("Enter the new tag name"),
+ "",
+ 1024,
+ GTK_STOCK_CANCEL,
+ _("C_reate"));
+
+ if (new_tag == NULL)
+ return;
+
+ if (! tag_name_is_valid (new_tag)) {
+ _gtk_error_dialog_run (GTK_WINDOW (data->dialog),
+ _("The name \"%s\" is not valid because it contains the character \",\". " "Please use a different name."),
+ new_tag);
+
+ } else if (tag_present (data, new_tag)) {
+ _gtk_error_dialog_run (GTK_WINDOW (data->dialog),
+ _("The tag \"%s\" is already present. Please use a different name."),
+ new_tag);
+
+ } else {
+ gtk_list_store_append (data->keywords_list_model, &iter);
+ gtk_list_store_set (data->keywords_list_model, &iter,
+ IS_EDITABLE_COLUMN, TRUE,
+ USE_TAG_COLUMN, 1,
+ TAG_COLUMN, new_tag,
+ -1);
+ update_tag_entry (data);
+ }
+
+ g_free (new_tag);
+}
+
+
+/* called when the "remove tag" button is pressed. */
+static void
+remove_tag_cb (GtkWidget *widget,
+ DialogData *data)
+{
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->keywords_list_view));
+ if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
+ return;
+
+ gtk_list_store_remove (data->keywords_list_model, &iter);
+ update_tag_entry (data);
+}
+
+
+static void
+save_tags (DialogData *data)
+{
+ Bookmarks *tags;
+ GList *scan;
+ GList *cat_list;
+
+ cat_list = get_tags (data->keywords_list_model, -1);
+ tags = bookmarks_new (RC_TAGS_FILE);
+ bookmarks_set_max_lines (tags, -1);
+
+ for (scan = cat_list; scan; scan = scan->next) {
+ char *tag = scan->data;
+ bookmarks_add (tags, tag, TRUE, TRUE);
+ }
+
+ bookmarks_write_to_disk (tags);
+
+ path_list_free (cat_list);
+ bookmarks_free (tags);
+}
+
+
+/* called when the "cancel" button is pressed. */
+static void
+cancel_clicked_cb (GtkWidget *widget,
+ DialogData *data)
+{
+ save_tags (data);
+ gtk_widget_destroy (data->dialog);
+}
+
+
+/* called when the "ok" button is pressed. */
+static void
+ok_clicked_cb (GtkWidget *widget,
+ DialogData *data)
+{
+ save_tags (data);
+
+ if (data->add_list != NULL) {
+ if (*(data->add_list) != NULL)
+ path_list_free (*(data->add_list));
+ *(data->add_list) = get_tags (data->keywords_list_model, 1);
+ }
+
+ if (data->remove_list != NULL) {
+ if (*(data->remove_list) != NULL)
+ path_list_free (*(data->remove_list));
+ *(data->remove_list) = get_tags (data->keywords_list_model, 0);
+ }
+
+ if (data->save_func) {
+ (*data->save_func) (data->file_list, data->save_data);
+ if (data->window != NULL) {
+ gth_window_update_current_image_metadata (data->window);
+ dlg_tags_close (data->dialog);
+ }
+ } else
+ gtk_widget_destroy (data->dialog);
+}
+
+
+/* called when the "help" button in the search dialog is pressed. */
+static void
+help_cb (GtkWidget *widget,
+ DialogData *data)
+{
+ gthumb_display_help (GTK_WINDOW (data->dialog), "gthumb-tags");
+}
+
+
+static void
+use_tag_toggled (GtkCellRendererThreeStates *cell,
+ gchar *path_string,
+ gpointer callback_data)
+{
+ DialogData *data = callback_data;
+ GtkTreeModel *model = GTK_TREE_MODEL (data->keywords_list_model);
+ GtkTreeIter iter;
+ GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
+ guint value;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ value = gtk_cell_renderer_three_states_get_next_state (cell);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, USE_TAG_COLUMN, value, -1);
+
+ gtk_tree_path_free (path);
+ update_tag_entry (data);
+}
+
+
+static void
+add_saved_tags (DialogData *data)
+{
+ Bookmarks *tags;
+ GList *scan;
+ GList *cat_list;
+
+ cat_list = get_tags (data->keywords_list_model, -1);
+ tags = bookmarks_new (RC_TAGS_FILE);
+ bookmarks_load_from_disk (tags);
+
+ for (scan = tags->list; scan; scan = scan->next) {
+ GtkTreeIter iter;
+ GList *scan2;
+ gboolean found = FALSE;
+ char *tag1 = scan->data;
+
+ for (scan2 = cat_list; scan2 && !found; scan2 = scan2->next) {
+ char *tag2 = scan2->data;
+ if (strcmp (tag1, tag2) == 0)
+ found = TRUE;
+ }
+
+ if (found)
+ continue;
+
+ gtk_list_store_append (data->keywords_list_model, &iter);
+
+ gtk_list_store_set (data->keywords_list_model, &iter,
+ IS_EDITABLE_COLUMN, FALSE,
+ USE_TAG_COLUMN, 0,
+ TAG_COLUMN, tag1,
+ -1);
+ }
+
+ bookmarks_free (tags);
+ path_list_free (cat_list);
+}
+
+
+static gboolean
+key_in_list (GList *list,
+ const char *key)
+{
+ GList *scan;
+
+ for (scan = list; scan; scan = scan->next)
+ if (strcmp (scan->data, key) == 0)
+ return TRUE;
+ return FALSE;
+}
+
+
+static int
+name_column_sort_func (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ char *tag1, *tag2;
+ int result;
+
+ gtk_tree_model_get (model, a, TAG_COLUMN, &tag1, -1);
+ gtk_tree_model_get (model, b, TAG_COLUMN, &tag2, -1);
+
+ result = g_utf8_collate (tag1, tag2);
+
+ g_free (tag1);
+ g_free (tag2);
+
+ return result;
+}
+
+
+static gboolean
+keyword_equal_func (GtkTreeModel *model,
+ gint column,
+ const gchar *key,
+ GtkTreeIter *iter,
+ gpointer search_data)
+{
+ char *cell;
+ gtk_tree_model_get (model, iter, column, &cell, -1);
+ return g_strcasecmp (key, cell) > 0;
+}
+
+
+static GtkWidget*
+dlg_tags_common (GtkWindow *parent,
+ GthWindow *window,
+ GList *file_list,
+ GList *default_tags_list,
+ GList **add_tags_list,
+ GList **remove_tags_list,
+ SaveFunc save_func,
+ gpointer save_data,
+ DoneFunc done_func,
+ gpointer done_data,
+ gboolean modal)
+{
+ DialogData *data;
+ GtkWidget *btn_ok;
+ GtkWidget *btn_cancel;
+ GtkWidget *btn_help;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+
+
+ data = g_new (DialogData, 1);
+
+ data->window = window;
+ data->default_tags_list = path_list_dup (default_tags_list);
+ data->add_list = add_tags_list;
+ data->remove_list = remove_tags_list;
+ data->save_func = save_func;
+ data->save_data = save_data;
+ data->done_func = done_func;
+ data->done_data = done_data;
+ data->original_cdata = NULL;
+
+ data->gui = glade_xml_new (GTHUMB_GLADEDIR "/" GLADE_FILE , NULL, NULL);
+ if (!data->gui) {
+ g_free (data);
+ g_warning ("Could not find " GLADE_FILE "\n");
+ return NULL;
+ }
+
+ if (file_list != NULL)
+ data->file_list = path_list_dup (file_list);
+ else
+ data->file_list = NULL;
+
+ /* Get the widgets. */
+
+ data->dialog = glade_xml_get_widget (data->gui, "tags_dialog");
+
+ data->keyword_entry = glade_xml_get_widget (data->gui, "c_keyword_entry");
+ data->add_key_button = glade_xml_get_widget (data->gui, "c_add_key_button");
+ data->remove_key_button = glade_xml_get_widget (data->gui, "c_remove_key_button");
+ data->keywords_list_view = glade_xml_get_widget (data->gui, "c_keywords_treeview");
+
+ data->c_ok_button = btn_ok = glade_xml_get_widget (data->gui, "c_ok_button");
+ btn_cancel = glade_xml_get_widget (data->gui, "c_cancel_button");
+ btn_help = glade_xml_get_widget (data->gui, "c_help_button");
+
+ /* Set widgets data. */
+
+ g_object_set_data (G_OBJECT (data->dialog), "dialog_data", data);
+
+ data->keywords_list_model = gtk_list_store_new (NUM_COLUMNS,
+ G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN,
+ G_TYPE_UINT,
+ G_TYPE_STRING);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (data->keywords_list_view),
+ GTK_TREE_MODEL (data->keywords_list_model));
+ g_object_unref (data->keywords_list_model);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (data->keywords_list_view), FALSE);
+
+ gtk_tree_view_set_search_column (GTK_TREE_VIEW (data->keywords_list_view),
+ TAG_COLUMN);
+ gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (data->keywords_list_view),
+ keyword_equal_func,
+ NULL,
+ NULL);
+
+ column = gtk_tree_view_column_new ();
+
+ renderer = gtk_cell_renderer_three_states_new ();
+ g_signal_connect (G_OBJECT (renderer),
+ "toggled",
+ G_CALLBACK (use_tag_toggled),
+ data);
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "state", USE_TAG_COLUMN,
+ "has_third_state", HAS_THIRD_STATE_COLUMN,
+ NULL);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "text", TAG_COLUMN,
+ "editable", IS_EDITABLE_COLUMN,
+ NULL);
+
+ gtk_tree_view_column_set_sort_column_id (column, 0);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (data->keywords_list_view),
+ column);
+
+ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (data->keywords_list_model), name_column_sort_func, NULL, NULL);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (data->keywords_list_model), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
+
+ /* Set the signals handlers. */
+
+ g_signal_connect (G_OBJECT (data->dialog),
+ "destroy",
+ G_CALLBACK (destroy_cb),
+ data);
+ g_signal_connect (G_OBJECT (data->dialog),
+ "unrealize",
+ G_CALLBACK (unrealize_cb),
+ data);
+ g_signal_connect (G_OBJECT (btn_ok),
+ "clicked",
+ G_CALLBACK (ok_clicked_cb),
+ data);
+ g_signal_connect (G_OBJECT (btn_cancel),
+ "clicked",
+ G_CALLBACK (cancel_clicked_cb),
+ data);
+ g_signal_connect (G_OBJECT (btn_help),
+ "clicked",
+ G_CALLBACK (help_cb),
+ data);
+
+ g_signal_connect (G_OBJECT (data->add_key_button),
+ "clicked",
+ G_CALLBACK (add_tag_cb),
+ data);
+ g_signal_connect (G_OBJECT (data->remove_key_button),
+ "clicked",
+ G_CALLBACK (remove_tag_cb),
+ data);
+
+ /* run dialog. */
+
+ if (parent != NULL)
+ gtk_window_set_transient_for (GTK_WINDOW (data->dialog), parent);
+
+ gtk_window_set_modal (GTK_WINDOW (data->dialog), modal);
+ pref_util_restore_window_geometry (GTK_WINDOW (data->dialog), DIALOG_NAME);
+ dlg_tags_update (data->dialog);
+
+ gtk_widget_grab_focus (data->keywords_list_view);
+
+ return data->dialog;
+}
+
+
+/**/
+
+
+void
+dlg_choose_tags (GtkWindow *parent,
+ GList *file_list,
+ GList *default_tags_list,
+ GList **add_tags_list,
+ GList **remove_tags_list,
+ DoneFunc done_func,
+ gpointer done_data)
+{
+ dlg_tags_common (parent,
+ NULL,
+ file_list,
+ default_tags_list,
+ add_tags_list,
+ remove_tags_list,
+ NULL,
+ NULL,
+ done_func,
+ done_data,
+ TRUE);
+}
+
+
+/**/
+
+
+typedef struct {
+ GthWindow *window;
+ GList *add_list;
+ GList *remove_list;
+} DlgTagsData;
+
+
+static void
+dlg_tags__done (gpointer data)
+{
+ DlgTagsData *dcdata = data;
+
+ path_list_free (dcdata->add_list);
+ dcdata->add_list = NULL;
+
+ path_list_free (dcdata->remove_list);
+ dcdata->remove_list = NULL;
+
+ g_free (dcdata);
+}
+
+
+static void
+dlg_tags__save (GList *file_list,
+ gpointer data)
+{
+ DlgTagsData *dcdata = data;
+ GList *scan;
+
+ for (scan = file_list; scan; scan = scan->next) {
+ const char *filename = scan->data;
+ CommentData *cdata;
+ GList *scan2;
+
+ cdata = comments_load_comment (filename, TRUE);
+ if (cdata == NULL)
+ cdata = comment_data_new ();
+ else
+ for (scan2 = dcdata->remove_list; scan2; scan2 = scan2->next) {
+ const char *k = scan2->data;
+ comment_data_remove_keyword (cdata, k);
+ }
+
+ for (scan2 = dcdata->add_list; scan2; scan2 = scan2->next) {
+ const char *k = scan2->data;
+ comment_data_add_keyword (cdata, k);
+ }
+
+ comments_save_tags (filename, cdata);
+ comment_data_free (cdata);
+ }
+
+ path_list_free (dcdata->add_list);
+ dcdata->add_list = NULL;
+
+ path_list_free (dcdata->remove_list);
+ dcdata->remove_list = NULL;
+}
+
+
+GtkWidget*
+dlg_tags_new (GthWindow *window)
+{
+ GtkWidget *current_dlg;
+ DlgTagsData *dcdata;
+
+ current_dlg = gth_window_get_tags_dlg (window);
+ if (current_dlg != NULL) {
+ gtk_window_present (GTK_WINDOW (current_dlg));
+ return current_dlg;
+ }
+
+ dcdata = g_new0 (DlgTagsData, 1);
+ dcdata->window = window;
+ dcdata->add_list = NULL;
+ dcdata->remove_list = NULL;
+
+ return dlg_tags_common (GTK_WINDOW (window),
+ window,
+ NULL,
+ NULL,
+ &(dcdata->add_list),
+ &(dcdata->remove_list),
+ dlg_tags__save,
+ dcdata,
+ dlg_tags__done,
+ dcdata,
+ FALSE);
+}
+
+
+void
+dlg_tags_update (GtkWidget *dlg)
+{
+ DialogData *data;
+ CommentData *cdata = NULL;
+ GList *scan;
+ GList *other_keys = NULL;
+ GSList *tmp1, *tmp2;
+
+
+ g_return_if_fail (dlg != NULL);
+
+ data = g_object_get_data (G_OBJECT (dlg), "dialog_data");
+ g_return_if_fail (data != NULL);
+
+ gtk_list_store_clear (data->keywords_list_model);
+
+ /**/
+
+ if (data->window != NULL) {
+ free_dialog_data (data);
+ data->file_list = gth_window_get_file_list_selection (data->window);
+ } else if (data->original_cdata != NULL) {
+ comment_data_free (data->original_cdata);
+ data->original_cdata = NULL;
+ }
+
+ if (data->file_list != NULL) {
+ char *first_image = data->file_list->data;
+ data->original_cdata = cdata = comments_load_comment (first_image, TRUE);
+ }
+
+ if (cdata != NULL) {
+ comment_data_free_comment (cdata);
+
+ /* remove a tag if it is not in all comments. */
+ for (scan = data->file_list->next; scan; scan = scan->next) {
+ CommentData *scan_cdata;
+
+ scan_cdata = comments_load_comment (scan->data, TRUE);
+
+ if (scan_cdata == NULL) {
+ comment_data_free_keywords (cdata);
+ break;
+ }
+
+ for (tmp1 = cdata->keywords; tmp1; tmp1 = g_slist_next (tmp1)) {
+ char *k1 = tmp1->data;
+ gboolean found = FALSE;
+
+ for (tmp2 = scan_cdata->keywords; tmp2; tmp2 = g_slist_next (tmp2)) {
+ char *k2 = tmp2->data;
+ if (strcmp (k1, k2) == 0) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ comment_data_remove_keyword (cdata, k1);
+ }
+
+ comment_data_free (scan_cdata);
+ }
+ }
+
+ for (scan = data->file_list; scan; scan = scan->next) {
+ CommentData *scan_cdata;
+
+ scan_cdata = comments_load_comment (scan->data, TRUE);
+
+ if (scan_cdata == NULL)
+ continue;
+
+ for (tmp2 = scan_cdata->keywords; tmp2; tmp2 = g_slist_next (tmp2)) {
+ char *k2 = tmp2->data;
+ gboolean found = FALSE;
+
+ if (cdata != NULL)
+ for (tmp1 = cdata->keywords; tmp1; tmp1 = g_slist_next (tmp1)) {
+ char *k1 = tmp1->data;
+ if (strcmp (k1, k2) == 0) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (! found && ! key_in_list (other_keys, k2))
+ other_keys = g_list_prepend (other_keys,
+ g_strdup (k2));
+ }
+ comment_data_free (scan_cdata);
+ }
+
+ if (cdata != NULL) {
+ for (tmp1 = cdata->keywords; tmp1; tmp1 = g_slist_next (tmp1)) {
+ GtkTreeIter iter;
+
+ gtk_list_store_append (data->keywords_list_model,
+ &iter);
+
+ gtk_list_store_set (data->keywords_list_model, &iter,
+ IS_EDITABLE_COLUMN, FALSE,
+ HAS_THIRD_STATE_COLUMN, FALSE,
+ USE_TAG_COLUMN, 1,
+ TAG_COLUMN, tmp1->data,
+ -1);
+ }
+ }
+
+ for (scan = data->default_tags_list; scan; scan = scan->next) {
+ char *keyword = scan->data;
+ GtkTreeIter iter;
+
+ gtk_list_store_append (data->keywords_list_model,
+ &iter);
+
+ gtk_list_store_set (data->keywords_list_model, &iter,
+ IS_EDITABLE_COLUMN, FALSE,
+ HAS_THIRD_STATE_COLUMN, FALSE,
+ USE_TAG_COLUMN, 1,
+ TAG_COLUMN, keyword,
+ -1);
+ }
+
+ for (scan = other_keys; scan; scan = scan->next) {
+ char *keyword = scan->data;
+ GtkTreeIter iter;
+
+ gtk_list_store_append (data->keywords_list_model,
+ &iter);
+
+ gtk_list_store_set (data->keywords_list_model, &iter,
+ IS_EDITABLE_COLUMN, FALSE,
+ HAS_THIRD_STATE_COLUMN, TRUE,
+ USE_TAG_COLUMN, 2,
+ TAG_COLUMN, keyword,
+ -1);
+ }
+
+ if (other_keys != NULL)
+ path_list_free (other_keys);
+
+ add_saved_tags (data);
+ update_tag_entry (data);
+}
+
+
+void
+dlg_tags_close (GtkWidget *dlg)
+{
+ DialogData *data;
+
+ g_return_if_fail (dlg != NULL);
+
+ data = g_object_get_data (G_OBJECT (dlg), "dialog_data");
+ g_return_if_fail (data != NULL);
+
+ gtk_widget_destroy (dlg);
+}
diff --git a/src/dlg-tags.h b/src/dlg-tags.h
new file mode 100644
index 0000000..ffd7c8c
--- /dev/null
+++ b/src/dlg-tags.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2001 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_TAGS_H
+#define DLG_TAGS_H
+
+#include "typedefs.h"
+#include "gth-window.h"
+
+void dlg_choose_tags (GtkWindow *parent,
+ GList *file_list,
+ GList *default_tags_list,
+ GList **add_tags_list,
+ GList **remove_tags_list,
+ DoneFunc done_func,
+ gpointer done_data);
+GtkWidget* dlg_tags_new (GthWindow *window);
+void dlg_tags_update (GtkWidget *dlg);
+void dlg_tags_close (GtkWidget *dlg);
+
+#endif /* DLG_TAGS_H */
diff --git a/src/gth-tag-selection-dialog.c b/src/gth-tag-selection-dialog.c
new file mode 100644
index 0000000..5508435
--- /dev/null
+++ b/src/gth-tag-selection-dialog.c
@@ -0,0 +1,479 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2007 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 <string.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include "typedefs.h"
+#include "glib-utils.h"
+#include "file-utils.h"
+#include "bookmarks.h"
+#include "gth-tag-selection-dialog.h"
+
+enum {
+ RESPONSE,
+ LAST_SIGNAL
+};
+
+
+enum {
+ C_USE_TAG_COLUMN,
+ C_TAG_COLUMN,
+ C_NUM_COLUMNS
+};
+
+
+#define TAG_SEPARATOR_C ';'
+#define TAG_SEPARATOR_STR ";"
+#define SEARCH_GLADE_FILE "gthumb_search.glade"
+#define DEFAULT_DIALOG_WIDTH 540
+#define DEFAULT_DIALOG_HEIGHT 480
+
+
+struct _GthTagSelectionPrivate
+{
+ char *tags;
+ gboolean match_all;
+ gboolean ok_clicked;
+
+ GladeXML *gui;
+
+ GtkWidget *dialog;
+ GtkWidget *c_tags_entry;
+ GtkWidget *c_tags_treeview;
+ GtkWidget *c_ok_button;
+ GtkWidget *c_cancel_button;
+ GtkWidget *s_at_least_one_cat_radiobutton;
+ GtkWidget *s_all_cat_radiobutton;
+
+ GtkListStore *c_tags_list_model;
+};
+
+
+static GObjectClass *parent_class = NULL;
+static guint signals[LAST_SIGNAL] = { 0 };
+
+
+static void
+gth_tag_selection_finalize (GObject *object)
+{
+ GthTagSelection *tag_sel;
+
+ tag_sel = GTH_TAG_SELECTION (object);
+
+ if (tag_sel->priv != NULL) {
+
+ if (tag_sel->priv->dialog != NULL)
+ g_signal_handlers_disconnect_by_data (tag_sel->priv->dialog, tag_sel);
+
+ g_free (tag_sel->priv->tags);
+ tag_sel->priv->tags = NULL;
+
+ if (tag_sel->priv->gui != NULL) {
+ g_object_unref (tag_sel->priv->gui);
+ tag_sel->priv->gui = NULL;
+ }
+
+ g_free (tag_sel->priv);
+ tag_sel->priv = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gth_tag_selection_class_init (GthTagSelectionClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ object_class = (GObjectClass*) class;
+
+ object_class->finalize = gth_tag_selection_finalize;
+
+ signals[RESPONSE] =
+ g_signal_new ("response",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GthTagSelectionClass, response),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE,
+ 1, G_TYPE_INT);
+}
+
+
+static void
+gth_tag_selection_init (GthTagSelection *tag_sel)
+{
+ tag_sel->priv = g_new0 (GthTagSelectionPrivate, 1);
+}
+
+
+static void
+update_tag_entry (GthTagSelection *tag_sel)
+{
+ GthTagSelectionPrivate *priv = tag_sel->priv;
+ GtkTreeIter iter;
+ GtkTreeModel *model = GTK_TREE_MODEL (priv->c_tags_list_model);
+ GString *tags;
+
+ if (! gtk_tree_model_get_iter_first (model, &iter)) {
+ gtk_entry_set_text (GTK_ENTRY (priv->c_tags_entry), "");
+ return;
+ }
+
+ tags = g_string_new (NULL);
+ do {
+ gboolean use_tag;
+ gtk_tree_model_get (model, &iter, C_USE_TAG_COLUMN, &use_tag, -1);
+ if (use_tag) {
+ char *tag_name;
+
+ gtk_tree_model_get (model, &iter,
+ C_TAG_COLUMN, &tag_name,
+ -1);
+ if (tags->len > 0)
+ tags = g_string_append (tags, TAG_SEPARATOR_STR " ");
+ tags = g_string_append (tags, tag_name);
+ g_free (tag_name);
+ }
+ } while (gtk_tree_model_iter_next (model, &iter));
+
+ gtk_entry_set_text (GTK_ENTRY (priv->c_tags_entry), tags->str);
+ g_string_free (tags, TRUE);
+}
+
+
+static GList *
+get_tags_from_entry (GthTagSelection *tag_sel)
+{
+ GthTagSelectionPrivate *priv = tag_sel->priv;
+ GList *cat_list = NULL;
+ const char *utf8_text;
+ char **tags;
+ int i;
+
+ utf8_text = gtk_entry_get_text (GTK_ENTRY (priv->c_tags_entry));
+ if (utf8_text == NULL)
+ return NULL;
+
+ tags = _g_utf8_strsplit (utf8_text, TAG_SEPARATOR_C);
+
+ for (i = 0; tags[i] != NULL; i++) {
+ char *s;
+
+ s = _g_utf8_strstrip (tags[i]);
+
+ if (s != NULL)
+ cat_list = g_list_prepend (cat_list, s);
+ }
+ g_strfreev (tags);
+
+ return g_list_reverse (cat_list);
+}
+
+
+static void
+add_saved_tags (GthTagSelection *tag_sel,
+ GList *cat_list)
+{
+ GthTagSelectionPrivate *priv = tag_sel->priv;
+ Bookmarks *tags;
+ GList *scan;
+
+ tags = bookmarks_new (RC_TAGS_FILE);
+ bookmarks_load_from_disk (tags);
+
+ for (scan = tags->list; scan; scan = scan->next) {
+ GtkTreeIter iter;
+ GList *scan2;
+ gboolean found = FALSE;
+ char *tag1 = scan->data;
+
+ for (scan2 = cat_list; scan2 && !found; scan2 = scan2->next) {
+ char *tag2 = scan2->data;
+ if (strcmp (tag1, tag2) == 0)
+ found = TRUE;
+ }
+
+ if (found)
+ continue;
+
+ gtk_list_store_append (priv->c_tags_list_model, &iter);
+
+ gtk_list_store_set (priv->c_tags_list_model, &iter,
+ C_USE_TAG_COLUMN, FALSE,
+ C_TAG_COLUMN, tag1,
+ -1);
+ }
+
+ bookmarks_free (tags);
+}
+
+
+static void
+update_list_from_entry (GthTagSelection *tag_sel)
+{
+ GthTagSelectionPrivate *priv = tag_sel->priv;
+ GList *tags = NULL;
+ GList *scan;
+
+ tags = get_tags_from_entry (tag_sel);
+
+ gtk_list_store_clear (priv->c_tags_list_model);
+ for (scan = tags; scan; scan = scan->next) {
+ char *tag = scan->data;
+ GtkTreeIter iter;
+
+ gtk_list_store_append (priv->c_tags_list_model, &iter);
+
+ gtk_list_store_set (priv->c_tags_list_model, &iter,
+ C_USE_TAG_COLUMN, TRUE,
+ C_TAG_COLUMN, tag,
+ -1);
+ }
+ add_saved_tags (tag_sel, tags);
+ path_list_free (tags);
+}
+
+
+static void
+use_tag_toggled (GtkCellRendererToggle *cell,
+ gchar *path_string,
+ gpointer callback_data)
+{
+ GthTagSelection *tag_sel = callback_data;
+ GthTagSelectionPrivate *priv = tag_sel->priv;
+ GtkTreeModel *model = GTK_TREE_MODEL (priv->c_tags_list_model);
+ GtkTreeIter iter;
+ GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
+ gboolean value;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, C_USE_TAG_COLUMN, &value, -1);
+
+ value = !value;
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, C_USE_TAG_COLUMN, value, -1);
+
+ gtk_tree_path_free (path);
+ update_tag_entry (tag_sel);
+}
+
+
+static void
+choose_tags_ok_cb (GtkWidget *widget,
+ GthTagSelection *tag_sel)
+{
+ GthTagSelectionPrivate *priv = tag_sel->priv;
+
+ priv->ok_clicked = TRUE;
+
+ g_free (priv->tags);
+ priv->tags = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->c_tags_entry)));
+ priv->match_all = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->s_all_cat_radiobutton));
+
+ gtk_widget_destroy (priv->dialog);
+ priv->dialog = NULL;
+
+ g_signal_emit (tag_sel, signals[RESPONSE], 0, GTK_RESPONSE_OK);
+}
+
+
+static gboolean
+tags_dialog__destroy_cb (GtkWidget *widget,
+ GthTagSelection *tag_sel)
+{
+ tag_sel->priv->dialog = NULL;
+
+ return FALSE;
+
+ if (! tag_sel->priv->ok_clicked) {
+ g_object_ref (tag_sel);
+ g_signal_emit (tag_sel, signals[RESPONSE], 0, GTK_RESPONSE_CANCEL);
+ g_object_unref (tag_sel);
+ }
+}
+
+
+static void
+gth_tag_selection_construct (GthTagSelection *tag_sel,
+ GtkWindow *parent,
+ const char *tags,
+ gboolean match_all)
+{
+ GthTagSelectionPrivate *priv;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+
+ priv = tag_sel->priv;
+
+ priv->gui = glade_xml_new (GTHUMB_GLADEDIR "/" SEARCH_GLADE_FILE,
+ NULL,
+ NULL);
+ if (! priv->gui) {
+ g_warning ("Could not find " SEARCH_GLADE_FILE "\n");
+ return;
+ }
+
+ if (tags != NULL)
+ priv->tags = g_strdup (tags);
+ priv->match_all = match_all;
+
+ /* Get the widgets. */
+
+ priv->dialog = glade_xml_get_widget (priv->gui, "tags_dialog");
+ priv->c_tags_entry = glade_xml_get_widget (priv->gui, "c_tags_entry");
+ priv->c_tags_treeview = glade_xml_get_widget (priv->gui, "c_tags_treeview");
+ priv->c_ok_button = glade_xml_get_widget (priv->gui, "c_ok_button");
+ priv->c_cancel_button = glade_xml_get_widget (priv->gui, "c_cancel_button");
+ priv->s_at_least_one_cat_radiobutton = glade_xml_get_widget (priv->gui, "s_at_least_one_cat_radiobutton");
+ priv->s_all_cat_radiobutton = glade_xml_get_widget (priv->gui, "s_all_cat_radiobutton");
+
+ /* Set widgets data. */
+
+ priv->c_tags_list_model = gtk_list_store_new (C_NUM_COLUMNS,
+ G_TYPE_BOOLEAN,
+ G_TYPE_STRING);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (priv->c_tags_treeview),
+ GTK_TREE_MODEL (priv->c_tags_list_model));
+ g_object_unref (priv->c_tags_list_model);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->c_tags_treeview), FALSE);
+
+ renderer = gtk_cell_renderer_toggle_new ();
+ g_signal_connect (G_OBJECT (renderer),
+ "toggled",
+ G_CALLBACK (use_tag_toggled),
+ tag_sel);
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->c_tags_treeview),
+ -1, "Use",
+ renderer,
+ "active", C_USE_TAG_COLUMN,
+ NULL);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes ("",
+ renderer,
+ "text", C_TAG_COLUMN,
+ NULL);
+
+ gtk_tree_view_column_set_sort_column_id (column, 0);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (priv->c_tags_treeview),
+ column);
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (priv->c_tags_list_model), C_TAG_COLUMN, GTK_SORT_ASCENDING);
+
+ gtk_entry_set_text (GTK_ENTRY (priv->c_tags_entry), tags);
+ update_list_from_entry (tag_sel);
+
+ if (priv->match_all)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->s_all_cat_radiobutton), TRUE);
+ else
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->s_at_least_one_cat_radiobutton), TRUE);
+
+ /* Set the signals handlers. */
+
+ g_signal_connect (G_OBJECT (priv->dialog),
+ "destroy",
+ G_CALLBACK (tags_dialog__destroy_cb),
+ tag_sel);
+ g_signal_connect (G_OBJECT (priv->c_ok_button),
+ "clicked",
+ G_CALLBACK (choose_tags_ok_cb),
+ tag_sel);
+ g_signal_connect_swapped (G_OBJECT (priv->c_cancel_button),
+ "clicked",
+ G_CALLBACK (gtk_widget_destroy),
+ G_OBJECT (priv->dialog));
+
+ /* Run dialog. */
+
+ gtk_widget_grab_focus (priv->c_tags_treeview);
+
+ if (parent != NULL) {
+ gtk_window_set_transient_for (GTK_WINDOW (priv->dialog), parent);
+ gtk_window_set_modal (GTK_WINDOW (priv->dialog), TRUE);
+ }
+
+ gtk_widget_show (priv->dialog);
+}
+
+
+GType
+gth_tag_selection_get_type (void)
+{
+ static GType type = 0;
+
+ if (! type) {
+ GTypeInfo type_info = {
+ sizeof (GthTagSelectionClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gth_tag_selection_class_init,
+ NULL,
+ NULL,
+ sizeof (GthTagSelection),
+ 0,
+ (GInstanceInitFunc) gth_tag_selection_init
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "GthTagSelection",
+ &type_info,
+ 0);
+ }
+
+ return type;
+}
+
+
+GthTagSelection*
+gth_tag_selection_new (GtkWindow *parent,
+ const char *tags,
+ gboolean match_all)
+{
+ GthTagSelection *csel;
+
+ csel = GTH_TAG_SELECTION (g_object_new (GTH_TYPE_TAG_SELECTION, NULL));
+ gth_tag_selection_construct (csel, parent, tags, match_all);
+
+ return csel;
+}
+
+
+char *
+gth_tag_selection_get_tags (GthTagSelection *csel)
+{
+ return csel->priv->tags;
+}
+
+
+gboolean
+gth_tag_selection_get_match_all (GthTagSelection *csel)
+{
+ return csel->priv->match_all;
+}
diff --git a/src/gth-tag-selection-dialog.h b/src/gth-tag-selection-dialog.h
new file mode 100644
index 0000000..e573f85
--- /dev/null
+++ b/src/gth-tag-selection-dialog.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2007 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_SELECTION_DIALOG_H
+#define GTH_TAG_SELECTION_DIALOG_H
+
+#include <gtk/gtk.h>
+
+#define GTH_TYPE_TAG_SELECTION (gth_tag_selection_get_type ())
+#define GTH_TAG_SELECTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTH_TYPE_TAG_SELECTION, GthTagSelection))
+#define GTH_TAG_SELECTION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTH_TYPE_TAG_SELECTION, GthTagSelectionClass))
+#define GTH_IS_TAG_SELECTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTH_TYPE_TAG_SELECTION))
+#define GTH_IS_TAG_SELECTION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTH_TYPE_TAG_SELECTION))
+#define GTH_TAG_SELECTION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GTH_TYPE_TAG_SELECTION, GthTagSelectionClass))
+
+typedef struct _GthTagSelection GthTagSelection;
+typedef struct _GthTagSelectionPrivate GthTagSelectionPrivate;
+typedef struct _GthTagSelectionClass GthTagSelectionClass;
+
+struct _GthTagSelection
+{
+ GObject __parent;
+ GthTagSelectionPrivate *priv;
+};
+
+struct _GthTagSelectionClass
+{
+ GObjectClass __parent_class;
+
+ /* -- Signals -- */
+
+ void (* response) (GthTagSelection *csel,
+ GtkResponseType response);
+};
+
+GType gth_tag_selection_get_type (void) G_GNUC_CONST;
+GthTagSelection * gth_tag_selection_new (GtkWindow *parent,
+ const char *tags,
+ gboolean match_all);
+char * gth_tag_selection_get_tags (GthTagSelection *csel);
+gboolean gth_tag_selection_get_match_all (GthTagSelection *csel);
+
+#endif /* GTH_TAG_SELECTION_DIALOG_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]