/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * GThumb * * Copyright (C) 2006-2008 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "dom.h" #include "glib-utils.h" #include "gth-filterbar.h" #include "gth-main.h" #include "gth-user-dir.h" enum { ITEM_TYPE_NONE, ITEM_TYPE_SEPARATOR, ITEM_TYPE_FILTER, ITEM_TYPE_PERSONALIZE }; enum { ICON_COLUMN, NAME_COLUMN, TYPE_COLUMN, FILTER_COLUMN, N_COLUMNS }; enum { CHANGED, PERSONALIZE, CLOSE_BUTTON_CLICKED, LAST_SIGNAL }; struct _GthFilterbarPrivate { GtkListStore *model; GtkWidget *test_combo_box; GthTest *test; GtkWidget *control_box; GtkWidget *control; GtkWidget *extra_area; GtkTreeIter current_iter; gulong filters_changed_id; gulong test_changed_id; }; static guint gth_filterbar_signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE_WITH_CODE (GthFilterbar, gth_filterbar, GTK_TYPE_BOX, G_ADD_PRIVATE (GthFilterbar)) static void gth_filterbar_finalize (GObject *object) { GthFilterbar *filterbar; filterbar = GTH_FILTERBAR (object); g_signal_handler_disconnect (gth_main_get_default_monitor (), filterbar->priv->filters_changed_id); if (filterbar->priv->test != NULL) { g_signal_handler_disconnect (filterbar->priv->test, filterbar->priv->test_changed_id); g_object_unref (filterbar->priv->test); } G_OBJECT_CLASS (gth_filterbar_parent_class)->finalize (object); } static void gth_filterbar_class_init (GthFilterbarClass *class) { GObjectClass *object_class; object_class = (GObjectClass*) class; object_class->finalize = gth_filterbar_finalize; gth_filterbar_signals[CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GthFilterbarClass, changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); gth_filterbar_signals[PERSONALIZE] = g_signal_new ("personalize", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GthFilterbarClass, personalize), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); gth_filterbar_signals[CLOSE_BUTTON_CLICKED] = g_signal_new ("close_button_clicked", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GthFilterbarClass, close_button_clicked), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void gth_filterbar_init (GthFilterbar *filterbar) { filterbar->priv = gth_filterbar_get_instance_private (filterbar); filterbar->priv->model = NULL; filterbar->priv->test_combo_box = NULL; filterbar->priv->test = NULL; filterbar->priv->control_box = NULL; filterbar->priv->control = NULL; filterbar->priv->extra_area = NULL; filterbar->priv->filters_changed_id = 0; filterbar->priv->test_changed_id = 0; gtk_orientable_set_orientation (GTK_ORIENTABLE (filterbar), GTK_ORIENTATION_HORIZONTAL); } static void gth_filterbar_changed (GthFilterbar *filterbar) { g_signal_emit (filterbar, gth_filterbar_signals[CHANGED], 0); } static void _gth_filterbar_set_test_control (GthFilterbar *filterbar, GtkWidget *control) { if (filterbar->priv->control != NULL) { gtk_container_remove (GTK_CONTAINER (filterbar->priv->control_box), filterbar->priv->control); filterbar->priv->control = NULL; } gth_filterbar_changed (filterbar); if (control == NULL) return; filterbar->priv->control = control; gtk_widget_show (control); gtk_container_add (GTK_CONTAINER (filterbar->priv->control_box), filterbar->priv->control); } static void test_changed_cb (GthTest *test, GthFilterbar *filterbar) { gth_filterbar_changed (filterbar); } static void _gth_filterbar_set_test (GthFilterbar *filterbar, GthTest *test) { GthTest *old_test; old_test = filterbar->priv->test; if (old_test != NULL) { if (filterbar->priv->test_changed_id != 0) g_signal_handler_disconnect (old_test, filterbar->priv->test_changed_id); filterbar->priv->test = NULL; } if (test != NULL) { filterbar->priv->test = g_object_ref (test); filterbar->priv->test_changed_id = g_signal_connect (test, "changed", G_CALLBACK (test_changed_cb), filterbar); _gth_filterbar_set_test_control (filterbar, gth_test_create_control (filterbar->priv->test)); gth_test_focus_control (filterbar->priv->test); } else _gth_filterbar_set_test_control (filterbar, NULL); _g_object_unref (old_test); } static void test_combo_box_changed_cb (GtkComboBox *scope_combo_box, GthFilterbar *filterbar) { GtkTreeIter iter; int item_type = ITEM_TYPE_NONE; GthTest *test; if (! gtk_combo_box_get_active_iter (scope_combo_box, &iter)) return; gtk_tree_model_get (GTK_TREE_MODEL (filterbar->priv->model), &iter, TYPE_COLUMN, &item_type, FILTER_COLUMN, &test, -1); switch (item_type) { case ITEM_TYPE_FILTER: _gth_filterbar_set_test (filterbar, test); filterbar->priv->current_iter = iter; break; case ITEM_TYPE_PERSONALIZE: g_signal_emit (filterbar, gth_filterbar_signals[PERSONALIZE], 0); g_signal_handlers_block_by_func (filterbar->priv->test_combo_box, test_combo_box_changed_cb, filterbar); gtk_combo_box_set_active_iter (GTK_COMBO_BOX (filterbar->priv->test_combo_box), &filterbar->priv->current_iter); g_signal_handlers_unblock_by_func (filterbar->priv->test_combo_box, test_combo_box_changed_cb, filterbar); break; default: break; } if (test != NULL) g_object_unref (test); } static gboolean test_combo_box_row_separator_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { int item_type = ITEM_TYPE_NONE; gtk_tree_model_get (model, iter, TYPE_COLUMN, &item_type, -1); return (item_type == ITEM_TYPE_SEPARATOR); } static void update_filter_list (GthFilterbar *filterbar, const char *current_filter) { gboolean no_filter_selected = TRUE; GList *filters, *scan; GtkTreeIter iter; gtk_list_store_clear (filterbar->priv->model); gtk_list_store_append (filterbar->priv->model, &iter); gtk_list_store_set (filterbar->priv->model, &iter, TYPE_COLUMN, ITEM_TYPE_FILTER, FILTER_COLUMN, NULL, NAME_COLUMN, _("All"), -1); filters = gth_main_get_all_filters (); for (scan = filters; scan; scan = scan->next) { GthTest *test = scan->data; if (! gth_test_is_visible (test)) continue; gtk_list_store_append (filterbar->priv->model, &iter); gtk_list_store_set (filterbar->priv->model, &iter, TYPE_COLUMN, ITEM_TYPE_FILTER, FILTER_COLUMN, test, NAME_COLUMN, gth_test_get_display_name (test), -1); if (g_strcmp0 (current_filter, gth_test_get_id (test)) == 0) { gtk_combo_box_set_active_iter (GTK_COMBO_BOX (filterbar->priv->test_combo_box), &iter); filterbar->priv->current_iter = iter; _gth_filterbar_set_test (GTH_FILTERBAR (filterbar), test); no_filter_selected = FALSE; } } _g_object_list_unref (filters); gtk_list_store_append (filterbar->priv->model, &iter); gtk_list_store_set (filterbar->priv->model, &iter, TYPE_COLUMN, ITEM_TYPE_SEPARATOR, -1); gtk_list_store_append (filterbar->priv->model, &iter); gtk_list_store_set (filterbar->priv->model, &iter, TYPE_COLUMN, ITEM_TYPE_PERSONALIZE, NAME_COLUMN, _("Personalize…"), -1); if (no_filter_selected) { GtkTreeIter iter; gtk_tree_model_get_iter_first (GTK_TREE_MODEL (filterbar->priv->model), &iter); gtk_combo_box_set_active_iter (GTK_COMBO_BOX (filterbar->priv->test_combo_box), &iter); filterbar->priv->current_iter = iter; } } static void filters_changed_cb (GthMonitor *monitor, GthFilterbar *filterbar) { GthTest *current_filter; gtk_tree_model_get (GTK_TREE_MODEL (filterbar->priv->model), &filterbar->priv->current_iter, FILTER_COLUMN, ¤t_filter, -1); update_filter_list (filterbar, current_filter != NULL ? gth_test_get_id (current_filter) : NULL); if (current_filter != NULL) g_object_unref (current_filter); } static void gth_filterbar_construct (GthFilterbar *filterbar, const char *selected_filter) { GtkCellRenderer *renderer; GtkWidget *label; gtk_box_set_spacing (GTK_BOX (filterbar), 6); gtk_container_set_border_width (GTK_CONTAINER (filterbar), 4); /* filter combo box */ filterbar->priv->model = gtk_list_store_new (N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT, G_TYPE_OBJECT); filterbar->priv->test_combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (filterbar->priv->model)); g_object_unref (filterbar->priv->model); gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (filterbar->priv->test_combo_box), test_combo_box_row_separator_func, filterbar, NULL); /* icon renderer */ renderer = gtk_cell_renderer_pixbuf_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (filterbar->priv->test_combo_box), renderer, FALSE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (filterbar->priv->test_combo_box), renderer, "pixbuf", ICON_COLUMN, NULL); /* name renderer */ renderer = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (filterbar->priv->test_combo_box), renderer, TRUE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (filterbar->priv->test_combo_box), renderer, "text", NAME_COLUMN, NULL); /**/ update_filter_list (filterbar, selected_filter); g_signal_connect (G_OBJECT (filterbar->priv->test_combo_box), "changed", G_CALLBACK (test_combo_box_changed_cb), filterbar); gtk_widget_show (filterbar->priv->test_combo_box); /* test control box */ filterbar->priv->control_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_widget_show (filterbar->priv->control_box); /* extra widgets container */ filterbar->priv->extra_area = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_widget_show (filterbar->priv->extra_area); /* view label */ label = gtk_label_new_with_mnemonic (_("S_how:")); gtk_label_set_mnemonic_widget (GTK_LABEL (label), filterbar->priv->test_combo_box); gtk_widget_show (label); /**/ filterbar->priv->filters_changed_id = g_signal_connect (gth_main_get_default_monitor (), "filters-changed", G_CALLBACK (filters_changed_cb), filterbar); gtk_box_pack_start (GTK_BOX (filterbar), label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (filterbar), filterbar->priv->test_combo_box, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (filterbar), filterbar->priv->control_box, FALSE, FALSE, 0); gtk_box_pack_end (GTK_BOX (filterbar), filterbar->priv->extra_area, FALSE, FALSE, 0); } GtkWidget* gth_filterbar_new (const char *selected_filter) { GtkWidget *widget; widget = GTK_WIDGET (g_object_new (GTH_TYPE_FILTERBAR, NULL)); gth_filterbar_construct (GTH_FILTERBAR (widget), selected_filter); return widget; } GthTest * gth_filterbar_get_test (GthFilterbar *filterbar) { if (filterbar->priv->test != NULL) return g_object_ref (filterbar->priv->test); else return NULL; } void gth_filterbar_save_filter (GthFilterbar *filterbar, const char *filename) { char *filter_description; gsize len; GFile *filter_file; if (filterbar->priv->test != NULL) { DomDocument *doc; doc = dom_document_new (); dom_element_append_child (DOM_ELEMENT (doc), dom_domizable_create_element (DOM_DOMIZABLE (filterbar->priv->test), doc)); filter_description = dom_document_dump (doc, &len); g_object_unref (doc); } else { filter_description = g_strdup (""); len = 0; } filter_file = gth_user_dir_get_file_for_write (GTH_DIR_CONFIG, GTHUMB_DIR, filename, NULL); _g_file_write (filter_file, FALSE, 0, filter_description, len, NULL, NULL); g_object_unref (filter_file); g_free (filter_description); } static gboolean find_test_by_id (GthFilterbar *filterbar, const char *id, GthTest **test, GtkTreeIter *iter) { g_return_val_if_fail (test != NULL, FALSE); g_return_val_if_fail (iter != NULL, FALSE); if (! gtk_tree_model_get_iter_first(GTK_TREE_MODEL (filterbar->priv->model), iter)) return FALSE; do { int item_type = ITEM_TYPE_NONE; gtk_tree_model_get (GTK_TREE_MODEL (filterbar->priv->model), iter, TYPE_COLUMN, &item_type, FILTER_COLUMN, test, -1); if ((item_type == ITEM_TYPE_FILTER) && (*test != NULL) && (g_strcmp0 (gth_test_get_id (*test), id) == 0)) return TRUE; } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (filterbar->priv->model), iter)); return FALSE; } void gth_filterbar_load_filter (GthFilterbar *filterbar, const char *filename) { GFile *filter_file; char *buffer; gsize len; DomDocument *doc; filter_file = gth_user_dir_get_file_for_write (GTH_DIR_CONFIG, GTHUMB_DIR, filename, NULL); if (! _g_file_load_in_buffer (filter_file, (void **) &buffer, &len, NULL, NULL)) { g_object_unref (filter_file); return; } if (buffer == NULL) { g_object_unref (filter_file); return; } doc = dom_document_new (); if (dom_document_load (doc, buffer, len, NULL)) { DomElement *node = DOM_ELEMENT (doc)->first_child; if (node != NULL) { GthTest *test; GtkTreeIter iter; if (find_test_by_id (filterbar, dom_element_get_attribute (node, "id"), &test, &iter)) { dom_domizable_load_from_element (DOM_DOMIZABLE (test), node); g_signal_handlers_block_by_func (filterbar->priv->test_combo_box, test_combo_box_changed_cb, filterbar); gtk_combo_box_set_active_iter (GTK_COMBO_BOX (filterbar->priv->test_combo_box), &iter); g_signal_handlers_unblock_by_func (filterbar->priv->test_combo_box, test_combo_box_changed_cb, filterbar); filterbar->priv->current_iter = iter; _gth_filterbar_set_test (GTH_FILTERBAR (filterbar), test); } } } g_object_unref (doc); g_free (buffer); g_object_unref (filter_file); } GtkWidget * gth_filterbar_get_extra_area (GthFilterbar *filterbar) { return filterbar->priv->extra_area; }