Split "filter_dialog_cb()" into "filter_dialog_cb()", which pops up a
[obnox/wireshark/wip.git] / gtk / filter_prefs.c
1 /* filter_prefs.c
2  * Dialog boxes for filter editing
3  * (This used to be a notebook page under "Preferences", hence the
4  * "prefs" in the file name.)
5  *
6  * $Id: filter_prefs.c,v 1.11 2000/04/01 12:03:40 guy Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * 
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <gtk/gtk.h>
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40 #include <ctype.h>
41 #ifdef HAVE_DIRECT_H
42 #include <direct.h>
43 #endif
44
45 #include "gtk/main.h"
46 #include "filter_prefs.h"
47 #include "packet.h"
48 #include "file.h"
49 #include "util.h"
50 #include "ui_util.h"
51 #include "prefs_dlg.h"
52
53 #define E_FILT_NAME_KEY "filter_name"
54 #define E_FILT_LBL_KEY  "filter_label"
55 #define E_FILT_CM_KEY   "in_cancel_mode"
56 #define E_FILTER_WIDGET_KEY "filter_widget"
57
58 typedef struct _filter_def {
59   char *name;
60   char *strval;
61 } filter_def;
62
63 typedef struct _filter_cb_data {
64   GList     *fl;
65   GtkWidget *win;
66 } filter_cb_data;
67
68
69 static GtkWidget   *filter_l, *chg_bt, *copy_bt, *del_bt, *name_te, *filter_te, *apply_bt;
70 static GList       *fl = NULL;
71
72 static void get_filter_list(void);
73 static GtkWidget *filter_dialog_new(GtkWidget *caller, GtkWidget *filter_te);
74 static void filter_dlg_ok(GtkWidget *ok_bt, gpointer parent_w);
75 static void filter_dlg_save(GtkWidget *save_bt, gpointer parent_w);
76 static void filter_dlg_cancel(GtkWidget *cancel_bt, gpointer parent_w);
77 static void filter_dlg_destroy(GtkWidget *win, gpointer data);
78 static void filter_sel_apply_cb(GtkWidget *cancel_bt, gpointer parent_w);
79
80 static GtkWidget *filter_prefs_show(GtkWidget *);
81 static void       filter_sel_list_cb(GtkWidget *, gpointer);
82 static void       filter_sel_new_cb(GtkWidget *, gpointer);
83 static void       filter_sel_chg_cb(GtkWidget *, gpointer);
84 static void       filter_sel_copy_cb(GtkWidget *, gpointer);
85 static void       filter_sel_del_cb(GtkWidget *, gpointer);
86 static void       filter_prefs_ok(GtkWidget *);
87 static void       filter_prefs_save(GtkWidget *);
88 static void       filter_prefs_cancel(GtkWidget *);
89 static void       filter_prefs_delete(GtkWidget *);
90
91 #define FILTER_LINE_SIZE        2048
92
93 static void
94 get_filter_list(void)
95 {
96   filter_def *filt;
97   FILE       *ff;
98   gchar      *ff_path, *ff_name = PF_DIR "/filters", f_buf[FILTER_LINE_SIZE];
99   gchar      *name_begin, *name_end, *filt_begin;
100   int         len, line = 0;
101
102   if (fl) return;
103   
104   /* To do: generalize this */
105   ff_path = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(ff_name) +  4);
106   sprintf(ff_path, "%s/%s", get_home_dir(), ff_name);
107
108   if ((ff = fopen(ff_path, "r")) == NULL) {
109     g_free(ff_path);
110     return;
111   }
112
113   while (fgets(f_buf, FILTER_LINE_SIZE, ff)) {
114     line++;
115     len = strlen(f_buf);
116     if (f_buf[len - 1] == '\n') {
117       len--;
118       f_buf[len] = '\0';
119     }
120     name_begin = strchr(f_buf, '"');
121     /* Empty line */
122     if (name_begin == NULL)
123       continue;
124     name_end = strchr(name_begin + 1, '"');
125     /* No terminating quote */
126     if (name_end == NULL) {
127       g_warning("Malformed filter in '%s' line %d.", ff_path, line);
128       continue;
129     }
130     name_begin++;
131     name_end[0] = '\0';
132     filt_begin  = name_end + 1;
133     while(isspace(filt_begin[0])) filt_begin++;
134     /* No filter string */
135     if (filt_begin[0] == '\0') {
136       g_warning("Malformed filter in '%s' line %d.", ff_path, line);
137       continue;
138     }
139     filt         = (filter_def *) g_malloc(sizeof(filter_def));
140     filt->name   = g_strdup(name_begin);
141     filt->strval = g_strdup(filt_begin);
142     fl = g_list_append(fl, filt);
143   }
144   fclose(ff);
145   g_free(ff_path);
146 }
147
148 /* XXX - we can have one global dialog box for editing, and a bunch
149    of dialog boxes associated with browse buttons; we want the dialog
150    boxes associated with browse buttons to at least let you save the
151    current filter, so they have to allow editing; however, how do we
152    arrange that if a change is made to the filter list, other dialog
153    boxes get updated appropriately? */
154
155 /* Create a filter dialog for browsing; this is to be used as a callback
156    for a button next to a text entry box, which, when clicked, allows
157    you to browse through the list of filters to select one to be put
158    into the text entry box, and, if you select a filter with this
159    dialog box, enters the text of the filter into a text entry box
160    associated with the button. */
161 void
162 filter_browse_cb(GtkWidget *w)
163 {
164         GtkWidget *caller = gtk_widget_get_toplevel(w);
165         GtkWidget *filter_browse_w;
166         GtkWidget *filter_te;
167
168         /* Has a filter dialog box already been opened for that top-level
169            widget? */
170         filter_browse_w = gtk_object_get_data(GTK_OBJECT(caller),
171             E_FILT_DIALOG_PTR_KEY);
172
173         if (filter_browse_w != NULL) {
174                 /* Yes.  Just re-activate that dialog box. */
175                 reactivate_window(filter_browse_w);
176                 return;
177         }
178
179         /* No.  Get the text entry attached to the button. */
180         filter_te = gtk_object_get_data(GTK_OBJECT(w), E_FILT_TE_PTR_KEY);
181
182         /* Now create a new dialog. */
183         filter_browse_w = filter_dialog_new(caller, filter_te);
184
185         /* Set the E_FILT_CALLER_PTR_KEY for the new dialog to point to
186            our caller. */
187         gtk_object_set_data(GTK_OBJECT(filter_browse_w), E_FILT_CALLER_PTR_KEY,
188             caller);
189
190         /* Set the E_FILT_DIALOG_PTR_KEY for the caller to point to us */
191         gtk_object_set_data(GTK_OBJECT(caller), E_FILT_DIALOG_PTR_KEY,
192             filter_browse_w);
193 }
194
195 static GtkWidget *global_filter_w;
196
197 /* Create a filter dialog for editing; this is to be used as a callback
198    for menu items, toolbars, etc.. */
199 void
200 filter_dialog_cb(GtkWidget *w)
201 {
202         /* Has a filter dialog box already been opened for editing? */
203         if (global_filter_w != NULL) {
204                 /* Yes.  Just reactivate it. */
205                 reactivate_window(global_filter_w);
206                 return;
207         }
208
209         /* No.  Create one. */
210         global_filter_w = filter_dialog_new(NULL, NULL);
211 }
212
213 static GtkWidget *
214 filter_dialog_new(GtkWidget *caller, GtkWidget *filter_te)
215 {
216         GtkWidget       *main_w,        /* main window */
217                         *main_vb,       /* main container */
218                         *bbox,          /* button container */
219                         *ok_bt,         /* ok button */
220                         *save_bt,       /* save button */
221                         *cancel_bt;     /* cancel button */ 
222         GtkWidget *filter_pg = NULL;    /* filter settings box */
223
224         main_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
225         gtk_window_set_title(GTK_WINDOW(main_w), "Ethereal: Filters");
226
227         /* Call a handler when we're destroyed, so we can inform
228            our caller, if any, that we've been destroyed. */
229         gtk_signal_connect(GTK_OBJECT(main_w), "destroy",
230             GTK_SIGNAL_FUNC(filter_dlg_destroy), NULL);
231
232         main_vb = gtk_vbox_new(FALSE, 5);
233         gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
234         gtk_container_add(GTK_CONTAINER(main_w), main_vb);
235         gtk_widget_show(main_vb);
236
237         filter_pg = filter_prefs_show(filter_te);
238         gtk_box_pack_start(GTK_BOX(main_vb), filter_pg, TRUE, TRUE, 0);
239         gtk_object_set_data(GTK_OBJECT(filter_pg), E_FILT_TE_PTR_KEY, filter_te);
240         gtk_object_set_data(GTK_OBJECT(main_w), E_FILTER_WIDGET_KEY, filter_pg);
241
242         bbox = gtk_hbutton_box_new();
243         gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
244         gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
245         gtk_container_add(GTK_CONTAINER(main_vb), bbox);
246         gtk_widget_show(bbox);
247
248         ok_bt = gtk_button_new_with_label ("OK");
249         gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
250                 GTK_SIGNAL_FUNC(filter_dlg_ok), GTK_OBJECT(main_w));
251         GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
252         gtk_box_pack_start(GTK_BOX(bbox), ok_bt, TRUE, TRUE, 0);
253         gtk_widget_grab_default(ok_bt);
254         gtk_widget_show(ok_bt);
255
256         save_bt = gtk_button_new_with_label ("Save");
257         gtk_signal_connect(GTK_OBJECT(save_bt), "clicked",
258                 GTK_SIGNAL_FUNC(filter_dlg_save), GTK_OBJECT(main_w));
259         GTK_WIDGET_SET_FLAGS(save_bt, GTK_CAN_DEFAULT);
260         gtk_box_pack_start(GTK_BOX(bbox), save_bt, TRUE, TRUE, 0);
261         gtk_widget_show(save_bt);
262
263         cancel_bt = gtk_button_new_with_label ("Cancel");
264         gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
265                 GTK_SIGNAL_FUNC(filter_dlg_cancel), GTK_OBJECT(main_w));
266         GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
267         gtk_box_pack_start(GTK_BOX(bbox), cancel_bt, TRUE, TRUE, 0);
268         gtk_widget_show(cancel_bt);
269
270         gtk_widget_show(main_w);
271
272         return main_w;
273 }
274
275 static void
276 filter_dlg_ok(GtkWidget *ok_bt, gpointer parent_w)
277 {
278         filter_prefs_ok(gtk_object_get_data(GTK_OBJECT(parent_w), E_FILTER_WIDGET_KEY));
279         gtk_widget_destroy(GTK_WIDGET(parent_w));
280 }
281
282 static void
283 filter_dlg_save(GtkWidget *save_bt, gpointer parent_w)
284 {
285         filter_prefs_save(gtk_object_get_data(GTK_OBJECT(parent_w), E_FILTER_WIDGET_KEY));
286 }
287
288 static void
289 filter_dlg_cancel(GtkWidget *cancel_bt, gpointer parent_w)
290 {
291         filter_prefs_cancel(gtk_object_get_data(GTK_OBJECT(parent_w),  E_FILTER_WIDGET_KEY));
292         gtk_widget_destroy(GTK_WIDGET(parent_w));
293 }
294
295 static void
296 filter_dlg_destroy(GtkWidget *win, gpointer data)
297 {
298         GtkWidget *caller;
299
300         /* Get the widget that requested that we be popped up, if any.
301            (It should arrange to destroy us if it's destroyed, so
302            that we don't get a pointer to a non-existent window here.) */
303         caller = gtk_object_get_data(GTK_OBJECT(win), E_FILT_CALLER_PTR_KEY);
304
305         if (caller != NULL) {
306                 /* Tell it we no longer exist. */
307                 gtk_object_set_data(GTK_OBJECT(caller), E_FILT_DIALOG_PTR_KEY,
308                     NULL);
309         } else {
310                 /* This is an editing dialog popped up from, for example,
311                    a menu item; note that we no longer have one. */
312                 g_assert(win == global_filter_w);
313                 global_filter_w = NULL;
314         }
315
316         /* Now nuke this window. */
317         gtk_grab_remove(GTK_WIDGET(win));
318         gtk_widget_destroy(GTK_WIDGET(win));
319 }
320
321 /* Create and display the filter selection widgets. */
322 static GtkWidget *
323 filter_prefs_show(GtkWidget *w) {
324   GtkWidget  *main_vb, *top_hb, *list_bb, *new_bt, *filter_sc,
325              *nl_item, *nl_lb, *middle_hb, *name_lb, *bottom_hb,
326              *filter_lb;
327   GtkWidget  *l_select = NULL;
328   GList      *flp = NULL;
329   filter_def *filt;
330   gchar      *filter_te_str = NULL;
331
332   /* Make sure everything is set up */  
333   get_filter_list();
334   if (w)
335     filter_te_str = gtk_entry_get_text(GTK_ENTRY(w));
336
337   /* Container for each row of widgets */
338   main_vb = gtk_vbox_new(FALSE, 5);
339   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
340   gtk_widget_show(main_vb);
341   gtk_object_set_data(GTK_OBJECT(main_vb), E_FILT_CM_KEY, (gpointer)FALSE);
342   
343   /* Top row: Filter list and buttons */
344   top_hb = gtk_hbox_new(FALSE, 5);
345   gtk_container_add(GTK_CONTAINER(main_vb), top_hb);
346   gtk_widget_show(top_hb);
347   
348   list_bb = gtk_vbutton_box_new();
349   gtk_button_box_set_layout (GTK_BUTTON_BOX (list_bb), GTK_BUTTONBOX_START);
350   gtk_container_add(GTK_CONTAINER(top_hb), list_bb);
351   gtk_widget_show(list_bb);
352
353   new_bt = gtk_button_new_with_label ("New");
354   gtk_signal_connect(GTK_OBJECT(new_bt), "clicked",
355     GTK_SIGNAL_FUNC(filter_sel_new_cb), NULL);
356   gtk_container_add(GTK_CONTAINER(list_bb), new_bt);
357   gtk_widget_show(new_bt);
358   
359   chg_bt = gtk_button_new_with_label ("Change");
360   gtk_widget_set_sensitive(chg_bt, FALSE);
361   gtk_signal_connect(GTK_OBJECT(chg_bt), "clicked",
362     GTK_SIGNAL_FUNC(filter_sel_chg_cb), NULL);
363   gtk_container_add(GTK_CONTAINER(list_bb), chg_bt);
364   gtk_widget_show(chg_bt);
365   
366   copy_bt = gtk_button_new_with_label ("Copy");
367   gtk_widget_set_sensitive(copy_bt, FALSE);
368   gtk_signal_connect(GTK_OBJECT(copy_bt), "clicked",
369     GTK_SIGNAL_FUNC(filter_sel_copy_cb), NULL);
370   gtk_container_add(GTK_CONTAINER(list_bb), copy_bt);
371   gtk_widget_show(copy_bt);
372   
373   del_bt = gtk_button_new_with_label ("Delete");
374   gtk_widget_set_sensitive(del_bt, FALSE);
375   gtk_signal_connect(GTK_OBJECT(del_bt), "clicked",
376     GTK_SIGNAL_FUNC(filter_sel_del_cb), NULL);
377   gtk_container_add(GTK_CONTAINER(list_bb), del_bt);
378   gtk_widget_show(del_bt);
379
380   apply_bt = gtk_button_new_with_label("Apply");
381   gtk_widget_set_sensitive(apply_bt, FALSE);
382   gtk_signal_connect(GTK_OBJECT(apply_bt), "clicked",
383     GTK_SIGNAL_FUNC(filter_sel_apply_cb), w);
384   gtk_container_add(GTK_CONTAINER(list_bb), apply_bt);
385   gtk_widget_show(apply_bt);
386
387   filter_sc = gtk_scrolled_window_new(NULL, NULL);
388   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(filter_sc),
389     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
390   gtk_widget_set_usize(filter_sc, 250, 150);
391   gtk_container_add(GTK_CONTAINER(top_hb), filter_sc);
392   gtk_widget_show(filter_sc);
393
394   filter_l = gtk_list_new();
395   gtk_list_set_selection_mode(GTK_LIST(filter_l), GTK_SELECTION_SINGLE);
396   gtk_signal_connect(GTK_OBJECT(filter_l), "selection_changed",
397     GTK_SIGNAL_FUNC(filter_sel_list_cb), main_vb);
398   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(filter_sc),
399     filter_l);
400   gtk_widget_show(filter_l);
401
402   flp = g_list_first(fl);
403   while (flp) {
404     filt    = (filter_def *) flp->data;
405     nl_lb   = gtk_label_new(filt->name);
406     nl_item = gtk_list_item_new();
407     gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5);
408     gtk_container_add(GTK_CONTAINER(nl_item), nl_lb);
409     gtk_widget_show(nl_lb);
410     gtk_container_add(GTK_CONTAINER(filter_l), nl_item);
411     gtk_widget_show(nl_item);
412     gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_LBL_KEY, nl_lb);
413     gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_NAME_KEY, flp);
414  
415     if (filter_te_str && filt->strval)
416       if (strcmp(filter_te_str, filt->strval) == 0)
417         l_select = nl_item;
418
419     flp = flp->next;
420   }
421   
422   /* Middle row: Filter name entry */
423   middle_hb = gtk_hbox_new(FALSE, 5);
424   gtk_container_add(GTK_CONTAINER(main_vb), middle_hb);
425   gtk_widget_show(middle_hb);
426   
427   name_lb = gtk_label_new("Filter name:");
428   gtk_box_pack_start(GTK_BOX(middle_hb), name_lb, FALSE, FALSE, 3);
429   gtk_widget_show(name_lb);
430   
431   name_te = gtk_entry_new();
432   gtk_box_pack_start(GTK_BOX(middle_hb), name_te, TRUE, TRUE, 3);
433   gtk_widget_show(name_te);
434
435   /* Bottom row: Filter text entry */
436   bottom_hb = gtk_hbox_new(FALSE, 5);
437   gtk_container_add(GTK_CONTAINER(main_vb), bottom_hb);
438   gtk_widget_show(bottom_hb);
439   
440   filter_lb = gtk_label_new("Filter string:");
441   gtk_box_pack_start(GTK_BOX(bottom_hb), filter_lb, FALSE, FALSE, 3);
442   gtk_widget_show(filter_lb);
443   
444   filter_te = gtk_entry_new();
445   gtk_box_pack_start(GTK_BOX(bottom_hb), filter_te, TRUE, TRUE, 3);
446   gtk_widget_show(filter_te);
447
448   if (l_select)
449   {
450     gtk_list_select_child(GTK_LIST(filter_l), l_select);
451   } else if (filter_te_str && filter_te_str[0]) {
452     gtk_entry_set_text(GTK_ENTRY(name_te), "New filter");
453     gtk_entry_set_text(GTK_ENTRY(filter_te), filter_te_str);
454   }
455     
456   return(main_vb);
457 }
458
459 static void
460 filter_sel_list_cb(GtkWidget *l, gpointer data) {
461   filter_def *filt;
462   gchar      *name = "", *strval = "";
463   GList      *sl, *flp;
464   GtkObject  *l_item;
465   gint        sensitivity = FALSE;
466
467   if (l)
468           sl = GTK_LIST(l)->selection;
469   else
470           sl = NULL;
471           
472   if (sl) {  /* Something was selected */
473     l_item = GTK_OBJECT(sl->data);
474     flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
475     if (flp) {
476       filt   = (filter_def *) flp->data;
477       name   = filt->name;
478       strval = filt->strval;
479       sensitivity = TRUE;
480     }
481   }
482
483   /* Did you know that this function is called when the window is destroyed? */
484   /* Funny, that. */
485   if (!gtk_object_get_data(GTK_OBJECT(data), E_FILT_CM_KEY)) {
486     gtk_entry_set_text(GTK_ENTRY(name_te), name);
487     gtk_entry_set_text(GTK_ENTRY(filter_te), strval);
488     gtk_widget_set_sensitive(chg_bt, sensitivity);
489     gtk_widget_set_sensitive(copy_bt, sensitivity);
490     gtk_widget_set_sensitive(del_bt, sensitivity);
491     gtk_widget_set_sensitive(apply_bt, sensitivity);
492   }
493 }
494
495 /* To do: add input checking to each of these callbacks */
496  
497 static void
498 filter_sel_new_cb(GtkWidget *w, gpointer data) {
499   filter_def *filt;
500   gchar      *name, *strval;
501   GtkWidget  *nl_item, *nl_lb;
502   
503   name   = gtk_entry_get_text(GTK_ENTRY(name_te));
504   strval = gtk_entry_get_text(GTK_ENTRY(filter_te));
505   
506   if (strlen(name) > 0 && strlen(strval) > 0) {
507     filt         = (filter_def *) g_malloc(sizeof(filter_def));
508     filt->name   = g_strdup(name);
509     filt->strval = g_strdup(strval);
510     fl           = g_list_append(fl, filt);
511     nl_lb        = gtk_label_new(filt->name);
512     nl_item      = gtk_list_item_new();
513     gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5);
514     gtk_container_add(GTK_CONTAINER(nl_item), nl_lb);
515     gtk_widget_show(nl_lb);
516     gtk_container_add(GTK_CONTAINER(filter_l), nl_item);
517     gtk_widget_show(nl_item);
518     gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_LBL_KEY, nl_lb);
519     gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_NAME_KEY, g_list_last(fl));
520     gtk_list_select_child(GTK_LIST(filter_l), nl_item);
521   }
522 }
523
524 static void
525 filter_sel_chg_cb(GtkWidget *w, gpointer data) {
526   filter_def *filt;
527   gchar      *name = "", *strval = "";
528   GList      *sl, *flp;
529   GtkObject  *l_item;
530   GtkLabel   *nl_lb;
531
532   sl     = GTK_LIST(filter_l)->selection;
533   name   = gtk_entry_get_text(GTK_ENTRY(name_te));
534   strval = gtk_entry_get_text(GTK_ENTRY(filter_te));
535
536   if (sl) {  /* Something was selected */
537     l_item = GTK_OBJECT(sl->data);
538     flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
539     nl_lb  = (GtkLabel *) gtk_object_get_data(l_item, E_FILT_LBL_KEY);
540     if (flp && nl_lb) {
541       filt = (filter_def *) flp->data;
542       
543       if (strlen(name) > 0 && strlen(strval) > 0 && filt) {
544         g_free(filt->name);
545         g_free(filt->strval);
546         filt->name   = g_strdup(name);
547         filt->strval = g_strdup(strval);
548         gtk_label_set(nl_lb, filt->name);
549       }
550     }
551   }
552 }
553
554 static void
555 filter_sel_copy_cb(GtkWidget *w, gpointer data) {
556   GList      *sl, *flp;
557   filter_def *filt, *nfilt;
558   gchar      *prefix = "Copy of ";
559   GtkObject  *l_item;
560   GtkWidget  *nl_item, *nl_lb;
561   
562   sl     = GTK_LIST(filter_l)->selection;
563   if (sl) {  /* Something was selected */
564     l_item = GTK_OBJECT(sl->data);
565     flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
566     if (flp) {
567       filt          = (filter_def *) flp->data;
568       nfilt         = (filter_def *) g_malloc(sizeof(filter_def));
569       nfilt->name   = g_malloc(strlen(prefix) + strlen(filt->name) + 1);
570       sprintf(nfilt->name, "%s%s", prefix, filt->name);
571       nfilt->strval = g_strdup(filt->strval);
572       fl            = g_list_append(fl, nfilt);
573       nl_lb         = gtk_label_new(nfilt->name);
574       nl_item       = gtk_list_item_new();
575       gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5);
576       gtk_container_add(GTK_CONTAINER(nl_item), nl_lb);
577       gtk_widget_show(nl_lb);
578       gtk_container_add(GTK_CONTAINER(filter_l), nl_item);
579       gtk_widget_show(nl_item);
580       gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_LBL_KEY, nl_lb);
581       gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_NAME_KEY, g_list_last(fl));
582       gtk_list_select_child(GTK_LIST(filter_l), nl_item);
583     }
584   }
585 }
586
587 static void
588 filter_sel_del_cb(GtkWidget *w, gpointer data) {
589   GList      *sl, *flp;
590   filter_def *filt;
591   GtkObject  *l_item;
592   gint        pos;
593   
594   sl = GTK_LIST(filter_l)->selection;
595   if (sl) {  /* Something was selected */
596     l_item = GTK_OBJECT(sl->data);
597     pos    = gtk_list_child_position(GTK_LIST(filter_l),
598       GTK_WIDGET(l_item));
599     flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
600     if (flp) {
601       filt = (filter_def *) flp->data;
602       g_free(filt->name);
603       g_free(filt->strval);
604       g_free(filt);
605       fl = g_list_remove_link(fl, flp);
606       gtk_list_clear_items(GTK_LIST(filter_l), pos, pos + 1);
607     } 
608   }
609 }
610
611 void
612 filter_sel_apply_cb(GtkWidget *w, gpointer data)
613 {
614         GList      *flp, *sl;
615         GtkObject  *l_item;
616         filter_def *filt;
617         GtkWidget  *mw_filt = data;
618         
619         sl = GTK_LIST(filter_l)->selection;
620         if (sl != NULL && mw_filt != NULL) {  /* Place something in the filter box. */
621                 l_item = GTK_OBJECT(sl->data);
622                 flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
623                 if (flp) {
624                         filt = (filter_def *) flp->data;
625                         gtk_entry_set_text(GTK_ENTRY(mw_filt), filt->strval);
626                         gtk_signal_emit_by_name(GTK_OBJECT(mw_filt), "activate");
627                 }
628         }
629 }
630
631 static void
632 filter_prefs_ok(GtkWidget *w) {
633   GList      *flp, *sl;
634   GtkObject  *l_item;
635   filter_def *filt;
636   GtkWidget  *mw_filt = gtk_object_get_data(GTK_OBJECT(w), E_FILT_TE_PTR_KEY);
637
638   sl = GTK_LIST(filter_l)->selection;
639   if (sl && mw_filt) {  /* Place something in the filter box. */
640     l_item = GTK_OBJECT(sl->data);
641     flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
642     if (flp) {
643       filt = (filter_def *) flp->data;
644       gtk_entry_set_text(GTK_ENTRY(mw_filt), filt->strval);
645     }
646   }
647
648   filter_prefs_delete(w);
649 }
650
651 static void
652 filter_prefs_save(GtkWidget *w) {
653   GList       *flp;
654   filter_def  *filt;
655   gchar       *ff_path, *ff_dir = PF_DIR, *ff_name = "filters";
656   FILE        *ff;
657   struct stat  s_buf;
658   
659   ff_path = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(ff_dir) +  
660     strlen(ff_name) + 4);
661   sprintf(ff_path, "%s/%s", get_home_dir(), ff_dir);
662
663   if (stat(ff_path, &s_buf) != 0)
664 #ifdef WIN32
665     mkdir(ff_path);
666 #else
667     mkdir(ff_path, 0755);
668 #endif
669     
670   sprintf(ff_path, "%s/%s/%s", get_home_dir(), ff_dir, ff_name);
671
672   if ((ff = fopen(ff_path, "w")) != NULL) {
673     flp = g_list_first(fl);
674     while (flp) {
675       filt = (filter_def *) flp->data;
676       fprintf(ff, "\"%s\" %s\n", filt->name, filt->strval);
677       flp = flp->next;
678     }
679     fclose(ff);
680   }
681
682   g_free(ff_path);
683 }
684
685 static void
686 filter_prefs_cancel(GtkWidget *w) {
687
688   filter_prefs_delete(w);
689 }
690
691 static void
692 filter_prefs_delete(GtkWidget *w) {
693  
694   /* Let the list cb know we're about to destroy the widget tree, so it */
695   /* doesn't operate on widgets that don't exist. */  
696   gtk_object_set_data(GTK_OBJECT(w), E_FILT_CM_KEY, (gpointer)TRUE);
697   gtk_widget_destroy(GTK_WIDGET(w));
698