2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2001 Hiroyuki Yamamoto
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 <gdk/gdkkeysyms.h>
36 #include "prefs_gtk.h"
37 #include "prefs_matcher.h"
38 #include "prefs_scoring.h"
39 #include "prefs_common.h"
40 #include "mainwindow.h"
41 #include "foldersel.h"
42 #include "manage_window.h"
46 #include "alertpanel.h"
50 #include "matcher_parser.h"
52 static struct Scoring {
56 GtkWidget *cond_entry;
57 GtkWidget *score_entry;
58 GtkWidget *kill_score_label;
59 GtkWidget *kill_score_entry;
60 GtkWidget *important_score_entry;
62 GtkWidget *cond_clist;
66 parameter name, default value, pointer to the prefs variable, data type,
67 pointer to the widget pointer,
68 pointer to the function for data setting,
69 pointer to the function for widget setting
72 /* widget creating functions */
73 static void prefs_scoring_create (void);
75 static void prefs_scoring_set_dialog (ScoringProp * prop);
76 static void prefs_scoring_set_list (void);
78 /* callback functions */
79 /* static void prefs_scoring_select_dest_cb (void); */
80 static void prefs_scoring_register_cb (void);
81 static void prefs_scoring_substitute_cb (void);
82 static void prefs_scoring_delete_cb (void);
83 static void prefs_scoring_up (void);
84 static void prefs_scoring_down (void);
85 static void prefs_scoring_select (GtkCList *clist,
90 static gint prefs_scoring_deleted (GtkWidget *widget,
93 static void prefs_scoring_key_pressed (GtkWidget *widget,
96 static void prefs_scoring_cancel (void);
97 static void prefs_scoring_ok (void);
99 static void prefs_scoring_condition_define (void);
100 static gint prefs_scoring_clist_set_row(gint row, ScoringProp * prop);
101 static void prefs_scoring_select_set_dialog(ScoringProp * prop);
102 static void prefs_scoring_reset_dialog(void);
105 static FolderItem * cur_item = NULL;
106 static gint cur_important_score;
107 static gint cur_kill_score;
109 void prefs_scoring_open(FolderItem * item)
111 if (prefs_rc_is_readonly(SCORING_RC))
116 if (!scoring.window) {
117 prefs_scoring_create();
120 manage_window_set_transient(GTK_WINDOW(scoring.window));
121 gtk_widget_grab_focus(scoring.ok_btn);
125 prefs_scoring_set_dialog(NULL);
127 gtk_widget_show(scoring.window);
130 void prefs_scoring_open_with_scoring(ScoringProp * prop)
134 if (!scoring.window) {
135 prefs_scoring_create();
138 manage_window_set_transient(GTK_WINDOW(scoring.window));
139 gtk_widget_grab_focus(scoring.ok_btn);
141 prefs_scoring_set_dialog(prop);
143 gtk_widget_show(scoring.window);
146 static void prefs_scoring_create(void)
151 GtkWidget *cancel_btn;
152 GtkWidget *confirm_area;
160 GtkWidget *cond_label;
161 GtkWidget *cond_entry;
163 GtkWidget *score_label;
164 GtkWidget *score_entry;
167 GtkWidget *subst_btn;
170 GtkWidget *cond_hbox;
171 GtkWidget *cond_scrolledwin;
172 GtkWidget *cond_clist;
178 GtkWidget *important_score_entry;
179 GtkWidget *kill_score_entry;
180 GtkWidget *kill_score_label;
184 debug_print("Creating scoring configuration window...\n");
186 window = gtk_window_new (GTK_WINDOW_DIALOG);
187 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
188 gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
189 gtk_window_set_modal (GTK_WINDOW (window), TRUE);
190 gtk_window_set_policy (GTK_WINDOW (window), FALSE, TRUE, FALSE);
192 vbox = gtk_vbox_new (FALSE, 6);
193 gtk_widget_show (vbox);
194 gtk_container_add (GTK_CONTAINER (window), vbox);
196 gtkut_button_set_create(&confirm_area, &ok_btn, _("OK"),
197 &cancel_btn, _("Cancel"), NULL, NULL);
198 gtk_widget_show (confirm_area);
199 gtk_box_pack_end (GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
200 gtk_widget_grab_default (ok_btn);
202 gtk_window_set_title (GTK_WINDOW(window),
203 _("Scoring configuration"));
204 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
205 GTK_SIGNAL_FUNC(prefs_scoring_deleted), NULL);
206 gtk_signal_connect (GTK_OBJECT(window), "key_press_event",
207 GTK_SIGNAL_FUNC(prefs_scoring_key_pressed), NULL);
208 MANAGE_WINDOW_SIGNALS_CONNECT (window);
209 gtk_signal_connect (GTK_OBJECT(ok_btn), "clicked",
210 GTK_SIGNAL_FUNC(prefs_scoring_ok), NULL);
211 gtk_signal_connect (GTK_OBJECT(cancel_btn), "clicked",
212 GTK_SIGNAL_FUNC(prefs_scoring_cancel), NULL);
214 vbox1 = gtk_vbox_new (FALSE, VSPACING);
215 gtk_widget_show (vbox1);
216 gtk_box_pack_start (GTK_BOX (vbox), vbox1, TRUE, TRUE, 0);
217 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
219 cond_label = gtk_label_new (_("Condition"));
220 gtk_widget_show (cond_label);
221 gtk_misc_set_alignment (GTK_MISC (cond_label), 0, 0.5);
222 gtk_box_pack_start (GTK_BOX (vbox1), cond_label, FALSE, FALSE, 0);
224 hbox1 = gtk_hbox_new (FALSE, VSPACING);
225 gtk_widget_show (vbox1);
226 gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
227 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
229 cond_entry = gtk_entry_new ();
230 gtk_widget_show (cond_entry);
231 gtk_widget_set_usize (cond_entry, 300, -1);
232 gtk_box_pack_start (GTK_BOX (hbox1), cond_entry, TRUE, TRUE, 0);
234 cond_btn = gtk_button_new_with_label (_("Define ..."));
235 gtk_widget_show (cond_btn);
236 gtk_box_pack_start (GTK_BOX (hbox1), cond_btn, FALSE, FALSE, 0);
237 gtk_signal_connect (GTK_OBJECT (cond_btn), "clicked",
238 GTK_SIGNAL_FUNC (prefs_scoring_condition_define),
241 hbox1 = gtk_hbox_new (FALSE, VSPACING);
242 gtk_widget_show (vbox1);
243 gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
244 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
246 score_label = gtk_label_new (_("Score"));
247 gtk_widget_show (score_label);
248 gtk_misc_set_alignment (GTK_MISC (score_label), 0, 0.5);
249 gtk_box_pack_start (GTK_BOX (hbox1), score_label, FALSE, FALSE, 0);
251 score_entry = gtk_entry_new ();
252 gtk_widget_show (score_entry);
253 gtk_widget_set_usize (score_entry, 50, -1);
254 gtk_box_pack_start (GTK_BOX (hbox1), score_entry, FALSE, FALSE, 0);
256 /* register / substitute / delete */
258 reg_hbox = gtk_hbox_new (FALSE, 4);
259 gtk_widget_show (reg_hbox);
260 gtk_box_pack_start (GTK_BOX (vbox1), reg_hbox, FALSE, FALSE, 0);
262 arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
263 gtk_widget_show (arrow);
264 gtk_box_pack_start (GTK_BOX (reg_hbox), arrow, FALSE, FALSE, 0);
265 gtk_widget_set_usize (arrow, -1, 16);
267 btn_hbox = gtk_hbox_new (TRUE, 4);
268 gtk_widget_show (btn_hbox);
269 gtk_box_pack_start (GTK_BOX (reg_hbox), btn_hbox, FALSE, FALSE, 0);
271 reg_btn = gtk_button_new_with_label (_("Add"));
272 gtk_widget_show (reg_btn);
273 gtk_box_pack_start (GTK_BOX (btn_hbox), reg_btn, FALSE, TRUE, 0);
274 gtk_signal_connect (GTK_OBJECT (reg_btn), "clicked",
275 GTK_SIGNAL_FUNC (prefs_scoring_register_cb), NULL);
277 subst_btn = gtk_button_new_with_label (_(" Replace "));
278 gtk_widget_show (subst_btn);
279 gtk_box_pack_start (GTK_BOX (btn_hbox), subst_btn, FALSE, TRUE, 0);
280 gtk_signal_connect (GTK_OBJECT (subst_btn), "clicked",
281 GTK_SIGNAL_FUNC (prefs_scoring_substitute_cb),
284 del_btn = gtk_button_new_with_label (_("Delete"));
285 gtk_widget_show (del_btn);
286 gtk_box_pack_start (GTK_BOX (btn_hbox), del_btn, FALSE, TRUE, 0);
287 gtk_signal_connect (GTK_OBJECT (del_btn), "clicked",
288 GTK_SIGNAL_FUNC (prefs_scoring_delete_cb), NULL);
290 cond_hbox = gtk_hbox_new (FALSE, 8);
291 gtk_widget_show (cond_hbox);
292 gtk_box_pack_start (GTK_BOX (vbox1), cond_hbox, TRUE, TRUE, 0);
294 cond_scrolledwin = gtk_scrolled_window_new (NULL, NULL);
295 gtk_widget_show (cond_scrolledwin);
296 gtk_widget_set_usize (cond_scrolledwin, -1, 150);
297 gtk_box_pack_start (GTK_BOX (cond_hbox), cond_scrolledwin,
299 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (cond_scrolledwin),
300 GTK_POLICY_AUTOMATIC,
301 GTK_POLICY_AUTOMATIC);
303 title[0] = _("Current scoring rules");
304 cond_clist = gtk_clist_new_with_titles(1, title);
305 gtk_widget_show (cond_clist);
306 gtk_container_add (GTK_CONTAINER (cond_scrolledwin), cond_clist);
307 gtk_clist_set_column_width (GTK_CLIST (cond_clist), 0, 80);
308 gtk_clist_set_selection_mode (GTK_CLIST (cond_clist),
309 GTK_SELECTION_BROWSE);
310 GTK_WIDGET_UNSET_FLAGS (GTK_CLIST (cond_clist)->column[0].button,
312 gtk_signal_connect (GTK_OBJECT (cond_clist), "select_row",
313 GTK_SIGNAL_FUNC (prefs_scoring_select), NULL);
315 btn_vbox = gtk_vbox_new (FALSE, 8);
316 gtk_widget_show (btn_vbox);
317 gtk_box_pack_start (GTK_BOX (cond_hbox), btn_vbox, FALSE, FALSE, 0);
319 up_btn = gtk_button_new_with_label (_("Up"));
320 gtk_widget_show (up_btn);
321 gtk_box_pack_start (GTK_BOX (btn_vbox), up_btn, FALSE, FALSE, 0);
322 gtk_signal_connect (GTK_OBJECT (up_btn), "clicked",
323 GTK_SIGNAL_FUNC (prefs_scoring_up), NULL);
325 down_btn = gtk_button_new_with_label (_("Down"));
326 gtk_widget_show (down_btn);
327 gtk_box_pack_start (GTK_BOX (btn_vbox), down_btn, FALSE, FALSE, 0);
328 gtk_signal_connect (GTK_OBJECT (down_btn), "clicked",
329 GTK_SIGNAL_FUNC (prefs_scoring_down), NULL);
331 hbox1 = gtk_hbox_new (FALSE, 8);
332 gtk_widget_show (hbox1);
333 gtk_box_pack_start (GTK_BOX (vbox1), hbox1, TRUE, TRUE, 0);
335 kill_score_label = gtk_label_new (_("Hide score"));
336 gtk_widget_show (kill_score_label);
337 gtk_misc_set_alignment (GTK_MISC (kill_score_label), 0, 0.5);
338 gtk_box_pack_start (GTK_BOX (hbox1), kill_score_label,
341 kill_score_entry = gtk_entry_new ();
342 gtk_widget_show (kill_score_entry);
343 gtk_widget_set_usize (kill_score_entry, 50, -1);
344 gtk_box_pack_start (GTK_BOX (hbox1), kill_score_entry,
347 score_label = gtk_label_new (_("Important score"));
348 gtk_widget_show (score_label);
349 gtk_misc_set_alignment (GTK_MISC (score_label), 0, 0.5);
350 gtk_box_pack_start (GTK_BOX (hbox1), score_label, FALSE, FALSE, 0);
352 important_score_entry = gtk_entry_new ();
353 gtk_widget_show (important_score_entry);
354 gtk_widget_set_usize (important_score_entry, 50, -1);
355 gtk_box_pack_start (GTK_BOX (hbox1), important_score_entry,
358 gtk_widget_show_all(window);
360 scoring.window = window;
361 scoring.ok_btn = ok_btn;
363 scoring.cond_entry = cond_entry;
364 scoring.score_entry = score_entry;
365 scoring.kill_score_entry = kill_score_entry;
366 scoring.kill_score_label = kill_score_label;
367 scoring.important_score_entry = important_score_entry;
369 scoring.cond_clist = cond_clist;
372 static void prefs_scoring_set_dialog(ScoringProp * cond)
374 GtkCList *clist = GTK_CLIST(scoring.cond_clist);
376 GSList * prefs_scoring;
380 prefs_scoring_reset_dialog();
382 prefs_scoring_select_set_dialog(cond);
384 gtk_clist_freeze(clist);
385 gtk_clist_clear(clist);
387 prefs_scoring_clist_set_row(-1, NULL);
388 if (cur_item == NULL) {
389 prefs_scoring = global_scoring;
390 cur_kill_score = prefs_common.kill_score;
391 cur_important_score = prefs_common.important_score;
392 gtk_widget_show(scoring.kill_score_label);
393 gtk_widget_show(scoring.kill_score_entry);
395 prefs_scoring = cur_item->prefs->scoring;
396 cur_kill_score = cur_item->prefs->kill_score;
397 cur_important_score = cur_item->prefs->important_score;
400 for(cur = prefs_scoring ; cur != NULL ;
401 cur = g_slist_next(cur)) {
402 ScoringProp * prop = (ScoringProp *) cur->data;
404 prefs_scoring_clist_set_row(-1, prop);
407 score_str = itos(cur_kill_score);
408 gtk_entry_set_text(GTK_ENTRY(scoring.kill_score_entry),
410 score_str = itos(cur_important_score);
411 gtk_entry_set_text(GTK_ENTRY(scoring.important_score_entry),
414 gtk_clist_thaw(clist);
417 static void prefs_scoring_reset_dialog(void)
419 gtk_entry_set_text(GTK_ENTRY(scoring.cond_entry), "");
420 gtk_entry_set_text(GTK_ENTRY(scoring.score_entry), "");
423 static void prefs_scoring_set_list(void)
429 GSList * prefs_scoring;
431 if (cur_item == NULL)
432 prefs_scoring = global_scoring;
434 prefs_scoring = cur_item->prefs->scoring;
436 for(cur = prefs_scoring ; cur != NULL ;
437 cur = g_slist_next(cur))
438 scoringprop_free((ScoringProp *) cur->data);
439 g_slist_free(prefs_scoring);
440 prefs_scoring = NULL;
442 while (gtk_clist_get_text(GTK_CLIST(scoring.cond_clist),
443 row, 0, &scoring_str)) {
444 if (strcmp(scoring_str, _("(New)")) != 0) {
445 prop = matcher_parser_get_scoring(scoring_str);
447 prefs_scoring = g_slist_append(prefs_scoring,
453 cur_kill_score = atoi(gtk_entry_get_text(GTK_ENTRY(scoring.kill_score_entry)));
454 cur_important_score = atoi(gtk_entry_get_text(GTK_ENTRY(scoring.important_score_entry)));
456 if (cur_item == NULL) {
457 global_scoring = prefs_scoring;
458 prefs_common.kill_score = cur_kill_score;
459 prefs_common.important_score = cur_important_score;
462 cur_item->prefs->scoring = prefs_scoring;
463 cur_item->prefs->kill_score = cur_kill_score;
464 cur_item->prefs->important_score = cur_important_score;
468 static gint prefs_scoring_clist_set_row(gint row, ScoringProp * prop)
470 GtkCList *clist = GTK_CLIST(scoring.cond_clist);
475 cond_str[0] = _("(New)");
476 return gtk_clist_append(clist, cond_str);
479 str = scoringprop_to_string(prop);
486 row = gtk_clist_append(clist, cond_str);
488 gtk_clist_set_text(clist, row, 0, cond_str[0]);
494 static void prefs_scoring_condition_define_done(MatcherList * matchers)
498 if (matchers == NULL)
501 str = matcherlist_to_string(matchers);
504 gtk_entry_set_text(GTK_ENTRY(scoring.cond_entry), str);
509 static void prefs_scoring_condition_define(void)
512 MatcherList * matchers = NULL;
514 cond_str = gtk_entry_get_text(GTK_ENTRY(scoring.cond_entry));
516 if (*cond_str != '\0') {
517 matchers = matcher_parser_get_cond(cond_str);
518 if (matchers == NULL)
519 alertpanel_error(_("Match string is not valid."));
522 prefs_matcher_open(matchers, prefs_scoring_condition_define_done);
524 if (matchers != NULL)
525 matcherlist_free(matchers);
529 /* register / substitute delete buttons */
531 static void prefs_scoring_register_cb(void)
539 cond_str = gtk_entry_get_text(GTK_ENTRY(scoring.cond_entry));
540 if (*cond_str == '\0') {
541 alertpanel_error(_("Condition string is empty."));
545 score_str = gtk_entry_get_text(GTK_ENTRY(scoring.score_entry));
546 if (*score_str == '\0') {
547 alertpanel_error(_("Score is not set."));
551 score = atoi(score_str);
552 cond = matcher_parser_get_cond(cond_str);
555 alertpanel_error(_("Condition string is not valid."));
559 prop = scoringprop_new(cond, score);
561 prefs_scoring_clist_set_row(-1, prop);
563 scoringprop_free(prop);
565 prefs_scoring_reset_dialog();
568 static void prefs_scoring_substitute_cb(void)
570 GtkCList *clist = GTK_CLIST(scoring.cond_clist);
578 if (!clist->selection) return;
580 row = GPOINTER_TO_INT(clist->selection->data);
581 if (row == 0) return;
583 cond_str = gtk_entry_get_text(GTK_ENTRY(scoring.cond_entry));
584 if (*cond_str == '\0') {
585 alertpanel_error(_("Condition string is empty."));
589 score_str = gtk_entry_get_text(GTK_ENTRY(scoring.score_entry));
590 if (*score_str == '\0') {
591 alertpanel_error(_("Score is not set."));
595 score = atoi(score_str);
596 cond = matcher_parser_get_cond(cond_str);
599 alertpanel_error(_("Condition string is not valid."));
603 prop = scoringprop_new(cond, score);
605 prefs_scoring_clist_set_row(row, prop);
607 scoringprop_free(prop);
609 prefs_scoring_reset_dialog();
612 static void prefs_scoring_delete_cb(void)
614 GtkCList *clist = GTK_CLIST(scoring.cond_clist);
617 if (!clist->selection) return;
618 row = GPOINTER_TO_INT(clist->selection->data);
619 if (row == 0) return;
621 if (alertpanel(_("Delete rule"),
622 _("Do you really want to delete this rule?"),
623 _("Yes"), _("No"), NULL) == G_ALERTALTERNATE)
626 gtk_clist_remove(clist, row);
629 static void prefs_scoring_up(void)
631 GtkCList *clist = GTK_CLIST(scoring.cond_clist);
634 if (!clist->selection) return;
636 row = GPOINTER_TO_INT(clist->selection->data);
638 gtk_clist_row_move(clist, row, row - 1);
639 if(gtk_clist_row_is_visible(clist, row - 1) != GTK_VISIBILITY_FULL) {
640 gtk_clist_moveto(clist, row - 1, 0, 0, 0);
645 static void prefs_scoring_down(void)
647 GtkCList *clist = GTK_CLIST(scoring.cond_clist);
650 if (!clist->selection) return;
652 row = GPOINTER_TO_INT(clist->selection->data);
653 if (row > 0 && row < clist->rows - 1) {
654 gtk_clist_row_move(clist, row, row + 1);
655 if(gtk_clist_row_is_visible(clist, row + 1) != GTK_VISIBILITY_FULL) {
656 gtk_clist_moveto(clist, row + 1, 0, 1, 0);
661 static void prefs_scoring_select_set_dialog(ScoringProp * prop)
669 matcher_str = matcherlist_to_string(prop->matchers);
670 if (matcher_str == NULL) {
671 scoringprop_free(prop);
675 score_str = itos(prop->score);
677 gtk_entry_set_text(GTK_ENTRY(scoring.cond_entry), matcher_str);
678 gtk_entry_set_text(GTK_ENTRY(scoring.score_entry), score_str);
683 static void prefs_scoring_select(GtkCList *clist, gint row, gint column,
691 prefs_scoring_reset_dialog();
695 if (!gtk_clist_get_text(GTK_CLIST(scoring.cond_clist),
696 row, 0, &scoring_str))
699 prop = matcher_parser_get_scoring(scoring_str);
703 prefs_scoring_select_set_dialog(prop);
705 scoringprop_free(prop);
708 static gint prefs_scoring_deleted(GtkWidget *widget, GdkEventAny *event,
711 prefs_scoring_cancel();
715 static void prefs_scoring_key_pressed(GtkWidget *widget, GdkEventKey *event,
718 if (event && event->keyval == GDK_Escape)
719 prefs_scoring_cancel();
722 static void prefs_scoring_ok(void)
734 cond_str = gtk_entry_get_text(GTK_ENTRY(scoring.cond_entry));
735 score_str = gtk_entry_get_text(GTK_ENTRY(scoring.score_entry));
736 if (*cond_str != '\0' && *score_str != '\0') {
737 score = atoi(score_str);
738 cond = matcher_parser_get_cond(cond_str);
741 prefs_common_save_config();
742 prefs_scoring_set_list();
743 prefs_matcher_write_config();
744 if (cur_item != NULL)
745 prefs_folder_item_save_config(cur_item);
746 gtk_widget_hide(scoring.window);
750 prop = scoringprop_new(cond, score);
751 str = scoringprop_to_string(prop);
752 while (gtk_clist_get_text(GTK_CLIST(scoring.cond_clist),
753 row, 0, &scoring_str)) {
754 if (strcmp(scoring_str, str) == 0) break;
757 if (strcmp(scoring_str, str) != 0) {
758 val = alertpanel(_("Entry not saved"),
759 _("The entry was not saved\nHave you really finished?"),
760 _("Yes"), _("No"), NULL);
761 if (G_ALERTDEFAULT != val) {
768 prefs_common_save_config();
769 prefs_scoring_set_list();
770 prefs_matcher_write_config();
771 if (cur_item != NULL)
772 prefs_folder_item_save_config(cur_item);
773 gtk_widget_hide(scoring.window);
777 static void prefs_scoring_cancel(void)
779 prefs_matcher_read_config();
780 gtk_widget_hide(scoring.window);