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"
55 #include "prefs_filtering_action.h"
57 static struct Filtering {
61 GtkWidget *cond_entry;
62 GtkWidget *action_entry;
64 GtkWidget *cond_clist;
67 /* widget creating functions */
68 static void prefs_filtering_create (void);
70 static void prefs_filtering_set_dialog (const gchar *header,
72 static void prefs_filtering_set_list (void);
74 /* callback functions */
75 static void prefs_filtering_register_cb (void);
76 static void prefs_filtering_substitute_cb (void);
77 static void prefs_filtering_delete_cb (void);
78 static void prefs_filtering_top (void);
79 static void prefs_filtering_up (void);
80 static void prefs_filtering_down (void);
81 static void prefs_filtering_bottom (void);
82 static void prefs_filtering_select (GtkCList *clist,
87 static gint prefs_filtering_deleted (GtkWidget *widget,
90 static void prefs_filtering_key_pressed (GtkWidget *widget,
93 static void prefs_filtering_cancel (void);
94 static void prefs_filtering_ok (void);
96 static void prefs_filtering_condition_define (void);
97 static void prefs_filtering_action_define(void);
98 static gint prefs_filtering_clist_set_row (gint row, FilteringProp * prop);
100 static void prefs_filtering_reset_dialog (void);
101 static gboolean prefs_filtering_rename_path_func(GNode *node, gpointer data);
102 static gboolean prefs_filtering_delete_path_func(GNode *node, gpointer data);
104 static FolderItem * cur_item = NULL; /* folder (if dialog opened for processing) */
106 typedef enum Action_ {
115 ACTION_MARK_AS_UNREAD,
117 ACTION_FORWARD_AS_ATTACHMENT,
121 /* add other action constants */
124 void prefs_filtering_open(FolderItem * item,
130 if (prefs_rc_is_readonly(FILTERING_RC))
135 if (!filtering.window) {
136 prefs_filtering_create();
139 manage_window_set_transient(GTK_WINDOW(filtering.window));
140 gtk_widget_grab_focus(filtering.ok_btn);
144 esckey = matcher_escape_str(key);
145 prefs_filtering_set_dialog(header, esckey);
148 gtk_widget_show(filtering.window);
150 start_address_completion();
153 /* prefs_filtering_close() - just to have one common exit point */
154 static void prefs_filtering_close(void)
156 end_address_completion();
158 gtk_widget_hide(filtering.window);
162 static void prefs_filtering_create(void)
167 GtkWidget *cancel_btn;
168 GtkWidget *confirm_area;
176 GtkWidget *cond_label;
177 GtkWidget *cond_entry;
179 GtkWidget *action_label;
180 GtkWidget *action_entry;
181 GtkWidget *action_btn;
184 GtkWidget *subst_btn;
187 GtkWidget *cond_hbox;
188 GtkWidget *cond_scrolledwin;
189 GtkWidget *cond_clist;
196 GtkWidget *bottom_btn;
200 debug_print("Creating filtering configuration window...\n");
202 window = gtk_window_new (GTK_WINDOW_DIALOG);
203 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
204 gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
205 gtk_window_set_modal (GTK_WINDOW (window), TRUE);
206 gtk_window_set_policy (GTK_WINDOW (window), FALSE, TRUE, FALSE);
208 vbox = gtk_vbox_new (FALSE, 6);
209 gtk_widget_show (vbox);
210 gtk_container_add (GTK_CONTAINER (window), vbox);
212 gtkut_button_set_create(&confirm_area, &ok_btn, _("OK"),
213 &cancel_btn, _("Cancel"), NULL, NULL);
214 gtk_widget_show (confirm_area);
215 gtk_box_pack_end (GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
216 gtk_widget_grab_default (ok_btn);
218 gtk_window_set_title (GTK_WINDOW(window),
219 _("Filtering/Processing configuration"));
221 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
222 GTK_SIGNAL_FUNC(prefs_filtering_deleted), NULL);
223 gtk_signal_connect (GTK_OBJECT(window), "key_press_event",
224 GTK_SIGNAL_FUNC(prefs_filtering_key_pressed), NULL);
225 MANAGE_WINDOW_SIGNALS_CONNECT (window);
226 gtk_signal_connect (GTK_OBJECT(ok_btn), "clicked",
227 GTK_SIGNAL_FUNC(prefs_filtering_ok), NULL);
228 gtk_signal_connect (GTK_OBJECT(cancel_btn), "clicked",
229 GTK_SIGNAL_FUNC(prefs_filtering_cancel), NULL);
231 vbox1 = gtk_vbox_new (FALSE, VSPACING);
232 gtk_widget_show (vbox1);
233 gtk_box_pack_start (GTK_BOX (vbox), vbox1, TRUE, TRUE, 0);
234 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
236 cond_label = gtk_label_new (_("Condition"));
237 gtk_widget_show (cond_label);
238 gtk_misc_set_alignment (GTK_MISC (cond_label), 0, 0.5);
239 gtk_box_pack_start (GTK_BOX (vbox1), cond_label, FALSE, FALSE, 0);
241 hbox1 = gtk_hbox_new (FALSE, VSPACING);
242 gtk_widget_show (hbox1);
243 gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
244 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
246 cond_entry = gtk_entry_new ();
247 gtk_widget_show (cond_entry);
248 gtk_box_pack_start (GTK_BOX (hbox1), cond_entry, TRUE, TRUE, 0);
250 cond_btn = gtk_button_new_with_label (_("Define ..."));
251 gtk_widget_show (cond_btn);
252 gtk_box_pack_start (GTK_BOX (hbox1), cond_btn, FALSE, FALSE, 0);
253 gtk_signal_connect (GTK_OBJECT (cond_btn), "clicked",
254 GTK_SIGNAL_FUNC (prefs_filtering_condition_define),
257 action_label = gtk_label_new (_("Action"));
258 gtk_widget_show (action_label);
259 gtk_misc_set_alignment (GTK_MISC (action_label), 0, 0.5);
260 gtk_box_pack_start (GTK_BOX (vbox1), action_label, FALSE, FALSE, 0);
262 hbox1 = gtk_hbox_new (FALSE, VSPACING);
263 gtk_widget_show (hbox1);
264 gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
265 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
267 action_entry = gtk_entry_new ();
268 gtk_widget_show (action_entry);
269 gtk_box_pack_start (GTK_BOX (hbox1), action_entry, TRUE, TRUE, 0);
271 action_btn = gtk_button_new_with_label (_("Define ..."));
272 gtk_widget_show (action_btn);
273 gtk_box_pack_start (GTK_BOX (hbox1), action_btn, FALSE, FALSE, 0);
274 gtk_signal_connect (GTK_OBJECT (action_btn), "clicked",
275 GTK_SIGNAL_FUNC (prefs_filtering_action_define),
278 /* register / substitute / delete */
280 reg_hbox = gtk_hbox_new (FALSE, 4);
281 gtk_widget_show (reg_hbox);
282 gtk_box_pack_start (GTK_BOX (vbox1), reg_hbox, FALSE, FALSE, 0);
284 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
285 gtk_widget_show (arrow);
286 gtk_box_pack_start (GTK_BOX (reg_hbox), arrow, FALSE, FALSE, 0);
287 gtk_widget_set_usize (arrow, -1, 16);
289 btn_hbox = gtk_hbox_new (TRUE, 4);
290 gtk_widget_show (btn_hbox);
291 gtk_box_pack_start (GTK_BOX (reg_hbox), btn_hbox, FALSE, FALSE, 0);
293 reg_btn = gtk_button_new_with_label (_("Add"));
294 gtk_widget_show (reg_btn);
295 gtk_box_pack_start (GTK_BOX (btn_hbox), reg_btn, FALSE, TRUE, 0);
296 gtk_signal_connect (GTK_OBJECT (reg_btn), "clicked",
297 GTK_SIGNAL_FUNC (prefs_filtering_register_cb), NULL);
299 subst_btn = gtk_button_new_with_label (_(" Replace "));
300 gtk_widget_show (subst_btn);
301 gtk_box_pack_start (GTK_BOX (btn_hbox), subst_btn, FALSE, TRUE, 0);
302 gtk_signal_connect (GTK_OBJECT (subst_btn), "clicked",
303 GTK_SIGNAL_FUNC (prefs_filtering_substitute_cb),
306 del_btn = gtk_button_new_with_label (_("Delete"));
307 gtk_widget_show (del_btn);
308 gtk_box_pack_start (GTK_BOX (btn_hbox), del_btn, FALSE, TRUE, 0);
309 gtk_signal_connect (GTK_OBJECT (del_btn), "clicked",
310 GTK_SIGNAL_FUNC (prefs_filtering_delete_cb), NULL);
312 cond_hbox = gtk_hbox_new (FALSE, 8);
313 gtk_widget_show (cond_hbox);
314 gtk_box_pack_start (GTK_BOX (vbox1), cond_hbox, TRUE, TRUE, 0);
316 cond_scrolledwin = gtk_scrolled_window_new (NULL, NULL);
317 gtk_widget_show (cond_scrolledwin);
318 gtk_widget_set_usize (cond_scrolledwin, -1, 150);
319 gtk_box_pack_start (GTK_BOX (cond_hbox), cond_scrolledwin,
321 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (cond_scrolledwin),
322 GTK_POLICY_AUTOMATIC,
323 GTK_POLICY_AUTOMATIC);
325 title[0] = _("Current filtering/processing rules");
326 cond_clist = gtk_clist_new_with_titles(1, title);
327 gtk_widget_show (cond_clist);
328 gtk_container_add (GTK_CONTAINER (cond_scrolledwin), cond_clist);
329 gtk_clist_set_column_width (GTK_CLIST (cond_clist), 0, 80);
330 gtk_clist_set_selection_mode (GTK_CLIST (cond_clist),
331 GTK_SELECTION_BROWSE);
332 GTK_WIDGET_UNSET_FLAGS (GTK_CLIST (cond_clist)->column[0].button,
334 gtk_signal_connect (GTK_OBJECT (cond_clist), "select_row",
335 GTK_SIGNAL_FUNC (prefs_filtering_select), NULL);
337 btn_vbox = gtk_vbox_new (FALSE, 8);
338 gtk_widget_show (btn_vbox);
339 gtk_box_pack_start (GTK_BOX (cond_hbox), btn_vbox, FALSE, FALSE, 0);
341 top_btn = gtk_button_new_with_label (_("Top"));
342 gtk_widget_show (top_btn);
343 gtk_box_pack_start (GTK_BOX (btn_vbox), top_btn, FALSE, FALSE, 0);
344 gtk_signal_connect (GTK_OBJECT (top_btn), "clicked",
345 GTK_SIGNAL_FUNC (prefs_filtering_top), NULL);
347 PACK_VSPACER (btn_vbox, spc_vbox, VSPACING_NARROW_2);
349 up_btn = gtk_button_new_with_label (_("Up"));
350 gtk_widget_show (up_btn);
351 gtk_box_pack_start (GTK_BOX (btn_vbox), up_btn, FALSE, FALSE, 0);
352 gtk_signal_connect (GTK_OBJECT (up_btn), "clicked",
353 GTK_SIGNAL_FUNC (prefs_filtering_up), NULL);
355 down_btn = gtk_button_new_with_label (_("Down"));
356 gtk_widget_show (down_btn);
357 gtk_box_pack_start (GTK_BOX (btn_vbox), down_btn, FALSE, FALSE, 0);
358 gtk_signal_connect (GTK_OBJECT (down_btn), "clicked",
359 GTK_SIGNAL_FUNC (prefs_filtering_down), NULL);
361 PACK_VSPACER (btn_vbox, spc_vbox, VSPACING_NARROW_2);
363 bottom_btn = gtk_button_new_with_label (_("Bottom"));
364 gtk_widget_show (bottom_btn);
365 gtk_box_pack_start (GTK_BOX (btn_vbox), bottom_btn, FALSE, FALSE, 0);
366 gtk_signal_connect (GTK_OBJECT (bottom_btn), "clicked",
367 GTK_SIGNAL_FUNC (prefs_filtering_bottom), NULL);
369 gtk_widget_set_usize(window, 500, -1);
371 gtk_widget_show_all(window);
373 filtering.window = window;
374 filtering.ok_btn = ok_btn;
376 filtering.cond_entry = cond_entry;
377 filtering.action_entry = action_entry;
378 filtering.cond_clist = cond_clist;
381 static void prefs_filtering_update_hscrollbar(void)
383 gint optwidth = gtk_clist_optimal_column_width(GTK_CLIST(filtering.cond_clist), 0);
384 gtk_clist_set_column_width(GTK_CLIST(filtering.cond_clist), 0, optwidth);
387 void prefs_filtering_rename_path(const gchar *old_path, const gchar *new_path)
390 gchar *paths[2] = {NULL, NULL};
391 paths[0] = (gchar*)old_path;
392 paths[1] = (gchar*)new_path;
393 for (cur = folder_get_list() ; cur != NULL ; cur = g_list_next(cur)) {
395 folder = (Folder *) cur->data;
396 g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
397 prefs_filtering_rename_path_func, paths);
399 prefs_filtering_rename_path_func(NULL, paths);
402 static gboolean prefs_filtering_rename_path_func(GNode *node, gpointer data)
405 gchar *old_path, *new_path;
410 gchar *old_path_with_sep;
417 old_path = ((gchar **)data)[0];
418 new_path = ((gchar **)data)[1];
420 g_return_val_if_fail(old_path != NULL, FALSE);
421 g_return_val_if_fail(new_path != NULL, FALSE);
423 oldpathlen = strlen(old_path);
424 old_path_with_sep = g_strconcat(old_path,G_DIR_SEPARATOR_S,NULL);
426 cur = global_processing;
429 if (!item || !item->prefs)
431 cur = item->prefs->processing;
435 for (; cur != NULL; cur = cur->next) {
436 FilteringProp *filtering = (FilteringProp *)cur->data;
438 for(action_cur = filtering->action_list ; action_cur != NULL ;
439 action_cur = action_cur->next) {
441 FilteringAction *action = action_cur->data;
443 if (!action->destination) continue;
445 destlen = strlen(action->destination);
447 if (destlen > oldpathlen) {
448 prefixlen = destlen - oldpathlen;
449 suffix = action->destination + prefixlen;
451 if (!strncmp(old_path, suffix, oldpathlen)) {
452 prefix = g_malloc0(prefixlen + 1);
453 strncpy2(prefix, action->destination, prefixlen);
455 base = suffix + oldpathlen;
456 while (*base == G_DIR_SEPARATOR) base++;
458 dest_path = g_strconcat(prefix,
462 dest_path = g_strconcat(prefix,
469 g_free(action->destination);
470 action->destination = dest_path;
471 } else { /* for non-leaf folders */
472 /* compare with trailing slash */
473 if (!strncmp(old_path_with_sep, action->destination, oldpathlen+1)) {
475 suffix = action->destination + oldpathlen + 1;
476 dest_path = g_strconcat(new_path,
479 g_free(action->destination);
480 action->destination = dest_path;
484 /* folder-moving a leaf */
485 if (!strcmp(old_path, action->destination)) {
486 dest_path = g_strdup(new_path);
487 g_free(action->destination);
488 action->destination = dest_path;
494 g_free(old_path_with_sep);
495 prefs_matcher_write_config();
500 void prefs_filtering_delete_path(const gchar *path)
503 for (cur = folder_get_list() ; cur != NULL ; cur = g_list_next(cur)) {
505 folder = (Folder *) cur->data;
506 g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
507 prefs_filtering_delete_path_func, (gchar *)path);
509 prefs_filtering_delete_path_func(NULL, (gchar *)path);
512 static gboolean prefs_filtering_delete_path_func(GNode *node, gpointer data)
514 GSList *cur, *filters, *duplist;
515 gchar *path = (gchar *) data;
523 g_return_val_if_fail(path != NULL, FALSE);
525 pathlen = strlen(path);
527 filters = global_processing;
530 if (!item || !item->prefs)
532 filters = item->prefs->processing;
535 duplist = g_slist_copy(filters);
536 for (cur = duplist ; cur != NULL; cur = g_slist_next(cur)) {
537 FilteringProp *filtering = (FilteringProp *) cur->data;
539 for(action_cur = filtering->action_list ; action_cur != NULL ;
540 action_cur = action_cur->next) {
542 FilteringAction *action;
544 action = action_cur->data;
546 if (!action->destination) continue;
548 destlen = strlen(action->destination);
550 if (destlen > pathlen) {
551 prefixlen = destlen - pathlen;
552 suffix = action->destination + prefixlen;
554 if (suffix && !strncmp(path, suffix, pathlen)) {
555 filteringprop_free(filtering);
556 filters = g_slist_remove(filters, filtering);
558 } else if (strcmp(action->destination, path) == 0) {
559 filteringprop_free(filtering);
560 filters = g_slist_remove(filters, filtering);
564 g_slist_free(duplist);
567 global_processing = filters;
570 if (!item || !item->prefs)
572 item->prefs->processing = filters;
575 prefs_matcher_write_config();
580 static void prefs_filtering_set_dialog(const gchar *header, const gchar *key)
582 GtkCList *clist = GTK_CLIST(filtering.cond_clist);
584 GSList * prefs_filtering;
588 gtk_clist_freeze(clist);
589 gtk_clist_clear(clist);
591 cond_str[0] = _("(New)");
592 row = gtk_clist_append(clist, cond_str);
593 gtk_clist_set_row_data(clist, row, NULL);
595 if (cur_item == NULL)
596 prefs_filtering = global_processing;
598 prefs_filtering = cur_item->prefs->processing;
600 for(cur = prefs_filtering ; cur != NULL ; cur = g_slist_next(cur)) {
601 FilteringProp * prop = (FilteringProp *) cur->data;
603 cond_str[0] = filteringprop_to_string(prop);
604 subst_char(cond_str[0], '\t', ':');
605 row = gtk_clist_append(clist, cond_str);
606 gtk_clist_set_row_data(clist, row, prop);
611 prefs_filtering_update_hscrollbar();
612 gtk_clist_thaw(clist);
614 prefs_filtering_reset_dialog();
617 gchar *match_str = g_strconcat(header, " ",
618 get_matchparser_tab_str(MATCHTYPE_MATCHCASE),
619 " \"", key, "\"", NULL);
620 gtk_entry_set_text(GTK_ENTRY(filtering.cond_entry), match_str);
625 static void prefs_filtering_reset_dialog(void)
627 gtk_entry_set_text(GTK_ENTRY(filtering.cond_entry), "");
628 gtk_entry_set_text(GTK_ENTRY(filtering.action_entry), "");
631 static void prefs_filtering_set_list(void)
636 gchar * filtering_str;
637 GSList * prefs_filtering;
639 if (cur_item == NULL)
640 prefs_filtering = global_processing;
642 prefs_filtering = cur_item->prefs->processing;
644 for(cur = prefs_filtering ; cur != NULL ; cur = g_slist_next(cur))
645 filteringprop_free((FilteringProp *) cur->data);
646 g_slist_free(prefs_filtering);
647 prefs_filtering = NULL;
649 while (gtk_clist_get_text(GTK_CLIST(filtering.cond_clist),
650 row, 0, &filtering_str)) {
651 if (strcmp(filtering_str, _("(New)")) != 0) {
652 prop = matcher_parser_get_filtering(filtering_str);
655 g_slist_append(prefs_filtering, prop);
660 if (cur_item == NULL)
661 global_processing = prefs_filtering;
663 cur_item->prefs->processing = prefs_filtering;
666 static gint prefs_filtering_clist_set_row(gint row, FilteringProp * prop)
668 GtkCList *clist = GTK_CLIST(filtering.cond_clist);
673 cond_str[0] = _("(New)");
674 return gtk_clist_append(clist, cond_str);
677 str = filteringprop_to_string(prop);
684 row = gtk_clist_append(clist, cond_str);
686 gtk_clist_set_text(clist, row, 0, cond_str[0]);
692 static void prefs_filtering_condition_define_done(MatcherList * matchers)
696 if (matchers == NULL)
699 str = matcherlist_to_string(matchers);
702 gtk_entry_set_text(GTK_ENTRY(filtering.cond_entry), str);
707 static void prefs_filtering_condition_define(void)
710 MatcherList * matchers = NULL;
712 cond_str = gtk_entry_get_text(GTK_ENTRY(filtering.cond_entry));
714 if (*cond_str != '\0') {
715 matchers = matcher_parser_get_cond(cond_str);
716 if (matchers == NULL)
717 alertpanel_error(_("Condition string is not valid."));
720 prefs_matcher_open(matchers, prefs_filtering_condition_define_done);
722 if (matchers != NULL)
723 matcherlist_free(matchers);
726 static void prefs_filtering_action_define_done(GSList * action_list)
730 if (action_list == NULL)
733 str = filteringaction_list_to_string(action_list);
736 gtk_entry_set_text(GTK_ENTRY(filtering.action_entry), str);
741 static void prefs_filtering_action_define(void)
744 GSList * action_list = NULL;
746 action_str = gtk_entry_get_text(GTK_ENTRY(filtering.action_entry));
748 if (*action_str != '\0') {
749 action_list = matcher_parser_get_action_list(action_str);
750 if (action_list == NULL)
751 alertpanel_error(_("Action string is not valid."));
754 prefs_filtering_action_open(action_list,
755 prefs_filtering_action_define_done);
757 if (action_list != NULL) {
759 for(cur = action_list ; cur != NULL ; cur = cur->next) {
760 filteringaction_free(cur->data);
766 /* register / substitute delete buttons */
769 static FilteringProp * prefs_filtering_dialog_to_filtering(gboolean alert)
774 FilteringProp * prop;
775 GSList * action_list;
777 cond_str = gtk_entry_get_text(GTK_ENTRY(filtering.cond_entry));
778 if (*cond_str == '\0') {
779 if(alert == TRUE) alertpanel_error(_("Condition string is empty."));
783 action_str = gtk_entry_get_text(GTK_ENTRY(filtering.action_entry));
784 if (*action_str == '\0') {
785 if(alert == TRUE) alertpanel_error(_("Action string is empty."));
789 cond = matcher_parser_get_cond(cond_str);
792 if(alert == TRUE) alertpanel_error(_("Condition string is not valid."));
796 action_list = matcher_parser_get_action_list(action_str);
798 if (action_list == NULL) {
799 if(alert == TRUE) alertpanel_error(_("Action string is not valid."));
803 prop = filteringprop_new(cond, action_list);
808 static void prefs_filtering_register_cb(void)
810 FilteringProp * prop;
812 prop = prefs_filtering_dialog_to_filtering(TRUE);
815 prefs_filtering_clist_set_row(-1, prop);
817 filteringprop_free(prop);
819 prefs_filtering_update_hscrollbar();
822 static void prefs_filtering_substitute_cb(void)
824 GtkCList *clist = GTK_CLIST(filtering.cond_clist);
826 FilteringProp * prop;
828 if (!clist->selection) return;
830 row = GPOINTER_TO_INT(clist->selection->data);
831 if (row == 0) return;
833 prop = prefs_filtering_dialog_to_filtering(TRUE);
836 prefs_filtering_clist_set_row(row, prop);
838 filteringprop_free(prop);
840 prefs_filtering_update_hscrollbar();
843 static void prefs_filtering_delete_cb(void)
845 GtkCList *clist = GTK_CLIST(filtering.cond_clist);
848 if (!clist->selection) return;
849 row = GPOINTER_TO_INT(clist->selection->data);
850 if (row == 0) return;
852 if (alertpanel(_("Delete rule"),
853 _("Do you really want to delete this rule?"),
854 _("Yes"), _("No"), NULL) == G_ALERTALTERNATE)
857 gtk_clist_remove(clist, row);
859 prefs_filtering_reset_dialog();
861 prefs_filtering_update_hscrollbar();
864 static void prefs_filtering_top(void)
866 GtkCList *clist = GTK_CLIST(filtering.cond_clist);
869 if (!clist->selection) return;
871 row = GPOINTER_TO_INT(clist->selection->data);
873 gtk_clist_row_move(clist, row, 1);
876 static void prefs_filtering_up(void)
878 GtkCList *clist = GTK_CLIST(filtering.cond_clist);
881 if (!clist->selection) return;
883 row = GPOINTER_TO_INT(clist->selection->data);
885 gtk_clist_row_move(clist, row, row - 1);
886 if (gtk_clist_row_is_visible(clist, row - 1) != GTK_VISIBILITY_FULL)
887 gtk_clist_moveto(clist, row - 1, 0, 0, 0);
891 static void prefs_filtering_down(void)
893 GtkCList *clist = GTK_CLIST(filtering.cond_clist);
896 if (!clist->selection) return;
898 row = GPOINTER_TO_INT(clist->selection->data);
899 if (row > 0 && row < clist->rows - 1) {
900 gtk_clist_row_move(clist, row, row + 1);
901 if (gtk_clist_row_is_visible(clist, row + 1) != GTK_VISIBILITY_FULL)
902 gtk_clist_moveto(clist, row + 1, 0, 1, 0);
906 static void prefs_filtering_bottom(void)
908 GtkCList *clist = GTK_CLIST(filtering.cond_clist);
911 if (!clist->selection) return;
913 row = GPOINTER_TO_INT(clist->selection->data);
914 if (row > 0 && row < clist->rows - 1)
915 gtk_clist_row_move(clist, row, clist->rows - 1);
918 static void prefs_filtering_select_set(FilteringProp *prop)
923 prefs_filtering_reset_dialog();
925 matcher_str = matcherlist_to_string(prop->matchers);
926 if (matcher_str == NULL) {
930 gtk_entry_set_text(GTK_ENTRY(filtering.cond_entry), matcher_str);
932 action_str = filteringaction_list_to_string(prop->action_list);
933 if (matcher_str == NULL) {
936 gtk_entry_set_text(GTK_ENTRY(filtering.action_entry), action_str);
942 static void prefs_filtering_select(GtkCList *clist, gint row, gint column,
945 FilteringProp * prop;
946 gchar * filtering_str;
949 prefs_filtering_reset_dialog();
953 if (!gtk_clist_get_text(GTK_CLIST(filtering.cond_clist),
954 row, 0, &filtering_str))
957 prop = matcher_parser_get_filtering(filtering_str);
961 prefs_filtering_select_set(prop);
963 filteringprop_free(prop);
967 static gint prefs_filtering_deleted(GtkWidget *widget, GdkEventAny *event,
970 prefs_filtering_cancel();
974 static void prefs_filtering_key_pressed(GtkWidget *widget, GdkEventKey *event,
977 if (event && event->keyval == GDK_Escape)
978 prefs_filtering_cancel();
981 static void prefs_filtering_ok(void)
983 FilteringProp * prop;
985 gchar * filtering_str;
989 prop = prefs_filtering_dialog_to_filtering(FALSE);
991 str = filteringprop_to_string(prop);
993 while (gtk_clist_get_text(GTK_CLIST(filtering.cond_clist),
994 row, 0, &filtering_str)) {
995 if (strcmp(filtering_str, str) == 0) break;
998 if (strcmp(filtering_str, str) != 0) {
999 val = alertpanel(_("Entry not saved"),
1000 _("The entry was not saved. Close anyway?"),
1001 _("Yes"), _("No"), NULL);
1002 if (G_ALERTDEFAULT != val) {
1009 prefs_filtering_set_list();
1010 prefs_matcher_write_config();
1011 prefs_filtering_close();
1014 static void prefs_filtering_cancel(void)
1016 prefs_matcher_read_config();
1017 prefs_filtering_close();