diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2012-12-10 21:09:59 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2012-12-13 03:33:43 +0800 |
commit | d09d8de870b6697c8a8b262e7e077b871a69b315 (patch) | |
tree | 3b718882e7a0bb0a996daf2967a033d91714c9b5 /e-util/e-rule-editor.c | |
parent | b61331ed03ac1c7a9b8614e25510040b9c60ae02 (diff) | |
download | gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar.gz gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar.zst gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.zip |
Consolidate base utility libraries into libeutil.
Evolution consists of entirely too many small utility libraries, which
increases linking and loading time, places a burden on higher layers of
the application (e.g. modules) which has to remember to link to all the
small in-tree utility libraries, and makes it difficult to generate API
documentation for these utility libraries in one Gtk-Doc module.
Merge the following utility libraries under the umbrella of libeutil,
and enforce a single-include policy on libeutil so we can reorganize
the files as desired without disrupting its pseudo-public API.
libemail-utils/libemail-utils.la
libevolution-utils/libevolution-utils.la
filter/libfilter.la
widgets/e-timezone-dialog/libetimezonedialog.la
widgets/menus/libmenus.la
widgets/misc/libemiscwidgets.la
widgets/table/libetable.la
widgets/text/libetext.la
This also merges libedataserverui from the Evolution-Data-Server module,
since Evolution is its only consumer nowadays, and I'd like to make some
improvements to those APIs without concern for backward-compatibility.
And finally, start a Gtk-Doc module for libeutil. It's going to be a
project just getting all the symbols _listed_ much less _documented_.
But the skeletal structure is in place and I'm off to a good start.
Diffstat (limited to 'e-util/e-rule-editor.c')
-rw-r--r-- | e-util/e-rule-editor.c | 920 |
1 files changed, 920 insertions, 0 deletions
diff --git a/e-util/e-rule-editor.c b/e-util/e-rule-editor.c new file mode 100644 index 0000000000..c063ae41ae --- /dev/null +++ b/e-util/e-rule-editor.c @@ -0,0 +1,920 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Authors: + * Not Zed <notzed@lostzed.mmc.com.au> + * Jeffrey Stedfast <fejj@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "e-rule-editor.h" + +/* for getenv only, remove when getenv need removed */ +#include <stdlib.h> +#include <string.h> + +#include <glib/gi18n.h> + +#include "e-alert-dialog.h" +#include "e-misc-utils.h" + +#define E_RULE_EDITOR_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_RULE_EDITOR, ERuleEditorPrivate)) + +static gint enable_undo = 0; + +enum { + BUTTON_ADD, + BUTTON_EDIT, + BUTTON_DELETE, + BUTTON_TOP, + BUTTON_UP, + BUTTON_DOWN, + BUTTON_BOTTOM, + BUTTON_LAST +}; + +struct _ERuleEditorPrivate { + GtkButton *buttons[BUTTON_LAST]; +}; + +G_DEFINE_TYPE ( + ERuleEditor, + e_rule_editor, + GTK_TYPE_DIALOG) + +static void +rule_editor_add_undo (ERuleEditor *editor, + gint type, + EFilterRule *rule, + gint rank, + gint newrank) +{ + ERuleEditorUndo *undo; + + if (!editor->undo_active && enable_undo) { + undo = g_malloc0 (sizeof (*undo)); + undo->rule = rule; + undo->type = type; + undo->rank = rank; + undo->newrank = newrank; + + undo->next = editor->undo_log; + editor->undo_log = undo; + } else { + g_object_unref (rule); + } +} + +static void +rule_editor_play_undo (ERuleEditor *editor) +{ + ERuleEditorUndo *undo, *next; + EFilterRule *rule; + + editor->undo_active = TRUE; + undo = editor->undo_log; + editor->undo_log = NULL; + while (undo) { + next = undo->next; + switch (undo->type) { + case E_RULE_EDITOR_LOG_EDIT: + rule = e_rule_context_find_rank_rule (editor->context, undo->rank, undo->rule->source); + if (rule) { + e_filter_rule_copy (rule, undo->rule); + } else { + g_warning ("Could not find the right rule to undo against?"); + } + break; + case E_RULE_EDITOR_LOG_ADD: + rule = e_rule_context_find_rank_rule (editor->context, undo->rank, undo->rule->source); + if (rule) + e_rule_context_remove_rule (editor->context, rule); + break; + case E_RULE_EDITOR_LOG_REMOVE: + g_object_ref (undo->rule); + e_rule_context_add_rule (editor->context, undo->rule); + e_rule_context_rank_rule (editor->context, undo->rule, editor->source, undo->rank); + break; + case E_RULE_EDITOR_LOG_RANK: + rule = e_rule_context_find_rank_rule (editor->context, undo->newrank, undo->rule->source); + if (rule) + e_rule_context_rank_rule (editor->context, rule, editor->source, undo->rank); + break; + } + + g_object_unref (undo->rule); + g_free (undo); + undo = next; + } + editor->undo_active = FALSE; +} + +static void +dialog_rule_changed (EFilterRule *fr, + GtkWidget *dialog) +{ + g_return_if_fail (dialog != NULL); + + gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, fr && fr->parts); +} + +static void +add_editor_response (GtkWidget *dialog, + gint button, + ERuleEditor *editor) +{ + GtkTreeSelection *selection; + GtkTreePath *path; + GtkTreeIter iter; + + if (button == GTK_RESPONSE_OK) { + EAlert *alert = NULL; + if (!e_filter_rule_validate (editor->edit, &alert)) { + e_alert_run_dialog (GTK_WINDOW (dialog), alert); + g_object_unref (alert); + return; + } + + if (e_rule_context_find_rule (editor->context, editor->edit->name, editor->edit->source)) { + e_alert_run_dialog_for_args ( + GTK_WINDOW (dialog), + "filter:bad-name-notunique", + editor->edit->name, NULL); + return; + } + + g_object_ref (editor->edit); + + gtk_list_store_append (editor->model, &iter); + gtk_list_store_set ( + editor->model, &iter, + 0, editor->edit->name, + 1, editor->edit, + 2, editor->edit->enabled, -1); + selection = gtk_tree_view_get_selection (editor->list); + gtk_tree_selection_select_iter (selection, &iter); + + /* scroll to the newly added row */ + path = gtk_tree_model_get_path ( + GTK_TREE_MODEL (editor->model), &iter); + gtk_tree_view_scroll_to_cell ( + editor->list, path, NULL, TRUE, 1.0, 0.0); + gtk_tree_path_free (path); + + editor->current = editor->edit; + e_rule_context_add_rule (editor->context, editor->current); + + g_object_ref (editor->current); + rule_editor_add_undo ( + editor, + E_RULE_EDITOR_LOG_ADD, + editor->current, + e_rule_context_get_rank_rule ( + editor->context, + editor->current, + editor->current->source), + 0); + } + + gtk_widget_destroy (dialog); +} + +static void +editor_destroy (ERuleEditor *editor, + GObject *deadbeef) +{ + if (editor->edit) { + g_object_unref (editor->edit); + editor->edit = NULL; + } + + editor->dialog = NULL; + + gtk_widget_set_sensitive (GTK_WIDGET (editor), TRUE); + e_rule_editor_set_sensitive (editor); +} + +static gboolean +update_selected_rule (ERuleEditor *editor) +{ + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + + selection = gtk_tree_view_get_selection (editor->list); + if (selection && gtk_tree_selection_get_selected (selection, &model, &iter)) { + gtk_tree_model_get (GTK_TREE_MODEL (editor->model), &iter, 1, &editor->current, -1); + return TRUE; + } + + return FALSE; +} + +static void +cursor_changed (GtkTreeView *treeview, + ERuleEditor *editor) +{ + if (update_selected_rule (editor)) { + g_return_if_fail (editor->current); + + e_rule_editor_set_sensitive (editor); + } +} + +static void +editor_response (GtkWidget *dialog, + gint button, + ERuleEditor *editor) +{ + if (button == GTK_RESPONSE_CANCEL) { + if (enable_undo) + rule_editor_play_undo (editor); + else { + ERuleEditorUndo *undo, *next; + + undo = editor->undo_log; + editor->undo_log = NULL; + while (undo) { + next = undo->next; + g_object_unref (undo->rule); + g_free (undo); + undo = next; + } + } + } +} + +static void +rule_add (GtkWidget *widget, + ERuleEditor *editor) +{ + GtkWidget *rules; + GtkWidget *content_area; + + if (editor->edit != NULL) + return; + + editor->edit = e_rule_editor_create_rule (editor); + e_filter_rule_set_source (editor->edit, editor->source); + rules = e_filter_rule_get_widget (editor->edit, editor->context); + + editor->dialog = gtk_dialog_new (); + gtk_dialog_add_buttons ( + GTK_DIALOG (editor->dialog), + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, + NULL); + + gtk_window_set_title ((GtkWindow *) editor->dialog, _("Add Rule")); + gtk_window_set_default_size (GTK_WINDOW (editor->dialog), 650, 400); + gtk_window_set_resizable (GTK_WINDOW (editor->dialog), TRUE); + gtk_window_set_transient_for ((GtkWindow *) editor->dialog, (GtkWindow *) editor); + gtk_container_set_border_width ((GtkContainer *) editor->dialog, 6); + + content_area = gtk_dialog_get_content_area (GTK_DIALOG (editor->dialog)); + gtk_box_pack_start (GTK_BOX (content_area), rules, TRUE, TRUE, 3); + + g_signal_connect ( + editor->dialog, "response", + G_CALLBACK (add_editor_response), editor); + g_object_weak_ref ((GObject *) editor->dialog, (GWeakNotify) editor_destroy, editor); + + g_signal_connect ( + editor->edit, "changed", + G_CALLBACK (dialog_rule_changed), editor->dialog); + dialog_rule_changed (editor->edit, editor->dialog); + + gtk_widget_set_sensitive (GTK_WIDGET (editor), FALSE); + + gtk_widget_show (editor->dialog); +} + +static void +edit_editor_response (GtkWidget *dialog, + gint button, + ERuleEditor *editor) +{ + EFilterRule *rule; + GtkTreePath *path; + GtkTreeIter iter; + gint pos; + + if (button == GTK_RESPONSE_OK) { + EAlert *alert = NULL; + if (!e_filter_rule_validate (editor->edit, &alert)) { + e_alert_run_dialog (GTK_WINDOW (dialog), alert); + g_object_unref (alert); + return; + } + + rule = e_rule_context_find_rule ( + editor->context, + editor->edit->name, + editor->edit->source); + + if (rule != NULL && rule != editor->current) { + e_alert_run_dialog_for_args ( + GTK_WINDOW (dialog), + "filter:bad-name-notunique", + rule->name, NULL); + return; + } + + pos = e_rule_context_get_rank_rule ( + editor->context, + editor->current, + editor->source); + + if (pos != -1) { + path = gtk_tree_path_new (); + gtk_tree_path_append_index (path, pos); + gtk_tree_model_get_iter ( + GTK_TREE_MODEL (editor->model), &iter, path); + gtk_tree_path_free (path); + + gtk_list_store_set ( + editor->model, &iter, + 0, editor->edit->name, -1); + + rule_editor_add_undo ( + editor, E_RULE_EDITOR_LOG_EDIT, + e_filter_rule_clone (editor->current), + pos, 0); + + /* replace the old rule with the new rule */ + e_filter_rule_copy (editor->current, editor->edit); + } + } + + gtk_widget_destroy (dialog); +} + +static void +rule_edit (GtkWidget *widget, + ERuleEditor *editor) +{ + GtkWidget *rules; + GtkWidget *content_area; + + update_selected_rule (editor); + + if (editor->current == NULL || editor->edit != NULL) + return; + + editor->edit = e_filter_rule_clone (editor->current); + + rules = e_filter_rule_get_widget (editor->edit, editor->context); + + editor->dialog = gtk_dialog_new (); + gtk_dialog_add_buttons ( + (GtkDialog *) editor->dialog, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, + NULL); + + gtk_window_set_title ((GtkWindow *) editor->dialog, _("Edit Rule")); + gtk_window_set_default_size (GTK_WINDOW (editor->dialog), 650, 400); + gtk_window_set_resizable (GTK_WINDOW (editor->dialog), TRUE); + gtk_window_set_transient_for (GTK_WINDOW (editor->dialog), GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (editor)))); + gtk_container_set_border_width ((GtkContainer *) editor->dialog, 6); + + content_area = gtk_dialog_get_content_area (GTK_DIALOG (editor->dialog)); + gtk_box_pack_start (GTK_BOX (content_area), rules, TRUE, TRUE, 3); + + g_signal_connect ( + editor->dialog, "response", + G_CALLBACK (edit_editor_response), editor); + g_object_weak_ref ((GObject *) editor->dialog, (GWeakNotify) editor_destroy, editor); + + g_signal_connect ( + editor->edit, "changed", + G_CALLBACK (dialog_rule_changed), editor->dialog); + dialog_rule_changed (editor->edit, editor->dialog); + + gtk_widget_set_sensitive (GTK_WIDGET (editor), FALSE); + + gtk_widget_show (editor->dialog); +} + +static void +rule_delete (GtkWidget *widget, + ERuleEditor *editor) +{ + GtkTreeSelection *selection; + GtkTreePath *path; + GtkTreeIter iter; + gint pos, len; + + update_selected_rule (editor); + + pos = e_rule_context_get_rank_rule (editor->context, editor->current, editor->source); + if (pos != -1) { + EFilterRule *delete_rule = editor->current; + + editor->current = NULL; + + e_rule_context_remove_rule (editor->context, delete_rule); + + path = gtk_tree_path_new (); + gtk_tree_path_append_index (path, pos); + gtk_tree_model_get_iter (GTK_TREE_MODEL (editor->model), &iter, path); + gtk_list_store_remove (editor->model, &iter); + gtk_tree_path_free (path); + + rule_editor_add_undo ( + editor, + E_RULE_EDITOR_LOG_REMOVE, + delete_rule, + e_rule_context_get_rank_rule ( + editor->context, + delete_rule, + delete_rule->source), + 0); +#if 0 + g_object_unref (delete_rule); +#endif + + /* now select the next rule */ + len = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (editor->model), NULL); + pos = pos >= len ? len - 1 : pos; + + if (pos >= 0) { + path = gtk_tree_path_new (); + gtk_tree_path_append_index (path, pos); + gtk_tree_model_get_iter (GTK_TREE_MODEL (editor->model), &iter, path); + gtk_tree_path_free (path); + + /* select the new row */ + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (editor->list)); + gtk_tree_selection_select_iter (selection, &iter); + + /* scroll to the selected row */ + path = gtk_tree_model_get_path ((GtkTreeModel *) editor->model, &iter); + gtk_tree_view_scroll_to_cell (editor->list, path, NULL, FALSE, 0.0, 0.0); + gtk_tree_path_free (path); + + /* update our selection state */ + cursor_changed (editor->list, editor); + return; + } + } + + e_rule_editor_set_sensitive (editor); +} + +static void +rule_move (ERuleEditor *editor, + gint from, + gint to) +{ + GtkTreeSelection *selection; + GtkTreePath *path; + GtkTreeIter iter; + EFilterRule *rule; + + rule_editor_add_undo ( + editor, E_RULE_EDITOR_LOG_RANK, + g_object_ref (editor->current), + e_rule_context_get_rank_rule (editor->context, + editor->current, editor->source), to); + + e_rule_context_rank_rule ( + editor->context, editor->current, editor->source, to); + + path = gtk_tree_path_new (); + gtk_tree_path_append_index (path, from); + gtk_tree_model_get_iter (GTK_TREE_MODEL (editor->model), &iter, path); + gtk_tree_path_free (path); + + gtk_tree_model_get (GTK_TREE_MODEL (editor->model), &iter, 1, &rule, -1); + g_return_if_fail (rule != NULL); + + /* remove and then re-insert the row at the new location */ + gtk_list_store_remove (editor->model, &iter); + gtk_list_store_insert (editor->model, &iter, to); + + /* set the data on the row */ + gtk_list_store_set (editor->model, &iter, 0, rule->name, 1, rule, 2, rule->enabled, -1); + + /* select the row */ + selection = gtk_tree_view_get_selection (editor->list); + gtk_tree_selection_select_iter (selection, &iter); + + /* scroll to the selected row */ + path = gtk_tree_model_get_path ((GtkTreeModel *) editor->model, &iter); + gtk_tree_view_scroll_to_cell (editor->list, path, NULL, FALSE, 0.0, 0.0); + gtk_tree_path_free (path); + + e_rule_editor_set_sensitive (editor); +} + +static void +rule_top (GtkWidget *widget, + ERuleEditor *editor) +{ + gint pos; + + update_selected_rule (editor); + + pos = e_rule_context_get_rank_rule ( + editor->context, editor->current, editor->source); + if (pos > 0) + rule_move (editor, pos, 0); +} + +static void +rule_up (GtkWidget *widget, + ERuleEditor *editor) +{ + gint pos; + + update_selected_rule (editor); + + pos = e_rule_context_get_rank_rule ( + editor->context, editor->current, editor->source); + if (pos > 0) + rule_move (editor, pos, pos - 1); +} + +static void +rule_down (GtkWidget *widget, + ERuleEditor *editor) +{ + gint pos; + + update_selected_rule (editor); + + pos = e_rule_context_get_rank_rule ( + editor->context, editor->current, editor->source); + if (pos >= 0) + rule_move (editor, pos, pos + 1); +} + +static void +rule_bottom (GtkWidget *widget, + ERuleEditor *editor) +{ + gint pos; + gint count = 0; + EFilterRule *rule = NULL; + + update_selected_rule (editor); + + pos = e_rule_context_get_rank_rule ( + editor->context, editor->current, editor->source); + /* There's probably a better/faster way to get the count of the list here */ + while ((rule = e_rule_context_next_rule (editor->context, rule, editor->source))) + count++; + count--; + if (pos >= 0) + rule_move (editor, pos, count); +} + +static struct { + const gchar *name; + GCallback func; +} edit_buttons[] = { + { "rule_add", G_CALLBACK (rule_add) }, + { "rule_edit", G_CALLBACK (rule_edit) }, + { "rule_delete", G_CALLBACK (rule_delete) }, + { "rule_top", G_CALLBACK (rule_top) }, + { "rule_up", G_CALLBACK (rule_up) }, + { "rule_down", G_CALLBACK (rule_down) }, + { "rule_bottom", G_CALLBACK (rule_bottom) }, +}; + +static void +rule_editor_finalize (GObject *object) +{ + ERuleEditor *editor = E_RULE_EDITOR (object); + ERuleEditorUndo *undo, *next; + + g_object_unref (editor->context); + + undo = editor->undo_log; + while (undo) { + next = undo->next; + g_object_unref (undo->rule); + g_free (undo); + undo = next; + } + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (e_rule_editor_parent_class)->finalize (object); +} + +static void +rule_editor_dispose (GObject *object) +{ + ERuleEditor *editor = E_RULE_EDITOR (object); + + if (editor->dialog != NULL) { + gtk_widget_destroy (GTK_WIDGET (editor->dialog)); + editor->dialog = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (e_rule_editor_parent_class)->dispose (object); +} + +static void +rule_editor_set_source (ERuleEditor *editor, + const gchar *source) +{ + EFilterRule *rule = NULL; + GtkTreeIter iter; + + gtk_list_store_clear (editor->model); + + while ((rule = e_rule_context_next_rule (editor->context, rule, source)) != NULL) { + gtk_list_store_append (editor->model, &iter); + gtk_list_store_set ( + editor->model, &iter, + 0, rule->name, 1, rule, 2, rule->enabled, -1); + } + + g_free (editor->source); + editor->source = g_strdup (source); + editor->current = NULL; + e_rule_editor_set_sensitive (editor); +} + +static void +rule_editor_set_sensitive (ERuleEditor *editor) +{ + EFilterRule *rule = NULL; + gint index = -1, count = 0; + + while ((rule = e_rule_context_next_rule (editor->context, rule, editor->source))) { + if (rule == editor->current) + index = count; + count++; + } + + count--; + + gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->buttons[BUTTON_EDIT]), index != -1); + gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->buttons[BUTTON_DELETE]), index != -1); + gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->buttons[BUTTON_TOP]), index > 0); + gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->buttons[BUTTON_UP]), index > 0); + gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->buttons[BUTTON_DOWN]), index >= 0 && index < count); + gtk_widget_set_sensitive (GTK_WIDGET (editor->priv->buttons[BUTTON_BOTTOM]), index >= 0 && index < count); +} + +static EFilterRule * +rule_editor_create_rule (ERuleEditor *editor) +{ + EFilterRule *rule; + EFilterPart *part; + + /* create a rule with 1 part in it */ + rule = e_filter_rule_new (); + part = e_rule_context_next_part (editor->context, NULL); + e_filter_rule_add_part (rule, e_filter_part_clone (part)); + + return rule; +} + +static void +e_rule_editor_class_init (ERuleEditorClass *class) +{ + GObjectClass *object_class; + + g_type_class_add_private (class, sizeof (ERuleEditorPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = rule_editor_finalize; + object_class->dispose = rule_editor_dispose; + + class->set_source = rule_editor_set_source; + class->set_sensitive = rule_editor_set_sensitive; + class->create_rule = rule_editor_create_rule; + + /* TODO: Remove when it works (or never will) */ + enable_undo = getenv ("EVOLUTION_RULE_UNDO") != NULL; +} + +static void +e_rule_editor_init (ERuleEditor *editor) +{ + editor->priv = E_RULE_EDITOR_GET_PRIVATE (editor); +} + +/** + * rule_editor_new: + * + * Create a new ERuleEditor object. + * + * Return value: A new #ERuleEditor object. + **/ +ERuleEditor * +e_rule_editor_new (ERuleContext *context, + const gchar *source, + const gchar *label) +{ + ERuleEditor *editor = (ERuleEditor *) g_object_new (E_TYPE_RULE_EDITOR, NULL); + GtkBuilder *builder; + + builder = gtk_builder_new (); + e_load_ui_builder_definition (builder, "filter.ui"); + e_rule_editor_construct (editor, context, builder, source, label); + gtk_widget_hide (e_builder_get_widget (builder, "label17")); + gtk_widget_hide (e_builder_get_widget (builder, "filter_source_combobox")); + g_object_unref (builder); + + return editor; +} + +void +e_rule_editor_set_sensitive (ERuleEditor *editor) +{ + ERuleEditorClass *class; + + g_return_if_fail (E_IS_RULE_EDITOR (editor)); + + class = E_RULE_EDITOR_GET_CLASS (editor); + g_return_if_fail (class->set_sensitive != NULL); + + class->set_sensitive (editor); +} + +void +e_rule_editor_set_source (ERuleEditor *editor, + const gchar *source) +{ + ERuleEditorClass *class; + + g_return_if_fail (E_IS_RULE_EDITOR (editor)); + + class = E_RULE_EDITOR_GET_CLASS (editor); + g_return_if_fail (class->set_source != NULL); + + class->set_source (editor, source); +} + +EFilterRule * +e_rule_editor_create_rule (ERuleEditor *editor) +{ + ERuleEditorClass *class; + + g_return_val_if_fail (E_IS_RULE_EDITOR (editor), NULL); + + class = E_RULE_EDITOR_GET_CLASS (editor); + g_return_val_if_fail (class->create_rule != NULL, NULL); + + return class->create_rule (editor); +} + +static void +double_click (GtkTreeView *treeview, + GtkTreePath *path, + GtkTreeViewColumn *column, + ERuleEditor *editor) +{ + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + + selection = gtk_tree_view_get_selection (editor->list); + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + gtk_tree_model_get (GTK_TREE_MODEL (editor->model), &iter, 1, &editor->current, -1); + + if (editor->current) + rule_edit ((GtkWidget *) treeview, editor); +} + +static void +rule_able_toggled (GtkCellRendererToggle *renderer, + gchar *path_string, + gpointer user_data) +{ + GtkWidget *table = user_data; + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeIter iter; + + path = gtk_tree_path_new_from_string (path_string); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (table)); + + if (gtk_tree_model_get_iter (model, &iter, path)) { + EFilterRule *rule = NULL; + + gtk_tree_model_get (model, &iter, 1, &rule, -1); + + if (rule) { + rule->enabled = !rule->enabled; + gtk_list_store_set (GTK_LIST_STORE (model), &iter, 2, rule->enabled, -1); + } + } + + gtk_tree_path_free (path); +} + +void +e_rule_editor_construct (ERuleEditor *editor, + ERuleContext *context, + GtkBuilder *builder, + const gchar *source, + const gchar *label) +{ + GtkWidget *widget; + GtkWidget *action_area; + GtkWidget *content_area; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GtkTreeSelection *selection; + GObject *object; + GList *list; + gint i; + + g_return_if_fail (E_IS_RULE_EDITOR (editor)); + g_return_if_fail (E_IS_RULE_CONTEXT (context)); + g_return_if_fail (GTK_IS_BUILDER (builder)); + + editor->context = g_object_ref (context); + + action_area = gtk_dialog_get_action_area (GTK_DIALOG (editor)); + content_area = gtk_dialog_get_content_area (GTK_DIALOG (editor)); + + gtk_window_set_resizable ((GtkWindow *) editor, TRUE); + gtk_window_set_default_size ((GtkWindow *) editor, 350, 400); + gtk_widget_realize ((GtkWidget *) editor); + gtk_container_set_border_width (GTK_CONTAINER (action_area), 12); + + widget = e_builder_get_widget (builder, "rule_editor"); + gtk_box_pack_start (GTK_BOX (content_area), widget, TRUE, TRUE, 0); + + for (i = 0; i < BUTTON_LAST; i++) { + widget = e_builder_get_widget (builder, edit_buttons[i].name); + editor->priv->buttons[i] = GTK_BUTTON (widget); + g_signal_connect ( + widget, "clicked", + G_CALLBACK (edit_buttons[i].func), editor); + } + + object = gtk_builder_get_object (builder, "rule_tree_view"); + editor->list = GTK_TREE_VIEW (object); + + column = gtk_tree_view_get_column (GTK_TREE_VIEW (object), 0); + g_return_if_fail (column != NULL); + + gtk_tree_view_column_set_visible (column, FALSE); + list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column)); + g_return_if_fail (list != NULL); + + renderer = GTK_CELL_RENDERER (list->data); + g_warn_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (renderer)); + + g_signal_connect ( + renderer, "toggled", + G_CALLBACK (rule_able_toggled), editor->list); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (object)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + + object = gtk_builder_get_object (builder, "rule_list_store"); + editor->model = GTK_LIST_STORE (object); + + g_signal_connect ( + editor->list, "cursor-changed", + G_CALLBACK (cursor_changed), editor); + g_signal_connect ( + editor->list, "row-activated", + G_CALLBACK (double_click), editor); + + widget = e_builder_get_widget (builder, "rule_label"); + gtk_label_set_label (GTK_LABEL (widget), label); + gtk_label_set_mnemonic_widget ( + GTK_LABEL (widget), GTK_WIDGET (editor->list)); + + g_signal_connect ( + editor, "response", + G_CALLBACK (editor_response), editor); + rule_editor_set_source (editor, source); + + gtk_dialog_add_buttons ( + GTK_DIALOG (editor), + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, + NULL); +} |