scroll list when moving rows up or down
[claws.git] / src / prefs_scoring.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2001 Hiroyuki Yamamoto
4  *
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.
9  *
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.
14  *
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.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include "defs.h"
25
26 #include <glib.h>
27 #include <gtk/gtk.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <errno.h>
33
34 #include "intl.h"
35 #include "main.h"
36 #include "prefs.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"
43 #include "inc.h"
44 #include "utils.h"
45 #include "gtkutils.h"
46 #include "alertpanel.h"
47 #include "folder.h"
48 #include "scoring.h"
49
50 static struct Scoring {
51         GtkWidget *window;
52
53         GtkWidget *ok_btn;
54         GtkWidget *cond_entry;
55         GtkWidget *score_entry;
56         GtkWidget *kill_score_label;
57         GtkWidget *kill_score_entry;
58         GtkWidget *important_score_entry;
59
60         GtkWidget *cond_clist;
61 } scoring;
62
63 /*
64    parameter name, default value, pointer to the prefs variable, data type,
65    pointer to the widget pointer,
66    pointer to the function for data setting,
67    pointer to the function for widget setting
68  */
69
70 #define VSPACING                12
71 #define VSPACING_NARROW         4
72 #define DEFAULT_ENTRY_WIDTH     80
73 #define PREFSBUFSIZE            1024
74
75 /* widget creating functions */
76 static void prefs_scoring_create                (void);
77
78 static void prefs_scoring_set_dialog    (ScoringProp * prop);
79 static void prefs_scoring_set_list      (void);
80
81 /* callback functions */
82 /* static void prefs_scoring_select_dest_cb     (void); */
83 static void prefs_scoring_register_cb   (void);
84 static void prefs_scoring_substitute_cb (void);
85 static void prefs_scoring_delete_cb     (void);
86 static void prefs_scoring_up            (void);
87 static void prefs_scoring_down          (void);
88 static void prefs_scoring_select                (GtkCList       *clist,
89                                          gint            row,
90                                          gint            column,
91                                          GdkEvent       *event);
92
93 static gint prefs_scoring_deleted       (GtkWidget      *widget,
94                                          GdkEventAny    *event,
95                                          gpointer        data);
96 static void prefs_scoring_key_pressed   (GtkWidget      *widget,
97                                          GdkEventKey    *event,
98                                          gpointer        data);
99 static void prefs_scoring_cancel                (void);
100 static void prefs_scoring_ok            (void);
101
102 static void prefs_scoring_condition_define      (void);
103 static gint prefs_scoring_clist_set_row(gint row, ScoringProp * prop);
104 static void prefs_scoring_select_set_dialog(ScoringProp * prop);
105 static void prefs_scoring_reset_dialog(void);
106
107
108 static FolderItem * cur_item = NULL;
109 static gint cur_important_score;
110 static gint cur_kill_score;
111
112 void prefs_scoring_open(FolderItem * item)
113 {
114         if (prefs_rc_is_readonly(SCORING_RC))
115                 return;
116
117         inc_autocheck_timer_remove();
118
119         if (!scoring.window) {
120                 prefs_scoring_create();
121         }
122
123         manage_window_set_transient(GTK_WINDOW(scoring.window));
124         gtk_widget_grab_focus(scoring.ok_btn);
125
126         cur_item = item;
127
128         prefs_scoring_set_dialog(NULL);
129
130         gtk_widget_show(scoring.window);
131 }
132
133 void prefs_scoring_open_with_scoring(ScoringProp * prop)
134 {
135         inc_autocheck_timer_remove();
136
137         if (!scoring.window) {
138                 prefs_scoring_create();
139         }
140
141         manage_window_set_transient(GTK_WINDOW(scoring.window));
142         gtk_widget_grab_focus(scoring.ok_btn);
143
144         prefs_scoring_set_dialog(prop);
145
146         gtk_widget_show(scoring.window);
147 }
148
149 static void prefs_scoring_create(void)
150 {
151         GtkWidget *window;
152         GtkWidget *vbox;
153         GtkWidget *ok_btn;
154         GtkWidget *cancel_btn;
155         GtkWidget *confirm_area;
156
157         GtkWidget *vbox1;
158         GtkWidget *hbox1;
159         GtkWidget *reg_hbox;
160         GtkWidget *arrow;
161         GtkWidget *btn_hbox;
162
163         GtkWidget *cond_label;
164         GtkWidget *cond_entry;
165         GtkWidget *cond_btn;
166         GtkWidget *score_label;
167         GtkWidget *score_entry;
168
169         GtkWidget *reg_btn;
170         GtkWidget *subst_btn;
171         GtkWidget *del_btn;
172
173         GtkWidget *cond_hbox;
174         GtkWidget *cond_scrolledwin;
175         GtkWidget *cond_clist;
176
177         GtkWidget *btn_vbox;
178         GtkWidget *up_btn;
179         GtkWidget *down_btn;
180
181         GtkWidget *important_score_entry;
182         GtkWidget *kill_score_entry;
183         GtkWidget *kill_score_label;
184
185         gchar *title[] = {_("Registered rules")};
186
187         debug_print(_("Creating scoring setting window...\n"));
188
189         window = gtk_window_new (GTK_WINDOW_DIALOG);
190         gtk_container_set_border_width (GTK_CONTAINER (window), 8);
191         gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
192         gtk_window_set_modal (GTK_WINDOW (window), TRUE);
193         gtk_window_set_policy (GTK_WINDOW (window), FALSE, TRUE, FALSE);
194
195         vbox = gtk_vbox_new (FALSE, 6);
196         gtk_widget_show (vbox);
197         gtk_container_add (GTK_CONTAINER (window), vbox);
198
199         gtkut_button_set_create(&confirm_area, &ok_btn, _("OK"),
200                                 &cancel_btn, _("Cancel"), NULL, NULL);
201         gtk_widget_show (confirm_area);
202         gtk_box_pack_end (GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
203         gtk_widget_grab_default (ok_btn);
204
205         gtk_window_set_title (GTK_WINDOW(window),
206                               _("Scoring setting"));
207         gtk_signal_connect (GTK_OBJECT(window), "delete_event",
208                             GTK_SIGNAL_FUNC(prefs_scoring_deleted), NULL);
209         gtk_signal_connect (GTK_OBJECT(window), "key_press_event",
210                             GTK_SIGNAL_FUNC(prefs_scoring_key_pressed), NULL);
211         gtk_signal_connect (GTK_OBJECT(window), "focus_in_event",
212                             GTK_SIGNAL_FUNC(manage_window_focus_in), NULL);
213         gtk_signal_connect (GTK_OBJECT(window), "focus_out_event",
214                             GTK_SIGNAL_FUNC(manage_window_focus_out), NULL);
215         gtk_signal_connect (GTK_OBJECT(ok_btn), "clicked",
216                             GTK_SIGNAL_FUNC(prefs_scoring_ok), NULL);
217         gtk_signal_connect (GTK_OBJECT(cancel_btn), "clicked",
218                             GTK_SIGNAL_FUNC(prefs_scoring_cancel), NULL);
219
220         vbox1 = gtk_vbox_new (FALSE, VSPACING);
221         gtk_widget_show (vbox1);
222         gtk_box_pack_start (GTK_BOX (vbox), vbox1, TRUE, TRUE, 0);
223         gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
224
225         cond_label = gtk_label_new (_("Condition"));
226         gtk_widget_show (cond_label);
227         gtk_misc_set_alignment (GTK_MISC (cond_label), 0, 0.5);
228         gtk_box_pack_start (GTK_BOX (vbox1), cond_label, FALSE, FALSE, 0);
229
230         hbox1 = gtk_hbox_new (FALSE, VSPACING);
231         gtk_widget_show (vbox1);
232         gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
233         gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
234
235         cond_entry = gtk_entry_new ();
236         gtk_widget_show (cond_entry);
237         gtk_widget_set_usize (cond_entry, 300, -1);
238         gtk_box_pack_start (GTK_BOX (hbox1), cond_entry, TRUE, TRUE, 0);
239
240         cond_btn = gtk_button_new_with_label (_("Define ..."));
241         gtk_widget_show (cond_btn);
242         gtk_box_pack_start (GTK_BOX (hbox1), cond_btn, FALSE, FALSE, 0);
243         gtk_signal_connect (GTK_OBJECT (cond_btn), "clicked",
244                             GTK_SIGNAL_FUNC (prefs_scoring_condition_define),
245                             NULL);
246
247         hbox1 = gtk_hbox_new (FALSE, VSPACING);
248         gtk_widget_show (vbox1);
249         gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
250         gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
251
252         score_label = gtk_label_new (_("Score"));
253         gtk_widget_show (score_label);
254         gtk_misc_set_alignment (GTK_MISC (score_label), 0, 0.5);
255         gtk_box_pack_start (GTK_BOX (hbox1), score_label, FALSE, FALSE, 0);
256
257         score_entry = gtk_entry_new ();
258         gtk_widget_show (score_entry);
259         gtk_widget_set_usize (score_entry, 50, -1);
260         gtk_box_pack_start (GTK_BOX (hbox1), score_entry, FALSE, FALSE, 0);
261
262         /* register / substitute / delete */
263
264         reg_hbox = gtk_hbox_new (FALSE, 4);
265         gtk_widget_show (reg_hbox);
266         gtk_box_pack_start (GTK_BOX (vbox1), reg_hbox, FALSE, FALSE, 0);
267
268         arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
269         gtk_widget_show (arrow);
270         gtk_box_pack_start (GTK_BOX (reg_hbox), arrow, FALSE, FALSE, 0);
271         gtk_widget_set_usize (arrow, -1, 16);
272
273         btn_hbox = gtk_hbox_new (TRUE, 4);
274         gtk_widget_show (btn_hbox);
275         gtk_box_pack_start (GTK_BOX (reg_hbox), btn_hbox, FALSE, FALSE, 0);
276
277         reg_btn = gtk_button_new_with_label (_("Register"));
278         gtk_widget_show (reg_btn);
279         gtk_box_pack_start (GTK_BOX (btn_hbox), reg_btn, FALSE, TRUE, 0);
280         gtk_signal_connect (GTK_OBJECT (reg_btn), "clicked",
281                             GTK_SIGNAL_FUNC (prefs_scoring_register_cb), NULL);
282
283         subst_btn = gtk_button_new_with_label (_(" Substitute "));
284         gtk_widget_show (subst_btn);
285         gtk_box_pack_start (GTK_BOX (btn_hbox), subst_btn, FALSE, TRUE, 0);
286         gtk_signal_connect (GTK_OBJECT (subst_btn), "clicked",
287                             GTK_SIGNAL_FUNC (prefs_scoring_substitute_cb),
288                             NULL);
289
290         del_btn = gtk_button_new_with_label (_("Delete"));
291         gtk_widget_show (del_btn);
292         gtk_box_pack_start (GTK_BOX (btn_hbox), del_btn, FALSE, TRUE, 0);
293         gtk_signal_connect (GTK_OBJECT (del_btn), "clicked",
294                             GTK_SIGNAL_FUNC (prefs_scoring_delete_cb), NULL);
295
296         cond_hbox = gtk_hbox_new (FALSE, 8);
297         gtk_widget_show (cond_hbox);
298         gtk_box_pack_start (GTK_BOX (vbox1), cond_hbox, TRUE, TRUE, 0);
299
300         cond_scrolledwin = gtk_scrolled_window_new (NULL, NULL);
301         gtk_widget_show (cond_scrolledwin);
302         gtk_widget_set_usize (cond_scrolledwin, -1, 150);
303         gtk_box_pack_start (GTK_BOX (cond_hbox), cond_scrolledwin,
304                             TRUE, TRUE, 0);
305         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (cond_scrolledwin),
306                                         GTK_POLICY_AUTOMATIC,
307                                         GTK_POLICY_AUTOMATIC);
308
309         cond_clist = gtk_clist_new_with_titles(1, title);
310         gtk_widget_show (cond_clist);
311         gtk_container_add (GTK_CONTAINER (cond_scrolledwin), cond_clist);
312         gtk_clist_set_column_width (GTK_CLIST (cond_clist), 0, 80);
313         gtk_clist_set_selection_mode (GTK_CLIST (cond_clist),
314                                       GTK_SELECTION_BROWSE);
315         GTK_WIDGET_UNSET_FLAGS (GTK_CLIST (cond_clist)->column[0].button,
316                                 GTK_CAN_FOCUS);
317         gtk_signal_connect (GTK_OBJECT (cond_clist), "select_row",
318                             GTK_SIGNAL_FUNC (prefs_scoring_select), NULL);
319
320         btn_vbox = gtk_vbox_new (FALSE, 8);
321         gtk_widget_show (btn_vbox);
322         gtk_box_pack_start (GTK_BOX (cond_hbox), btn_vbox, FALSE, FALSE, 0);
323
324         up_btn = gtk_button_new_with_label (_("Up"));
325         gtk_widget_show (up_btn);
326         gtk_box_pack_start (GTK_BOX (btn_vbox), up_btn, FALSE, FALSE, 0);
327         gtk_signal_connect (GTK_OBJECT (up_btn), "clicked",
328                             GTK_SIGNAL_FUNC (prefs_scoring_up), NULL);
329
330         down_btn = gtk_button_new_with_label (_("Down"));
331         gtk_widget_show (down_btn);
332         gtk_box_pack_start (GTK_BOX (btn_vbox), down_btn, FALSE, FALSE, 0);
333         gtk_signal_connect (GTK_OBJECT (down_btn), "clicked",
334                             GTK_SIGNAL_FUNC (prefs_scoring_down), NULL);
335
336         hbox1 = gtk_hbox_new (FALSE, 8);
337         gtk_widget_show (hbox1);
338         gtk_box_pack_start (GTK_BOX (vbox1), hbox1, TRUE, TRUE, 0);
339
340         kill_score_label = gtk_label_new (_("Kill score"));
341         gtk_widget_show (kill_score_label);
342         gtk_misc_set_alignment (GTK_MISC (kill_score_label), 0, 0.5);
343         gtk_box_pack_start (GTK_BOX (hbox1), kill_score_label,
344                             FALSE, FALSE, 0);
345
346         kill_score_entry = gtk_entry_new ();
347         gtk_widget_show (kill_score_entry);
348         gtk_widget_set_usize (kill_score_entry, 50, -1);
349         gtk_box_pack_start (GTK_BOX (hbox1), kill_score_entry,
350                             FALSE, FALSE, 0);
351
352         score_label = gtk_label_new (_("Important score"));
353         gtk_widget_show (score_label);
354         gtk_misc_set_alignment (GTK_MISC (score_label), 0, 0.5);
355         gtk_box_pack_start (GTK_BOX (hbox1), score_label, FALSE, FALSE, 0);
356
357         important_score_entry = gtk_entry_new ();
358         gtk_widget_show (important_score_entry);
359         gtk_widget_set_usize (important_score_entry, 50, -1);
360         gtk_box_pack_start (GTK_BOX (hbox1), important_score_entry,
361                             FALSE, FALSE, 0);
362
363         gtk_widget_show_all(window);
364
365         scoring.window    = window;
366         scoring.ok_btn = ok_btn;
367
368         scoring.cond_entry = cond_entry;
369         scoring.score_entry = score_entry;
370         scoring.kill_score_entry = kill_score_entry;
371         scoring.kill_score_label = kill_score_label;
372         scoring.important_score_entry = important_score_entry;
373
374         scoring.cond_clist   = cond_clist;
375 }
376
377 static void prefs_scoring_set_dialog(ScoringProp * cond)
378 {
379         GtkCList *clist = GTK_CLIST(scoring.cond_clist);
380         GSList *cur;
381         GSList * prefs_scoring;
382         gchar * score_str;
383
384         if (cond == NULL)
385                 prefs_scoring_reset_dialog();
386         else
387                 prefs_scoring_select_set_dialog(cond);
388
389         gtk_clist_freeze(clist);
390         gtk_clist_clear(clist);
391
392         prefs_scoring_clist_set_row(-1, NULL);
393         if (cur_item == NULL) {
394                 prefs_scoring = global_scoring;
395                 cur_kill_score = prefs_common.kill_score;
396                 cur_important_score = prefs_common.important_score;
397                 gtk_widget_show(scoring.kill_score_label);
398                 gtk_widget_show(scoring.kill_score_entry);
399         }
400         else {
401                 prefs_scoring = cur_item->prefs->scoring;
402                 cur_kill_score = cur_item->prefs->kill_score;
403                 cur_important_score = cur_item->prefs->important_score;
404                 if (cur_item->folder->type != F_NEWS) {
405                         gtk_widget_hide(scoring.kill_score_label);
406                         gtk_widget_hide(scoring.kill_score_entry);
407                 }
408                 else {
409                         gtk_widget_show(scoring.kill_score_label);
410                         gtk_widget_show(scoring.kill_score_entry);
411                 }
412         }
413
414         for(cur = prefs_scoring ; cur != NULL ;
415             cur = g_slist_next(cur)) {
416                 ScoringProp * prop = (ScoringProp *) cur->data;
417                 
418                 prefs_scoring_clist_set_row(-1, prop);
419         }
420
421         score_str = itos(cur_kill_score);
422         gtk_entry_set_text(GTK_ENTRY(scoring.kill_score_entry),
423                            score_str);
424         score_str = itos(cur_important_score);
425         gtk_entry_set_text(GTK_ENTRY(scoring.important_score_entry),
426                            score_str);
427
428         gtk_clist_thaw(clist);
429 }
430
431 static void prefs_scoring_reset_dialog(void)
432 {
433         gtk_entry_set_text(GTK_ENTRY(scoring.cond_entry), "");
434         gtk_entry_set_text(GTK_ENTRY(scoring.score_entry), "");
435 }
436
437 static void prefs_scoring_set_list(void)
438 {
439         gint row = 1;
440         ScoringProp *prop;
441         GSList * cur;
442         gchar * scoring_str;
443         gchar * tmp;
444         GSList * prefs_scoring;
445
446         if (cur_item == NULL)
447                 prefs_scoring = global_scoring;
448         else
449                 prefs_scoring = cur_item->prefs->scoring;
450
451         for(cur = prefs_scoring ; cur != NULL ;
452             cur = g_slist_next(cur))
453                 scoringprop_free((ScoringProp *) cur->data);
454         g_slist_free(prefs_scoring);
455         prefs_scoring = NULL;
456
457         while (gtk_clist_get_text(GTK_CLIST(scoring.cond_clist),
458                                   row, 0, &scoring_str)) {
459                 if (strcmp(scoring_str, _("(New)")) != 0) {
460                         tmp = scoring_str;
461                         prop = scoringprop_parse(&tmp);
462                         if (prop != NULL)
463                                 prefs_scoring = g_slist_append(prefs_scoring,
464                                                                prop);
465                 }
466                 row++;
467         }
468
469         cur_kill_score = atoi(gtk_entry_get_text(GTK_ENTRY(scoring.kill_score_entry)));
470         cur_important_score = atoi(gtk_entry_get_text(GTK_ENTRY(scoring.important_score_entry)));
471
472         if (cur_item == NULL) {
473                 global_scoring = prefs_scoring;
474                 prefs_common.kill_score = cur_kill_score;
475                 prefs_common.important_score = cur_important_score;
476         }
477         else {
478                 cur_item->prefs->scoring = prefs_scoring;
479                 cur_item->prefs->kill_score = cur_kill_score;
480                 cur_item->prefs->important_score = cur_important_score;
481         }
482 }
483
484 static gint prefs_scoring_clist_set_row(gint row, ScoringProp * prop)
485 {
486         GtkCList *clist = GTK_CLIST(scoring.cond_clist);
487         gchar * str;
488         gchar *cond_str[1];
489
490         if (prop == NULL) {
491                 cond_str[0] = _("(New)");
492                 return gtk_clist_append(clist, cond_str);
493         }
494
495         str = scoringprop_to_string(prop);
496         if (str == NULL) {
497                 return -1;
498         }
499         cond_str[0] = str;
500
501         if (row < 0)
502                 row = gtk_clist_append(clist, cond_str);
503         else
504                 gtk_clist_set_text(clist, row, 0, cond_str[0]);
505         g_free(str);
506
507         return row;
508 }
509
510 static void prefs_scoring_condition_define_done(MatcherList * matchers)
511 {
512         gchar * str;
513
514         if (matchers == NULL)
515                 return;
516
517         str = matcherlist_to_string(matchers);
518
519         if (str != NULL) {
520                 gtk_entry_set_text(GTK_ENTRY(scoring.cond_entry), str);
521                 g_free(str);
522         }
523 }
524
525 static void prefs_scoring_condition_define(void)
526 {
527         gchar * cond_str;
528         MatcherList * matchers = NULL;
529
530         cond_str = gtk_entry_get_text(GTK_ENTRY(scoring.cond_entry));
531
532         if (*cond_str != '\0') {
533                 gchar * tmp;
534                 
535                 tmp = cond_str;
536                 matchers = matcherlist_parse(&tmp);
537                 if (tmp == NULL)
538                         alertpanel_error(_("Match string is not valid."));
539         }
540
541         prefs_matcher_open(matchers, prefs_scoring_condition_define_done);
542
543         if (matchers != NULL)
544                 matcherlist_free(matchers);
545 }
546
547
548 /* register / substitute delete buttons */
549
550 static void prefs_scoring_register_cb(void)
551 {
552         MatcherList * cond;
553         gchar * cond_str;
554         gchar * score_str;
555         ScoringProp * prop;
556         gint score;
557         gchar * tmp;
558
559         cond_str = gtk_entry_get_text(GTK_ENTRY(scoring.cond_entry));
560         if (*cond_str == '\0') {
561                 alertpanel_error(_("Score is not set."));
562                 return;
563         }
564
565         score_str = gtk_entry_get_text(GTK_ENTRY(scoring.score_entry));
566         if (*score_str == '\0') {
567                 alertpanel_error(_("Match string is not set."));
568                 return;
569         }
570
571         score = atoi(score_str);
572         tmp = cond_str;
573         cond = matcherlist_parse(&tmp);
574
575         if (tmp == NULL) {
576                 alertpanel_error(_("Match string is not valid."));
577                 return;
578         }
579
580         prop = scoringprop_new(cond, score);
581
582         prefs_scoring_clist_set_row(-1, prop);
583
584         scoringprop_free(prop);
585
586         prefs_scoring_reset_dialog();
587 }
588
589 static void prefs_scoring_substitute_cb(void)
590 {
591         GtkCList *clist = GTK_CLIST(scoring.cond_clist);
592         gint row;
593         MatcherList * cond;
594         gchar * cond_str;
595         gchar * score_str;
596         ScoringProp * prop;
597         gint score;
598         gchar * tmp;
599
600         if (!clist->selection) return;
601
602         row = GPOINTER_TO_INT(clist->selection->data);
603         if (row == 0) return;
604
605         cond_str = gtk_entry_get_text(GTK_ENTRY(scoring.cond_entry));
606         if (*cond_str == '\0') {
607                 alertpanel_error(_("Score is not set."));
608                 return;
609         }
610
611         score_str = gtk_entry_get_text(GTK_ENTRY(scoring.score_entry));
612         if (*score_str == '\0') {
613                 alertpanel_error(_("Match string is not set."));
614                 return;
615         }
616
617         score = atoi(score_str);
618         tmp = cond_str;
619         cond = matcherlist_parse(&tmp);
620
621         if (tmp == NULL) {
622                 alertpanel_error(_("Match string is not valid."));
623                 return;
624         }
625
626         prop = scoringprop_new(cond, score);
627
628         prefs_scoring_clist_set_row(row, prop);
629
630         scoringprop_free(prop);
631
632         prefs_scoring_reset_dialog();
633 }
634
635 static void prefs_scoring_delete_cb(void)
636 {
637         GtkCList *clist = GTK_CLIST(scoring.cond_clist);
638         gint row;
639
640         if (!clist->selection) return;
641         row = GPOINTER_TO_INT(clist->selection->data);
642         if (row == 0) return;
643
644         if (alertpanel(_("Delete rule"),
645                        _("Do you really want to delete this rule?"),
646                        _("Yes"), _("No"), NULL) == G_ALERTALTERNATE)
647                 return;
648
649         gtk_clist_remove(clist, row);
650 }
651
652 static void prefs_scoring_up(void)
653 {
654         GtkCList *clist = GTK_CLIST(scoring.cond_clist);
655         gint row;
656
657         if (!clist->selection) return;
658
659         row = GPOINTER_TO_INT(clist->selection->data);
660         if (row > 1) {
661                 gtk_clist_row_move(clist, row, row - 1);
662                 if(gtk_clist_row_is_visible(clist, row - 1) != GTK_VISIBILITY_FULL) {
663                         gtk_clist_moveto(clist, row - 1, 0, 0, 0);
664                 } 
665         }
666 }
667
668 static void prefs_scoring_down(void)
669 {
670         GtkCList *clist = GTK_CLIST(scoring.cond_clist);
671         gint row;
672
673         if (!clist->selection) return;
674
675         row = GPOINTER_TO_INT(clist->selection->data);
676         if (row > 0 && row < clist->rows - 1) {
677                 gtk_clist_row_move(clist, row, row + 1);
678                 if(gtk_clist_row_is_visible(clist, row + 1) != GTK_VISIBILITY_FULL) {
679                         gtk_clist_moveto(clist, row + 1, 0, 1, 0);
680                 } 
681         }
682 }
683
684 static void prefs_scoring_select_set_dialog(ScoringProp * prop)
685 {
686         gchar * matcher_str;
687         gchar * score_str;
688
689         if (prop == NULL)
690                 return;
691
692         matcher_str = matcherlist_to_string(prop->matchers);
693         if (matcher_str == NULL) {
694                 scoringprop_free(prop);
695                 return;
696         }
697
698         score_str = itos(prop->score);
699
700         gtk_entry_set_text(GTK_ENTRY(scoring.cond_entry), matcher_str);
701         gtk_entry_set_text(GTK_ENTRY(scoring.score_entry), score_str);
702
703         g_free(matcher_str);
704 }
705
706 static void prefs_scoring_select(GtkCList *clist, gint row, gint column,
707                                 GdkEvent *event)
708 {
709         ScoringProp * prop;
710         gchar * tmp;
711
712         gchar * scoring_str;
713
714         if (row == 0) {
715                 prefs_scoring_reset_dialog();
716                 return;
717         }
718
719         if (!gtk_clist_get_text(GTK_CLIST(scoring.cond_clist),
720                                 row, 0, &scoring_str))
721                 return;
722
723         tmp = scoring_str;
724         prop = scoringprop_parse(&tmp);
725         if (tmp == NULL)
726                 return;
727
728         prefs_scoring_select_set_dialog(prop);
729
730         scoringprop_free(prop);
731 }
732
733 static gint prefs_scoring_deleted(GtkWidget *widget, GdkEventAny *event,
734                                  gpointer data)
735 {
736         prefs_scoring_cancel();
737         return TRUE;
738 }
739
740 static void prefs_scoring_key_pressed(GtkWidget *widget, GdkEventKey *event,
741                                      gpointer data)
742 {
743         if (event && event->keyval == GDK_Escape)
744                 prefs_scoring_cancel();
745 }
746
747 static void prefs_scoring_ok(void)
748 {
749         prefs_scoring_set_list();
750         prefs_scoring_write_config();
751         if (cur_item != NULL)
752                 prefs_folder_item_save_config(cur_item);
753         gtk_widget_hide(scoring.window);
754 }
755
756 static void prefs_scoring_cancel(void)
757 {
758         prefs_scoring_read_config();
759         gtk_widget_hide(scoring.window);
760 }