2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2003 Hiroyuki Yamamoto and the Sylpheed-Claws team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 #include <gtk/gtkoptionmenu.h>
29 #include <gdk/gdkkeysyms.h>
37 #include "prefs_gtk.h"
38 #include "prefs_matcher.h"
39 #include "prefs_filtering.h"
40 #include "prefs_common.h"
41 #include "mainwindow.h"
42 #include "foldersel.h"
43 #include "manage_window.h"
47 #include "alertpanel.h"
49 #include "filtering.h"
50 #include "addr_compl.h"
51 #include "colorlabel.h"
53 #include "matcher_parser.h"
56 static struct Filtering {
60 GtkWidget *cond_entry;
61 GtkWidget *action_entry;
63 GtkWidget *cond_clist;
66 /* widget creating functions */
67 static void prefs_filtering_create (void);
69 static void prefs_filtering_set_dialog (const gchar *header,
71 static void prefs_filtering_set_list (void);
73 /* callback functions */
74 static void prefs_filtering_register_cb (void);
75 static void prefs_filtering_substitute_cb (void);
76 static void prefs_filtering_delete_cb (void);
77 static void prefs_filtering_up (void);
78 static void prefs_filtering_down (void);
79 static void prefs_filtering_select (GtkCList *clist,
84 static gint prefs_filtering_deleted (GtkWidget *widget,
87 static void prefs_filtering_key_pressed (GtkWidget *widget,
90 static void prefs_filtering_cancel (void);
91 static void prefs_filtering_ok (void);
93 static void prefs_filtering_condition_define (void);
94 static void prefs_filtering_action_define(void);
95 static gint prefs_filtering_clist_set_row (gint row, FilteringProp * prop);
96 static void prefs_filtering_select_dest (void);
97 static void prefs_filtering_action_select (GtkList *list,
101 static void prefs_filtering_action_selection_changed(GtkList *list,
104 static void prefs_filtering_reset_dialog (void);
105 static gboolean prefs_filtering_rename_path_func(GNode *node, gpointer data);
106 static gboolean prefs_filtering_delete_path_func(GNode *node, gpointer data);
108 static FolderItem * cur_item = NULL; /* folder (if dialog opened for processing) */
110 typedef enum Action_ {
119 ACTION_MARK_AS_UNREAD,
121 ACTION_FORWARD_AS_ATTACHMENT,
125 /* add other action constants */
132 { N_("Move"), ACTION_MOVE },
133 { N_("Copy"), ACTION_COPY },
134 { N_("Delete"), ACTION_DELETE },
135 { N_("Mark"), ACTION_MARK },
136 { N_("Unmark"), ACTION_UNMARK },
137 { N_("Lock"), ACTION_LOCK },
138 { N_("Unlock"), ACTION_UNLOCK },
139 { N_("Mark as read"), ACTION_MARK_AS_READ },
140 { N_("Mark as unread"), ACTION_MARK_AS_UNREAD },
141 { N_("Forward"), ACTION_FORWARD },
142 { N_("Forward as attachment"), ACTION_FORWARD_AS_ATTACHMENT },
143 { N_("Redirect"), ACTION_REDIRECT },
144 { N_("Execute"), ACTION_EXECUTE },
145 { N_("Color"), ACTION_COLOR }
148 static const gchar *get_action_text(Action action)
151 for (n = 0; n < sizeof action_text / sizeof action_text[0]; n++)
152 if (action_text[n].action == action)
153 return action_text[n].text;
157 static gint get_sel_from_list(GtkList * list)
163 if (list->selection == NULL)
166 sel = list->selection->data;
167 for(child = list->children ; child != NULL ;
168 child = g_list_next(child)) {
169 if (child->data == sel)
177 static gint get_account_id_from_list_id(gint list_id)
181 for (accounts = account_get_list() ; accounts != NULL;
182 accounts = accounts->next) {
183 PrefsAccount *ac = (PrefsAccount *)accounts->data;
186 return ac->account_id;
192 static gint get_list_id_from_account_id(gint account_id)
197 for (accounts = account_get_list() ; accounts != NULL;
198 accounts = accounts->next) {
199 PrefsAccount *ac = (PrefsAccount *)accounts->data;
201 if (account_id == ac->account_id)
208 static gint prefs_filtering_get_matching_from_action(Action action_id)
212 return MATCHACTION_MOVE;
214 return MATCHACTION_COPY;
216 return MATCHACTION_DELETE;
218 return MATCHACTION_MARK;
220 return MATCHACTION_UNMARK;
222 return MATCHACTION_LOCK;
224 return MATCHACTION_UNLOCK;
225 case ACTION_MARK_AS_READ:
226 return MATCHACTION_MARK_AS_READ;
227 case ACTION_MARK_AS_UNREAD:
228 return MATCHACTION_MARK_AS_UNREAD;
230 return MATCHACTION_FORWARD;
231 case ACTION_FORWARD_AS_ATTACHMENT:
232 return MATCHACTION_FORWARD_AS_ATTACHMENT;
233 case ACTION_REDIRECT:
234 return MATCHACTION_REDIRECT;
236 return MATCHACTION_EXECUTE;
238 return MATCHACTION_COLOR;
244 void prefs_filtering_open(FolderItem * item,
250 if (prefs_rc_is_readonly(FILTERING_RC))
255 if (!filtering.window) {
256 prefs_filtering_create();
259 manage_window_set_transient(GTK_WINDOW(filtering.window));
260 gtk_widget_grab_focus(filtering.ok_btn);
264 esckey = matcher_escape_str(key);
265 prefs_filtering_set_dialog(header, esckey);
268 gtk_widget_show(filtering.window);
270 start_address_completion();
273 /* prefs_filtering_close() - just to have one common exit point */
274 static void prefs_filtering_close(void)
276 end_address_completion();
278 gtk_widget_hide(filtering.window);
282 static void prefs_filtering_create(void)
287 GtkWidget *cancel_btn;
288 GtkWidget *confirm_area;
296 GtkWidget *cond_label;
297 GtkWidget *cond_entry;
299 GtkWidget *action_label;
300 GtkWidget *action_entry;
301 GtkWidget *action_btn;
304 GtkWidget *subst_btn;
307 GtkWidget *cond_hbox;
308 GtkWidget *cond_scrolledwin;
309 GtkWidget *cond_clist;
324 debug_print("Creating filtering configuration window...\n");
326 window = gtk_window_new (GTK_WINDOW_DIALOG);
327 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
328 gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
329 gtk_window_set_modal (GTK_WINDOW (window), TRUE);
330 gtk_window_set_policy (GTK_WINDOW (window), FALSE, TRUE, FALSE);
332 vbox = gtk_vbox_new (FALSE, 6);
333 gtk_widget_show (vbox);
334 gtk_container_add (GTK_CONTAINER (window), vbox);
336 gtkut_button_set_create(&confirm_area, &ok_btn, _("OK"),
337 &cancel_btn, _("Cancel"), NULL, NULL);
338 gtk_widget_show (confirm_area);
339 gtk_box_pack_end (GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
340 gtk_widget_grab_default (ok_btn);
342 gtk_window_set_title (GTK_WINDOW(window),
343 _("Filtering/Processing configuration"));
345 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
346 GTK_SIGNAL_FUNC(prefs_filtering_deleted), NULL);
347 gtk_signal_connect (GTK_OBJECT(window), "key_press_event",
348 GTK_SIGNAL_FUNC(prefs_filtering_key_pressed), NULL);
349 MANAGE_WINDOW_SIGNALS_CONNECT (window);
350 gtk_signal_connect (GTK_OBJECT(ok_btn), "clicked",
351 GTK_SIGNAL_FUNC(prefs_filtering_ok), NULL);
352 gtk_signal_connect (GTK_OBJECT(cancel_btn), "clicked",
353 GTK_SIGNAL_FUNC(prefs_filtering_cancel), NULL);
355 vbox1 = gtk_vbox_new (FALSE, VSPACING);
356 gtk_widget_show (vbox1);
357 gtk_box_pack_start (GTK_BOX (vbox), vbox1, TRUE, TRUE, 0);
358 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
360 cond_label = gtk_label_new (_("Condition"));
361 gtk_widget_show (cond_label);
362 gtk_misc_set_alignment (GTK_MISC (cond_label), 0, 0.5);
363 gtk_box_pack_start (GTK_BOX (vbox1), cond_label, FALSE, FALSE, 0);
365 hbox1 = gtk_hbox_new (FALSE, VSPACING);
366 gtk_widget_show (hbox1);
367 gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
368 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
370 cond_entry = gtk_entry_new ();
371 gtk_widget_show (cond_entry);
372 gtk_box_pack_start (GTK_BOX (hbox1), cond_entry, TRUE, TRUE, 0);
374 cond_btn = gtk_button_new_with_label (_("Define ..."));
375 gtk_widget_show (cond_btn);
376 gtk_box_pack_start (GTK_BOX (hbox1), cond_btn, FALSE, FALSE, 0);
377 gtk_signal_connect (GTK_OBJECT (cond_btn), "clicked",
378 GTK_SIGNAL_FUNC (prefs_filtering_condition_define),
381 action_label = gtk_label_new (_("Action"));
382 gtk_widget_show (action_label);
383 gtk_misc_set_alignment (GTK_MISC (action_label), 0, 0.5);
384 gtk_box_pack_start (GTK_BOX (vbox1), action_label, FALSE, FALSE, 0);
386 hbox1 = gtk_hbox_new (FALSE, VSPACING);
387 gtk_widget_show (hbox1);
388 gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
389 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
391 action_entry = gtk_entry_new ();
392 gtk_widget_show (action_entry);
393 gtk_box_pack_start (GTK_BOX (hbox1), action_entry, TRUE, TRUE, 0);
395 action_btn = gtk_button_new_with_label (_("Define ..."));
396 gtk_widget_show (action_btn);
397 gtk_box_pack_start (GTK_BOX (hbox1), action_btn, FALSE, FALSE, 0);
398 gtk_signal_connect (GTK_OBJECT (action_btn), "clicked",
399 GTK_SIGNAL_FUNC (prefs_filtering_action_define),
402 /* register / substitute / delete */
404 reg_hbox = gtk_hbox_new (FALSE, 4);
405 gtk_widget_show (reg_hbox);
406 gtk_box_pack_start (GTK_BOX (vbox1), reg_hbox, FALSE, FALSE, 0);
408 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
409 gtk_widget_show (arrow);
410 gtk_box_pack_start (GTK_BOX (reg_hbox), arrow, FALSE, FALSE, 0);
411 gtk_widget_set_usize (arrow, -1, 16);
413 btn_hbox = gtk_hbox_new (TRUE, 4);
414 gtk_widget_show (btn_hbox);
415 gtk_box_pack_start (GTK_BOX (reg_hbox), btn_hbox, FALSE, FALSE, 0);
417 reg_btn = gtk_button_new_with_label (_("Add"));
418 gtk_widget_show (reg_btn);
419 gtk_box_pack_start (GTK_BOX (btn_hbox), reg_btn, FALSE, TRUE, 0);
420 gtk_signal_connect (GTK_OBJECT (reg_btn), "clicked",
421 GTK_SIGNAL_FUNC (prefs_filtering_register_cb), NULL);
423 subst_btn = gtk_button_new_with_label (_(" Replace "));
424 gtk_widget_show (subst_btn);
425 gtk_box_pack_start (GTK_BOX (btn_hbox), subst_btn, FALSE, TRUE, 0);
426 gtk_signal_connect (GTK_OBJECT (subst_btn), "clicked",
427 GTK_SIGNAL_FUNC (prefs_filtering_substitute_cb),
430 del_btn = gtk_button_new_with_label (_("Delete"));
431 gtk_widget_show (del_btn);
432 gtk_box_pack_start (GTK_BOX (btn_hbox), del_btn, FALSE, TRUE, 0);
433 gtk_signal_connect (GTK_OBJECT (del_btn), "clicked",
434 GTK_SIGNAL_FUNC (prefs_filtering_delete_cb), NULL);
436 cond_hbox = gtk_hbox_new (FALSE, 8);
437 gtk_widget_show (cond_hbox);
438 gtk_box_pack_start (GTK_BOX (vbox1), cond_hbox, TRUE, TRUE, 0);
440 cond_scrolledwin = gtk_scrolled_window_new (NULL, NULL);
441 gtk_widget_show (cond_scrolledwin);
442 gtk_widget_set_usize (cond_scrolledwin, -1, 150);
443 gtk_box_pack_start (GTK_BOX (cond_hbox), cond_scrolledwin,
445 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (cond_scrolledwin),
446 GTK_POLICY_AUTOMATIC,
447 GTK_POLICY_AUTOMATIC);
449 title[0] = _("Current filtering/processing rules");
450 cond_clist = gtk_clist_new_with_titles(1, title);
451 gtk_widget_show (cond_clist);
452 gtk_container_add (GTK_CONTAINER (cond_scrolledwin), cond_clist);
453 gtk_clist_set_column_width (GTK_CLIST (cond_clist), 0, 80);
454 gtk_clist_set_selection_mode (GTK_CLIST (cond_clist),
455 GTK_SELECTION_BROWSE);
456 GTK_WIDGET_UNSET_FLAGS (GTK_CLIST (cond_clist)->column[0].button,
458 gtk_signal_connect (GTK_OBJECT (cond_clist), "select_row",
459 GTK_SIGNAL_FUNC (prefs_filtering_select), NULL);
461 btn_vbox = gtk_vbox_new (FALSE, 8);
462 gtk_widget_show (btn_vbox);
463 gtk_box_pack_start (GTK_BOX (cond_hbox), btn_vbox, FALSE, FALSE, 0);
465 up_btn = gtk_button_new_with_label (_("Up"));
466 gtk_widget_show (up_btn);
467 gtk_box_pack_start (GTK_BOX (btn_vbox), up_btn, FALSE, FALSE, 0);
468 gtk_signal_connect (GTK_OBJECT (up_btn), "clicked",
469 GTK_SIGNAL_FUNC (prefs_filtering_up), NULL);
471 down_btn = gtk_button_new_with_label (_("Down"));
472 gtk_widget_show (down_btn);
473 gtk_box_pack_start (GTK_BOX (btn_vbox), down_btn, FALSE, FALSE, 0);
474 gtk_signal_connect (GTK_OBJECT (down_btn), "clicked",
475 GTK_SIGNAL_FUNC (prefs_filtering_down), NULL);
477 gtk_widget_set_usize(window, 500, -1);
479 gtk_widget_show_all(window);
481 filtering.window = window;
482 filtering.ok_btn = ok_btn;
484 filtering.cond_entry = cond_entry;
485 filtering.action_entry = action_entry;
486 filtering.cond_clist = cond_clist;
489 static void prefs_filtering_update_hscrollbar(void)
491 gint optwidth = gtk_clist_optimal_column_width(GTK_CLIST(filtering.cond_clist), 0);
492 gtk_clist_set_column_width(GTK_CLIST(filtering.cond_clist), 0, optwidth);
495 void prefs_filtering_rename_path(const gchar *old_path, const gchar *new_path)
498 gchar *paths[2] = {NULL, NULL};
499 paths[0] = (gchar*)old_path;
500 paths[1] = (gchar*)new_path;
501 for (cur = folder_get_list() ; cur != NULL ; cur = g_list_next(cur)) {
503 folder = (Folder *) cur->data;
504 g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
505 prefs_filtering_rename_path_func, paths);
507 prefs_filtering_rename_path_func(NULL, paths);
510 static gboolean prefs_filtering_rename_path_func(GNode *node, gpointer data)
513 gchar *old_path, *new_path;
518 gchar *old_path_with_sep;
525 old_path = ((gchar **)data)[0];
526 new_path = ((gchar **)data)[1];
528 g_return_val_if_fail(old_path != NULL, FALSE);
529 g_return_val_if_fail(new_path != NULL, FALSE);
531 oldpathlen = strlen(old_path);
532 old_path_with_sep = g_strconcat(old_path,G_DIR_SEPARATOR_S,NULL);
534 cur = global_processing;
537 if (!item || !item->prefs)
539 cur = item->prefs->processing;
543 for (; cur != NULL; cur = cur->next) {
544 FilteringProp *filtering = (FilteringProp *)cur->data;
546 for(action_cur = filtering->action_list ; action_cur != NULL ;
547 action_cur = action_cur->next) {
549 FilteringAction *action = action_cur->data;
551 if (!action->destination) continue;
553 destlen = strlen(action->destination);
555 if (destlen > oldpathlen) {
556 prefixlen = destlen - oldpathlen;
557 suffix = action->destination + prefixlen;
559 if (!strncmp(old_path, suffix, oldpathlen)) {
560 prefix = g_malloc0(prefixlen + 1);
561 strncpy2(prefix, action->destination, prefixlen);
563 base = suffix + oldpathlen;
564 while (*base == G_DIR_SEPARATOR) base++;
566 dest_path = g_strconcat(prefix,
570 dest_path = g_strconcat(prefix,
577 g_free(action->destination);
578 action->destination = dest_path;
579 } else { /* for non-leaf folders */
580 /* compare with trailing slash */
581 if (!strncmp(old_path_with_sep, action->destination, oldpathlen+1)) {
583 suffix = action->destination + oldpathlen + 1;
584 dest_path = g_strconcat(new_path,
587 g_free(action->destination);
588 action->destination = dest_path;
592 /* folder-moving a leaf */
593 if (!strcmp(old_path, action->destination)) {
594 dest_path = g_strdup(new_path);
595 g_free(action->destination);
596 action->destination = dest_path;
602 g_free(old_path_with_sep);
603 prefs_matcher_write_config();
608 void prefs_filtering_delete_path(const gchar *path)
611 for (cur = folder_get_list() ; cur != NULL ; cur = g_list_next(cur)) {
613 folder = (Folder *) cur->data;
614 g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
615 prefs_filtering_delete_path_func, (gchar *)path);
617 prefs_filtering_delete_path_func(NULL, (gchar *)path);
620 static gboolean prefs_filtering_delete_path_func(GNode *node, gpointer data)
623 gchar *path = (gchar *)data;
631 g_return_val_if_fail(path != NULL, FALSE);
633 pathlen = strlen(path);
635 cur = global_processing;
638 if (!item || !item->prefs)
640 cur = item->prefs->processing;
644 for (; cur != NULL; cur = cur->next) {
645 FilteringProp *filtering = (FilteringProp *)cur->data;
647 for(action_cur = filtering->action_list ; action_cur != NULL ;
648 action_cur = action_cur->next) {
650 FilteringAction *action;
652 action = action_cur->data;
654 if (!action->destination) continue;
656 destlen = strlen(action->destination);
658 if (destlen > pathlen) {
659 prefixlen = destlen - pathlen;
660 suffix = action->destination + prefixlen;
662 if (suffix && !strncmp(path, suffix, pathlen)) {
663 filteringprop_free(filtering);
664 orig = g_slist_remove(orig, filtering);
666 } else if (strcmp(action->destination, path) == 0) {
667 filteringprop_free(filtering);
668 orig = g_slist_remove(orig, filtering);
675 global_processing = orig;
678 if (!item || !item->prefs)
680 item->prefs->processing = orig;
683 prefs_matcher_write_config();
688 static void prefs_filtering_set_dialog(const gchar *header, const gchar *key)
690 GtkCList *clist = GTK_CLIST(filtering.cond_clist);
692 GSList * prefs_filtering;
696 gtk_clist_freeze(clist);
697 gtk_clist_clear(clist);
699 cond_str[0] = _("(New)");
700 row = gtk_clist_append(clist, cond_str);
701 gtk_clist_set_row_data(clist, row, NULL);
703 if (cur_item == NULL)
704 prefs_filtering = global_processing;
706 prefs_filtering = cur_item->prefs->processing;
708 for(cur = prefs_filtering ; cur != NULL ; cur = g_slist_next(cur)) {
709 FilteringProp * prop = (FilteringProp *) cur->data;
711 cond_str[0] = filteringprop_to_string(prop);
712 subst_char(cond_str[0], '\t', ':');
713 row = gtk_clist_append(clist, cond_str);
714 gtk_clist_set_row_data(clist, row, prop);
719 prefs_filtering_update_hscrollbar();
720 gtk_clist_thaw(clist);
722 prefs_filtering_reset_dialog();
725 gchar *match_str = g_strconcat(header, " ",
726 get_matchparser_tab_str(MATCHTYPE_MATCHCASE),
727 " \"", key, "\"", NULL);
728 gtk_entry_set_text(GTK_ENTRY(filtering.cond_entry), match_str);
733 static void prefs_filtering_reset_dialog(void)
735 gtk_entry_set_text(GTK_ENTRY(filtering.cond_entry), "");
736 gtk_entry_set_text(GTK_ENTRY(filtering.action_entry), "");
739 static void prefs_filtering_set_list(void)
744 gchar * filtering_str;
745 GSList * prefs_filtering;
747 if (cur_item == NULL)
748 prefs_filtering = global_processing;
750 prefs_filtering = cur_item->prefs->processing;
752 for(cur = prefs_filtering ; cur != NULL ; cur = g_slist_next(cur))
753 filteringprop_free((FilteringProp *) cur->data);
754 g_slist_free(prefs_filtering);
755 prefs_filtering = NULL;
757 while (gtk_clist_get_text(GTK_CLIST(filtering.cond_clist),
758 row, 0, &filtering_str)) {
759 if (strcmp(filtering_str, _("(New)")) != 0) {
760 prop = matcher_parser_get_filtering(filtering_str);
763 g_slist_append(prefs_filtering, prop);
768 if (cur_item == NULL)
769 global_processing = prefs_filtering;
771 cur_item->prefs->processing = prefs_filtering;
774 static gint prefs_filtering_clist_set_row(gint row, FilteringProp * prop)
776 GtkCList *clist = GTK_CLIST(filtering.cond_clist);
781 cond_str[0] = _("(New)");
782 return gtk_clist_append(clist, cond_str);
785 str = filteringprop_to_string(prop);
792 row = gtk_clist_append(clist, cond_str);
794 gtk_clist_set_text(clist, row, 0, cond_str[0]);
800 static void prefs_filtering_condition_define_done(MatcherList * matchers)
804 if (matchers == NULL)
807 str = matcherlist_to_string(matchers);
810 gtk_entry_set_text(GTK_ENTRY(filtering.cond_entry), str);
815 static void prefs_filtering_condition_define(void)
818 MatcherList * matchers = NULL;
820 cond_str = gtk_entry_get_text(GTK_ENTRY(filtering.cond_entry));
822 if (*cond_str != '\0') {
823 matchers = matcher_parser_get_cond(cond_str);
824 if (matchers == NULL)
825 alertpanel_error(_("Condition string is not valid."));
828 prefs_matcher_open(matchers, prefs_filtering_condition_define_done);
830 if (matchers != NULL)
831 matcherlist_free(matchers);
834 static void prefs_filtering_action_define_done(GSList * action_list)
838 if (action_list == NULL)
841 str = filteringaction_list_to_string(action_list);
844 gtk_entry_set_text(GTK_ENTRY(filtering.action_entry), str);
849 static void prefs_filtering_action_define(void)
852 GSList * action_list = NULL;
854 action_str = gtk_entry_get_text(GTK_ENTRY(filtering.action_entry));
856 if (*action_str != '\0') {
857 action_list = matcher_parser_get_action_list(action_str);
858 if (action_list == NULL)
859 alertpanel_error(_("Action string is not valid."));
862 prefs_filtering_action_open(action_list,
863 prefs_filtering_action_define_done);
865 if (action_list != NULL) {
867 for(cur = action_list ; cur != NULL ; cur = cur->next) {
868 filteringaction_free(cur->data);
874 /* register / substitute delete buttons */
877 static FilteringProp * prefs_filtering_dialog_to_filtering(gboolean alert)
882 FilteringProp * prop;
883 FilteringAction * action;
890 GSList * action_list;
892 cond_str = gtk_entry_get_text(GTK_ENTRY(filtering.cond_entry));
893 if (*cond_str == '\0') {
894 if(alert == TRUE) alertpanel_error(_("Condition string is empty."));
898 action_str = gtk_entry_get_text(GTK_ENTRY(filtering.action_entry));
899 if (*action_str == '\0') {
900 if(alert == TRUE) alertpanel_error(_("Action string is empty."));
904 cond = matcher_parser_get_cond(cond_str);
907 if(alert == TRUE) alertpanel_error(_("Condition string is not valid."));
911 action_list = matcher_parser_get_action_list(action_str);
913 if (action_list == NULL) {
914 if(alert == TRUE) alertpanel_error(_("Action string is not valid."));
918 prop = filteringprop_new(cond, action_list);
923 static void prefs_filtering_register_cb(void)
925 FilteringProp * prop;
927 prop = prefs_filtering_dialog_to_filtering(TRUE);
930 prefs_filtering_clist_set_row(-1, prop);
932 filteringprop_free(prop);
934 prefs_filtering_update_hscrollbar();
937 static void prefs_filtering_substitute_cb(void)
939 GtkCList *clist = GTK_CLIST(filtering.cond_clist);
941 FilteringProp * prop;
943 if (!clist->selection) return;
945 row = GPOINTER_TO_INT(clist->selection->data);
946 if (row == 0) return;
948 prop = prefs_filtering_dialog_to_filtering(TRUE);
951 prefs_filtering_clist_set_row(row, prop);
953 filteringprop_free(prop);
955 prefs_filtering_update_hscrollbar();
958 static void prefs_filtering_delete_cb(void)
960 GtkCList *clist = GTK_CLIST(filtering.cond_clist);
963 if (!clist->selection) return;
964 row = GPOINTER_TO_INT(clist->selection->data);
965 if (row == 0) return;
967 if (alertpanel(_("Delete rule"),
968 _("Do you really want to delete this rule?"),
969 _("Yes"), _("No"), NULL) == G_ALERTALTERNATE)
972 gtk_clist_remove(clist, row);
974 prefs_filtering_reset_dialog();
976 prefs_filtering_update_hscrollbar();
979 static void prefs_filtering_up(void)
981 GtkCList *clist = GTK_CLIST(filtering.cond_clist);
984 if (!clist->selection) return;
986 row = GPOINTER_TO_INT(clist->selection->data);
988 gtk_clist_row_move(clist, row, row - 1);
989 if(gtk_clist_row_is_visible(clist, row - 1) != GTK_VISIBILITY_FULL) {
990 gtk_clist_moveto(clist, row - 1, 0, 0, 0);
995 static void prefs_filtering_down(void)
997 GtkCList *clist = GTK_CLIST(filtering.cond_clist);
1000 if (!clist->selection) return;
1002 row = GPOINTER_TO_INT(clist->selection->data);
1003 if (row > 0 && row < clist->rows - 1) {
1004 gtk_clist_row_move(clist, row, row + 1);
1005 if(gtk_clist_row_is_visible(clist, row + 1) != GTK_VISIBILITY_FULL) {
1006 gtk_clist_moveto(clist, row + 1, 0, 1, 0);
1011 static void prefs_filtering_select_set(FilteringProp *prop)
1013 FilteringAction *action;
1018 prefs_filtering_reset_dialog();
1020 matcher_str = matcherlist_to_string(prop->matchers);
1021 if (matcher_str == NULL) {
1025 gtk_entry_set_text(GTK_ENTRY(filtering.cond_entry), matcher_str);
1027 action_str = filteringaction_list_to_string(prop->action_list);
1028 if (matcher_str == NULL) {
1031 gtk_entry_set_text(GTK_ENTRY(filtering.action_entry), action_str);
1034 g_free(matcher_str);
1037 static void prefs_filtering_select(GtkCList *clist, gint row, gint column,
1040 FilteringProp * prop;
1041 gchar * filtering_str;
1044 prefs_filtering_reset_dialog();
1048 if (!gtk_clist_get_text(GTK_CLIST(filtering.cond_clist),
1049 row, 0, &filtering_str))
1052 prop = matcher_parser_get_filtering(filtering_str);
1056 prefs_filtering_select_set(prop);
1058 filteringprop_free(prop);
1062 static gint prefs_filtering_deleted(GtkWidget *widget, GdkEventAny *event,
1065 prefs_filtering_cancel();
1069 static void prefs_filtering_key_pressed(GtkWidget *widget, GdkEventKey *event,
1072 if (event && event->keyval == GDK_Escape)
1073 prefs_filtering_cancel();
1076 static void prefs_filtering_ok(void)
1078 FilteringProp * prop;
1080 gchar * filtering_str;
1084 prop = prefs_filtering_dialog_to_filtering(FALSE);
1086 str = filteringprop_to_string(prop);
1088 while (gtk_clist_get_text(GTK_CLIST(filtering.cond_clist),
1089 row, 0, &filtering_str)) {
1090 if (strcmp(filtering_str, str) == 0) break;
1093 if (strcmp(filtering_str, str) != 0) {
1094 val = alertpanel(_("Entry not saved"),
1095 _("The entry was not saved. Close anyway?"),
1096 _("Yes"), _("No"), NULL);
1097 if (G_ALERTDEFAULT != val) {
1104 prefs_filtering_set_list();
1105 prefs_matcher_write_config();
1106 prefs_filtering_close();
1109 static void prefs_filtering_cancel(void)
1111 prefs_matcher_read_config();
1112 prefs_filtering_close();