2 * Dialog boxes for (display and capture) filter editing
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 #include <epan/filesystem.h>
37 #include "filter_dlg.h"
38 #include "dlg_utils.h"
39 #include "gui_utils.h"
40 #include "simple_dialog.h"
41 #include "dfilter_expr_dlg.h"
42 #include "compat_macros.h"
43 #include "gtkglobals.h"
45 #include <epan/prefs.h>
47 #define E_FILT_DIALOG_PTR_KEY "filter_dialog_ptr"
48 #define E_FILT_BUTTON_PTR_KEY "filter_button_ptr"
49 #define E_FILT_PARENT_FILTER_TE_KEY "filter_parent_filter_te"
50 #define E_FILT_CONSTRUCT_ARGS_KEY "filter_construct_args"
51 #define E_FILT_LIST_ITEM_MODEL_KEY "filter_list_item_model"
52 #define E_FILT_LBL_KEY "filter_label"
53 #define E_FILT_FILTER_L_KEY "filter_filter_l"
54 #define E_FILT_CHG_BT_KEY "filter_chg_bt"
55 #define E_FILT_COPY_BT_KEY "filter_copy_bt"
56 #define E_FILT_DEL_BT_KEY "filter_del_bt"
57 #define E_FILT_NAME_TE_KEY "filter_name_te"
58 #define E_FILT_DBLFUNC_KEY "filter_dblfunc"
59 #define E_FILT_DBLARG_KEY "filter_dblarg"
60 #define E_FILT_DBLACTIVATE_KEY "filter_dblactivate"
62 typedef struct _filter_cb_data {
67 static GtkWidget *filter_dialog_new(GtkWidget *button, GtkWidget *filter_te,
68 filter_list_type_t list_type,
69 construct_args_t *construct_args);
70 static void filter_dlg_dclick(GtkWidget *dummy, gpointer main_w_arg,
72 static void filter_dlg_ok_cb(GtkWidget *ok_bt, gpointer data);
73 static void filter_dlg_apply_cb(GtkWidget *apply_bt, gpointer data);
74 static void filter_apply(GtkWidget *main_w, gboolean destroy);
75 static void filter_dlg_save(filter_list_type_t list_type);
76 static void filter_dlg_save_cb(GtkWidget *save_bt, gpointer parent_w);
77 static void filter_dlg_destroy_cb(GtkWidget *win, gpointer data);
80 filter_dlg_delete_event_cb(GtkWidget *prefs_w, GdkEvent *event, gpointer data);
82 filter_dlg_cancel_cb(GtkWidget *cancel_bt, gpointer data);
84 static gint filter_sel_list_button_cb(GtkWidget *, GdkEventButton *,
86 #if GTK_MAJOR_VERSION < 2
87 static void filter_sel_list_cb(GtkWidget *, gpointer);
89 static void filter_sel_list_cb(GtkTreeSelection *, gpointer);
91 static void filter_new_bt_clicked_cb(GtkWidget *, gpointer);
92 static void filter_del_bt_clicked_cb(GtkWidget *, gpointer);
93 static void filter_name_te_changed_cb(GtkWidget *, gpointer);
96 /* Create a filter dialog for constructing a capture filter.
98 This is to be used as a callback for a button next to a text entry box,
99 which, when clicked, pops up this dialog to allow you to construct a
100 display filter by browsing the list of saved filters (the dialog
101 for constructing expressions assumes display filter syntax, not
102 capture filter syntax). The "OK" button sets the text entry box to the
103 constructed filter and activates that text entry box (which should have
104 no effect in the main capture dialog); this dialog is then dismissed. */
106 capture_filter_construct_cb(GtkWidget *w, gpointer user_data _U_)
108 GtkWidget *filter_browse_w;
109 GtkWidget *parent_filter_te;
110 /* No Apply button, and "OK" just sets our text widget, it doesn't
111 activate it (i.e., it doesn't cause us to try to open the file). */
112 static construct_args_t args = {
113 "Wireshark: Capture Filter",
119 /* Has a filter dialog box already been opened for that button? */
120 filter_browse_w = OBJECT_GET_DATA(w, E_FILT_DIALOG_PTR_KEY);
122 if (filter_browse_w != NULL) {
123 /* Yes. Just re-activate that dialog box. */
124 reactivate_window(filter_browse_w);
128 /* No. Get the text entry attached to the button. */
129 parent_filter_te = OBJECT_GET_DATA(w, E_FILT_TE_PTR_KEY);
131 /* Now create a new dialog, without an "Add Expression..." button. */
132 filter_browse_w = filter_dialog_new(w, parent_filter_te,
133 CFILTER_LIST, &args);
137 /* Create a filter dialog for constructing a display filter.
139 This is to be used as a callback for a button next to a text entry box,
140 which, when clicked, pops up this dialog to allow you to construct a
141 display filter by browsing the list of saved filters and/or by adding
142 test expressions constructed with another dialog. The "OK" button
143 sets the text entry box to the constructed filter and activates that
144 text entry box, causing the filter to be used; this dialog is then
147 If "wants_apply_button" is non-null, we add an "Apply" button that
148 acts like "OK" but doesn't dismiss this dialog. */
150 display_filter_construct_cb(GtkWidget *w, gpointer construct_args_ptr)
152 construct_args_t *construct_args = construct_args_ptr;
153 GtkWidget *filter_browse_w;
154 GtkWidget *parent_filter_te;
156 /* Has a filter dialog box already been opened for the button? */
157 filter_browse_w = OBJECT_GET_DATA(w, E_FILT_DIALOG_PTR_KEY);
159 if (filter_browse_w != NULL) {
160 /* Yes. Just re-activate that dialog box. */
161 reactivate_window(filter_browse_w);
165 /* No. Get the text entry attached to the button. */
166 parent_filter_te = OBJECT_GET_DATA(w, E_FILT_TE_PTR_KEY);
168 /* Now create a new dialog, possibly with an "Apply" button, and
169 definitely with an "Add Expression..." button. */
170 filter_browse_w = filter_dialog_new(w, parent_filter_te,
171 DFILTER_LIST, construct_args);
174 /* Should be called when a button that creates filters is destroyed; it
175 destroys any filter dialog created by that button. */
177 filter_button_destroy_cb(GtkWidget *button, gpointer user_data _U_)
181 /* Is there a filter edit/selection dialog associated with this
183 filter_w = OBJECT_GET_DATA(button, E_FILT_DIALOG_PTR_KEY);
185 if (filter_w != NULL) {
186 /* Yes. Break the association, and destroy the dialog. */
187 OBJECT_SET_DATA(button, E_FILT_DIALOG_PTR_KEY, NULL);
188 window_destroy(filter_w);
193 static GtkWidget *global_cfilter_w;
195 /* Create a filter dialog for editing capture filters; this is to be used
196 as a callback for menu items, toolbars, etc.. */
198 cfilter_dialog_cb(GtkWidget *w _U_)
200 /* No Apply button, and there's no text widget to set, much less
201 activate, on "OK". */
202 static construct_args_t args = {
203 "Wireshark: Capture Filter",
209 /* Has a filter dialog box already been opened for editing
211 if (global_cfilter_w != NULL) {
212 /* Yes. Just reactivate it. */
213 reactivate_window(global_cfilter_w);
218 * No. Create one; we didn't pop this up as a result of pressing
219 * a button next to some text entry field, so don't associate it
220 * with a text entry field or button.
222 global_cfilter_w = filter_dialog_new(NULL, NULL, CFILTER_LIST, &args);
226 /* Create a filter dialog for editing display filters; this is to be used
227 as a callback for menu items, toolbars, etc.. */
229 dfilter_dialog_cb(GtkWidget *w _U_)
231 static construct_args_t args = {
232 "Wireshark: Display Filter",
238 display_filter_construct_cb(OBJECT_GET_DATA(top_level, E_FILT_BT_PTR_KEY), &args);
241 /* List of capture filter dialogs, so that if the list of filters changes
242 (the model, if you will), we can update all of their lists displaying
243 the filters (the views). */
244 static GList *cfilter_dialogs;
246 /* List of display filter dialogs, so that if the list of filters changes
247 (the model, if you will), we can update all of their lists displaying
248 the filters (the views). */
249 static GList *dfilter_dialogs;
252 remember_filter_dialog(GtkWidget *main_w, GList **filter_dialogs)
254 *filter_dialogs = g_list_append(*filter_dialogs, main_w);
257 /* Remove a filter dialog from the specified list of filter_dialogs. */
259 forget_filter_dialog(GtkWidget *main_w, filter_list_type_t list_type)
263 case CFILTER_EDITED_LIST:
264 cfilter_dialogs = g_list_remove(cfilter_dialogs, main_w);
267 case DFILTER_EDITED_LIST:
268 dfilter_dialogs = g_list_remove(dfilter_dialogs, main_w);
272 g_assert_not_reached();
277 /* Get the dialog list corresponding to a particular filter list. */
279 get_filter_dialog_list(filter_list_type_t list_type)
283 case CFILTER_EDITED_LIST:
284 return cfilter_dialogs;
286 case DFILTER_EDITED_LIST:
287 return dfilter_dialogs;
290 g_assert_not_reached();
296 #if GTK_MAJOR_VERSION < 2
301 fill_list(GtkWidget *main_w, filter_list_type_t list_type, const gchar *filter_te_str)
305 #if GTK_MAJOR_VERSION < 2
309 GtkWidget *filter_l = OBJECT_GET_DATA(main_w, E_FILT_FILTER_L_KEY);
311 GtkTreeView *filter_l;
314 GtkTreeIter *l_select = NULL;
316 filter_l = GTK_TREE_VIEW(OBJECT_GET_DATA(main_w, E_FILT_FILTER_L_KEY));
317 store = GTK_LIST_STORE(gtk_tree_view_get_model(filter_l));
321 fl_entry = get_filter_list_first(list_type);
322 while (fl_entry != NULL) {
323 filt = (filter_def *) fl_entry->data;
324 #if GTK_MAJOR_VERSION < 2
325 nl_lb = gtk_label_new(filt->name);
326 nl_item = gtk_list_item_new();
328 SIGNAL_CONNECT(nl_item, "button_press_event", filter_sel_list_button_cb,
331 gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5);
332 gtk_container_add(GTK_CONTAINER(nl_item), nl_lb);
333 gtk_widget_show(nl_lb);
334 gtk_container_add(GTK_CONTAINER(filter_l), nl_item);
335 gtk_widget_show(nl_item);
336 OBJECT_SET_DATA(nl_item, E_FILT_LBL_KEY, nl_lb);
337 OBJECT_SET_DATA(nl_item, E_FILT_LIST_ITEM_MODEL_KEY, fl_entry);
339 gtk_list_store_append(store, &iter);
340 gtk_list_store_set(store, &iter, 0, filt->name,
344 if (filter_te_str && filt->strval) {
345 if (strcmp(filter_te_str, filt->strval) == 0) {
346 #if GTK_MAJOR_VERSION < 2
350 * XXX - We're assuming that we can just copy a GtkTreeIter
351 * and use it later without any crashes. This may not be a
354 l_select = g_memdup(&iter, sizeof(iter));
359 fl_entry = fl_entry->next;
366 clear_list(GtkWidget *main_w) {
367 GtkWidget *filter_l = OBJECT_GET_DATA(main_w, E_FILT_FILTER_L_KEY);
368 #if GTK_MAJOR_VERSION >= 2
369 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(filter_l));
372 #if GTK_MAJOR_VERSION < 2
373 gtk_list_clear_items(GTK_LIST(filter_l), 0, -1);
375 gtk_list_store_clear(GTK_LIST_STORE(model));
381 filter_dialog_new(GtkWidget *button, GtkWidget *parent_filter_te,
382 filter_list_type_t list_type, construct_args_t *construct_args)
384 GtkWidget *main_w, /* main window */
385 *main_vb, /* main container */
386 *bbox, /* button container */
387 *ok_bt, /* "OK" button */
388 *apply_bt, /* "Apply" button */
389 *save_bt, /* "Save" button */
390 *cancel_bt, /* "Cancel" button */
391 *help_bt; /* "Help" button */
392 GtkWidget *filter_vb, /* filter settings box */
411 GtkTooltips *tooltips;
412 static filter_list_type_t cfilter_list_type = CFILTER_EDITED_LIST;
413 static filter_list_type_t dfilter_list_type = DFILTER_EDITED_LIST;
414 filter_list_type_t *filter_list_type_p;
415 GList **filter_dialogs;
416 const gchar *filter_te_str = NULL;
417 #if GTK_MAJOR_VERSION < 2
418 GtkWidget *l_select = NULL;
421 GtkCellRenderer *renderer;
422 GtkTreeViewColumn *column;
423 GtkTreeSelection *sel;
424 GtkTreeIter *l_select;
427 /* Get a pointer to a static variable holding the type of filter on
428 which we're working, so we can pass that pointer to callback
433 filter_dialogs = &cfilter_dialogs;
434 filter_list_type_p = &cfilter_list_type;
435 list_type = CFILTER_EDITED_LIST;
439 filter_dialogs = &dfilter_dialogs;
440 filter_list_type_p = &dfilter_list_type;
441 list_type = DFILTER_EDITED_LIST;
445 g_assert_not_reached();
446 filter_dialogs = NULL;
447 filter_list_type_p = NULL;
451 tooltips = gtk_tooltips_new ();
453 main_w = dlg_window_new(construct_args->title);
454 gtk_window_set_default_size(GTK_WINDOW(main_w), 400, 400);
455 OBJECT_SET_DATA(main_w, E_FILT_CONSTRUCT_ARGS_KEY, construct_args);
457 main_vb = gtk_vbox_new(FALSE, 0);
458 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
459 gtk_container_add(GTK_CONTAINER(main_w), main_vb);
460 gtk_widget_show(main_vb);
462 /* Make sure everything is set up */
463 if (parent_filter_te)
464 filter_te_str = gtk_entry_get_text(GTK_ENTRY(parent_filter_te));
466 /* Container for each row of widgets */
467 filter_vb = gtk_vbox_new(FALSE, 0);
468 gtk_container_border_width(GTK_CONTAINER(filter_vb), 0);
469 gtk_container_add(GTK_CONTAINER(main_vb), filter_vb);
470 gtk_widget_show(filter_vb);
472 /* Top row: Buttons and filter list */
473 top_hb = gtk_hbox_new(FALSE, 0);
474 gtk_container_add(GTK_CONTAINER(filter_vb), top_hb);
475 gtk_widget_show(top_hb);
477 edit_fr = gtk_frame_new("Edit");
478 gtk_box_pack_start(GTK_BOX(top_hb), edit_fr, FALSE, FALSE, 0);
479 gtk_widget_show(edit_fr);
481 list_bb = gtk_vbox_new(TRUE, 0);
482 gtk_container_border_width(GTK_CONTAINER(list_bb), 5);
483 gtk_container_add(GTK_CONTAINER(edit_fr), list_bb);
484 gtk_widget_show(list_bb);
486 new_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_NEW);
487 SIGNAL_CONNECT(new_bt, "clicked", filter_new_bt_clicked_cb, filter_list_type_p);
488 #if GTK_MAJOR_VERSION < 2
489 WIDGET_SET_SIZE(new_bt, 50, 20);
491 gtk_widget_show(new_bt);
492 gtk_box_pack_start (GTK_BOX (list_bb), new_bt, FALSE, FALSE, 0);
493 gtk_tooltips_set_tip (tooltips, new_bt,
494 "Create a new filter at the end of the list (with the current properties)", NULL);
496 del_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_DELETE);
497 gtk_widget_set_sensitive(del_bt, FALSE);
498 SIGNAL_CONNECT(del_bt, "clicked", filter_del_bt_clicked_cb, filter_list_type_p);
499 OBJECT_SET_DATA(main_w, E_FILT_DEL_BT_KEY, del_bt);
500 #if GTK_MAJOR_VERSION < 2
501 WIDGET_SET_SIZE(del_bt, 50, 20);
503 gtk_widget_show(del_bt);
504 gtk_box_pack_start (GTK_BOX (list_bb), del_bt, FALSE, FALSE, 0);
505 gtk_tooltips_set_tip (tooltips, del_bt, ("Delete the selected filter"), NULL);
507 filter_fr = gtk_frame_new("Filter");
508 gtk_box_pack_start(GTK_BOX(top_hb), filter_fr, TRUE, TRUE, 0);
509 gtk_widget_show(filter_fr);
511 filter_sc = scrolled_window_new(NULL, NULL);
512 #if GTK_MAJOR_VERSION >= 2
513 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(filter_sc),
517 gtk_container_set_border_width (GTK_CONTAINER (filter_sc), 5);
518 gtk_container_add(GTK_CONTAINER(filter_fr), filter_sc);
519 gtk_widget_show(filter_sc);
521 #if GTK_MAJOR_VERSION < 2
522 filter_l = gtk_list_new();
523 gtk_list_set_selection_mode(GTK_LIST(filter_l), GTK_SELECTION_SINGLE);
524 SIGNAL_CONNECT(filter_l, "selection_changed", filter_sel_list_cb,
527 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
528 filter_l = tree_view_new(GTK_TREE_MODEL(store));
529 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(filter_l), FALSE);
530 renderer = gtk_cell_renderer_text_new();
531 column = gtk_tree_view_column_new_with_attributes("", renderer, "text",
533 gtk_tree_view_column_set_sort_column_id(column, 0);
534 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_l), column);
535 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_l));
536 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
537 SIGNAL_CONNECT(sel, "changed", filter_sel_list_cb, filter_vb);
538 SIGNAL_CONNECT(filter_l, "button_press_event", filter_sel_list_button_cb,
541 OBJECT_SET_DATA(main_w, E_FILT_FILTER_L_KEY, filter_l);
542 #if GTK_MAJOR_VERSION < 2
543 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(filter_sc),
546 gtk_container_add(GTK_CONTAINER(filter_sc), filter_l);
548 gtk_widget_show(filter_l);
550 OBJECT_SET_DATA(filter_l, E_FILT_DBLFUNC_KEY, filter_dlg_dclick);
551 OBJECT_SET_DATA(filter_l, E_FILT_DBLARG_KEY, main_w);
552 /* This is a Boolean, but we make it a non-null pointer for TRUE
553 and a null pointer for FALSE, as object data is a pointer. */
554 OBJECT_SET_DATA(filter_l, E_FILT_DBLACTIVATE_KEY,
555 construct_args->activate_on_ok ? "" : NULL);
558 l_select = fill_list(main_w, list_type, filter_te_str);
560 #if GTK_MAJOR_VERSION >= 2
561 g_object_unref(G_OBJECT(store));
565 props_fr = gtk_frame_new("Properties");
566 gtk_box_pack_start(GTK_BOX(filter_vb), props_fr, FALSE, FALSE, 0);
567 gtk_widget_show(props_fr);
569 props_vb = gtk_vbox_new(FALSE, 3);
570 gtk_container_border_width(GTK_CONTAINER(props_vb), 5);
571 gtk_container_add(GTK_CONTAINER(props_fr), props_vb);
572 gtk_widget_show(props_vb);
574 /* row: Filter name entry */
575 middle_hb = gtk_hbox_new(FALSE, 3);
576 gtk_container_add(GTK_CONTAINER(props_vb), middle_hb);
577 gtk_widget_show(middle_hb);
579 name_lb = gtk_label_new("Filter name:");
580 gtk_box_pack_start(GTK_BOX(middle_hb), name_lb, FALSE, FALSE, 0);
581 gtk_widget_show(name_lb);
583 name_te = gtk_entry_new();
584 gtk_box_pack_start(GTK_BOX(middle_hb), name_te, TRUE, TRUE, 0);
585 OBJECT_SET_DATA(main_w, E_FILT_NAME_TE_KEY, name_te);
586 SIGNAL_CONNECT(name_te, "changed", filter_name_te_changed_cb, filter_list_type_p);
587 gtk_widget_show(name_te);
589 /* row: Filter text entry */
590 bottom_hb = gtk_hbox_new(FALSE, 3);
591 gtk_container_add(GTK_CONTAINER(props_vb), bottom_hb);
592 gtk_widget_show(bottom_hb);
594 filter_lb = gtk_label_new("Filter string:");
595 gtk_box_pack_start(GTK_BOX(bottom_hb), filter_lb, FALSE, FALSE, 0);
596 gtk_widget_show(filter_lb);
598 filter_te = gtk_entry_new();
599 gtk_box_pack_start(GTK_BOX(bottom_hb), filter_te, TRUE, TRUE, 0);
600 OBJECT_SET_DATA(main_w, E_FILT_FILTER_TE_KEY, filter_te);
601 SIGNAL_CONNECT(filter_te, "changed", filter_name_te_changed_cb, filter_list_type_p);
602 gtk_widget_show(filter_te);
604 OBJECT_SET_DATA(main_w, E_FILT_PARENT_FILTER_TE_KEY, parent_filter_te);
606 if (list_type == DFILTER_EDITED_LIST) {
607 gtk_tooltips_set_tip(tooltips, filter_te,
608 "Enter a display filter. "
609 "The background color of this field is changed by a continuous syntax check (green is valid, red is invalid).",
612 /* Create the "Add Expression..." button, to pop up a dialog
613 for constructing filter comparison expressions. */
614 add_expression_bt = BUTTON_NEW_FROM_STOCK(WIRESHARK_STOCK_ADD_EXPRESSION);
615 SIGNAL_CONNECT(add_expression_bt, "clicked", filter_add_expr_bt_cb, main_w);
616 gtk_box_pack_start(GTK_BOX(bottom_hb), add_expression_bt, FALSE, FALSE, 0);
617 gtk_widget_show(add_expression_bt);
618 gtk_tooltips_set_tip (tooltips, add_expression_bt, ("Add an expression to the filter string"), NULL);
622 /* button row (create all possible buttons and hide the unrequired later - it's a lot easier) */
623 bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_SAVE, GTK_STOCK_CANCEL, GTK_STOCK_HELP, NULL);
624 gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 5);
625 gtk_widget_show(bbox);
627 ok_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_OK);
628 SIGNAL_CONNECT(ok_bt, "clicked", filter_dlg_ok_cb, filter_list_type_p);
629 gtk_tooltips_set_tip (tooltips, ok_bt, ("Apply the filters and close this dialog"), NULL);
631 /* Catch the "activate" signal on the filter name and filter
632 expression text entries, so that if the user types Return
633 there, we act as if the "OK" button had been selected, as
634 happens if Return is typed if some widget that *doesn't*
635 handle the Return key has the input focus. */
636 if (parent_filter_te != NULL) {
637 dlg_set_activate(name_te, ok_bt);
638 dlg_set_activate(filter_te, ok_bt);
641 apply_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_APPLY);
642 SIGNAL_CONNECT(apply_bt, "clicked", filter_dlg_apply_cb, filter_list_type_p);
643 gtk_tooltips_set_tip (tooltips, apply_bt, ("Apply the filters and keep this dialog open"), NULL);
645 save_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_SAVE);
646 SIGNAL_CONNECT(save_bt, "clicked", filter_dlg_save_cb, filter_list_type_p);
647 gtk_tooltips_set_tip (tooltips, save_bt, ("Save the filters permanently and keep this dialog open"), NULL);
649 cancel_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CANCEL);
650 gtk_tooltips_set_tip (tooltips, cancel_bt, ("Cancel the changes"), NULL);
651 SIGNAL_CONNECT(cancel_bt, "clicked", filter_dlg_cancel_cb, filter_list_type_p);
652 window_set_cancel_button(main_w, cancel_bt, NULL);
654 help_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_HELP);
655 if (list_type == CFILTER_EDITED_LIST) {
656 SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_CAPTURE_FILTERS_DIALOG);
658 SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_DISPLAY_FILTERS_DIALOG);
660 gtk_tooltips_set_tip (tooltips, help_bt, ("Show topic specific help"), NULL);
663 gtk_widget_grab_default(ok_bt);
666 remember_filter_dialog(main_w, filter_dialogs);
668 if (button != NULL) {
669 /* This dialog box was created by a "Filter" button.
670 Set the E_FILT_BUTTON_PTR_KEY for the new dialog to point to
672 OBJECT_SET_DATA(main_w, E_FILT_BUTTON_PTR_KEY, button);
674 /* Set the E_FILT_DIALOG_PTR_KEY for the button to point to us */
675 OBJECT_SET_DATA(button, E_FILT_DIALOG_PTR_KEY, main_w);
678 /* DO SELECTION THINGS *AFTER* SHOWING THE DIALOG! */
679 /* otherwise the updatings can get confused */
681 #if GTK_MAJOR_VERSION < 2
682 gtk_list_select_child(GTK_LIST(filter_l), l_select);
684 gtk_tree_selection_select_iter(sel, l_select);
687 } else if (filter_te_str && filter_te_str[0]) {
688 gtk_entry_set_text(GTK_ENTRY(name_te), "New filter");
689 gtk_entry_set_text(GTK_ENTRY(filter_te), filter_te_str);
692 SIGNAL_CONNECT(main_w, "delete_event", filter_dlg_delete_event_cb, filter_list_type_p);
693 SIGNAL_CONNECT(main_w, "destroy", filter_dlg_destroy_cb, filter_list_type_p);
695 gtk_widget_show(main_w);
697 if(construct_args->modal_and_transient) {
698 parent = gtk_widget_get_parent_window(parent_filter_te);
699 gdk_window_set_transient_for(main_w->window, parent);
700 gtk_window_set_modal(GTK_WINDOW(main_w), TRUE);
703 /* hide the Ok button, if we don't have to apply it and our caller wants a Save button */
704 if (parent_filter_te == NULL && prefs.gui_use_pref_save) {
705 gtk_widget_hide(ok_bt);
708 /* hide the Apply button, if our caller don't wants one */
709 if (!construct_args->wants_apply_button) {
710 gtk_widget_hide(apply_bt);
713 /* hide the Save button if the user uses implicit save */
714 if (!prefs.gui_use_pref_save) {
715 gtk_widget_hide(save_bt);
718 window_present(main_w);
724 filter_dlg_dclick(GtkWidget *filter_l, gpointer main_w_arg, gpointer activate)
726 GtkWidget *main_w = GTK_WIDGET(main_w_arg);
727 GtkWidget *parent_filter_te =
728 OBJECT_GET_DATA(main_w, E_FILT_PARENT_FILTER_TE_KEY);
731 #if GTK_MAJOR_VERSION < 2
735 GtkTreeSelection *sel;
739 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_l));
742 if (parent_filter_te != NULL) {
744 * We have a text entry widget associated with this dialog
745 * box; is one of the filters in the list selected?
747 #if GTK_MAJOR_VERSION < 2
748 sl = GTK_LIST(filter_l)->selection;
751 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
754 * Yes. Is there a filter definition for that filter?
756 #if GTK_MAJOR_VERSION < 2
757 l_item = GTK_OBJECT(sl->data);
758 flp = (GList *)OBJECT_GET_DATA(l_item,
759 E_FILT_LIST_ITEM_MODEL_KEY);
761 gtk_tree_model_get(model, &iter, 1, &flp, -1);
765 * Yes - put it in the text entry widget.
767 filt = (filter_def *) flp->data;
768 gtk_entry_set_text(GTK_ENTRY(parent_filter_te),
772 * Are we supposed to cause the filter we
773 * put there to be applied?
775 if (activate != NULL) {
779 SIGNAL_EMIT_BY_NAME(SIGNAL_EMIT_OBJECT(parent_filter_te), "activate", NULL);
785 window_destroy(main_w);
789 filter_dlg_ok_cb(GtkWidget *ok_bt, gpointer data)
791 filter_list_type_t list_type = *(filter_list_type_t *)data;
794 * Destroy the dialog box and apply the filter.
796 filter_apply(gtk_widget_get_toplevel(ok_bt), TRUE);
798 /* if we don't have a Save button, just save the settings now */
799 if (!prefs.gui_use_pref_save) {
800 filter_dlg_save(list_type);
805 filter_dlg_apply_cb(GtkWidget *apply_bt, gpointer data)
807 filter_list_type_t list_type = *(filter_list_type_t *)data;
810 * Apply the filter, but don't destroy the dialog box.
812 filter_apply(gtk_widget_get_toplevel(apply_bt), FALSE);
814 /* if we don't have a Save button, just save the settings now */
815 if (!prefs.gui_use_pref_save) {
816 filter_dlg_save(list_type);
821 filter_apply(GtkWidget *main_w, gboolean destroy)
823 construct_args_t *construct_args =
824 OBJECT_GET_DATA(main_w, E_FILT_CONSTRUCT_ARGS_KEY);
825 GtkWidget *parent_filter_te =
826 OBJECT_GET_DATA(main_w, E_FILT_PARENT_FILTER_TE_KEY);
827 GtkWidget *filter_te;
828 const gchar *filter_string;
830 if (parent_filter_te != NULL) {
832 * We have a text entry widget associated with this dialog
833 * box; put the filter in our text entry widget into that
836 filter_te = OBJECT_GET_DATA(main_w, E_FILT_FILTER_TE_KEY);
838 (const gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
839 gtk_entry_set_text(GTK_ENTRY(parent_filter_te), filter_string);
845 * Destroy the filter dialog box.
847 window_destroy(main_w);
850 if (parent_filter_te != NULL) {
852 * We have a text entry widget associated with this dialog
853 * box; activate that widget to cause the filter we put
854 * there to be applied if we're supposed to do so.
856 * We do this after dismissing the filter dialog box,
857 * as activating the widget the dialog box to which
858 * it belongs to be dismissed, and that may cause it
859 * to destroy our dialog box if the filter succeeds.
860 * This means that our subsequent attempt to destroy
863 * We don't know whether it'll destroy our dialog box,
864 * so we can't rely on it to do so. Instead, we
865 * destroy it ourselves, which will clear the
866 * E_FILT_DIALOG_PTR_KEY pointer for their dialog box,
867 * meaning they won't think it has one and won't try
870 if (construct_args->activate_on_ok) {
871 SIGNAL_EMIT_BY_NAME(SIGNAL_EMIT_OBJECT(parent_filter_te), "activate", NULL);
878 filter_dlg_save(filter_list_type_t list_type)
883 const char *filter_type;
887 case CFILTER_EDITED_LIST:
888 filter_type = "capture";
889 list_type = CFILTER_LIST;
890 copy_filter_list(CFILTER_LIST, CFILTER_EDITED_LIST);
893 case DFILTER_EDITED_LIST:
894 filter_type = "display";
895 list_type = DFILTER_LIST;
896 copy_filter_list(DFILTER_LIST, DFILTER_EDITED_LIST);
900 g_assert_not_reached();
905 /* Create the directory that holds personal configuration files,
907 if (create_persconffile_dir(&pf_dir_path) == -1) {
908 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
909 "Can't create directory\n\"%s\"\nfor filter files: %s.",
910 pf_dir_path, strerror(errno));
915 save_filter_list(list_type, &f_path, &f_save_errno);
916 if (f_path != NULL) {
917 /* We had an error saving the filter. */
918 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
919 "Could not save to your %s filter file\n\"%s\": %s.",
920 filter_type, f_path, strerror(f_save_errno));
927 filter_dlg_save_cb(GtkWidget *save_bt _U_, gpointer data)
929 filter_list_type_t list_type = *(filter_list_type_t *)data;
931 filter_dlg_save(list_type);
935 /* update a remaining dialog if another one was cancelled */
936 static void filter_dlg_update_list_cb(gpointer data, gpointer user_data)
938 GtkWidget *main_w = data;
939 filter_list_type_t list_type = *(filter_list_type_t *)user_data;
941 /* refill the list */
943 fill_list(main_w, list_type, NULL);
947 /* cancel button pressed, revert changes and exit dialog */
949 filter_dlg_cancel_cb(GtkWidget *cancel_bt, gpointer data)
951 filter_list_type_t list_type = *(filter_list_type_t *)data;
952 GtkWidget *main_w = gtk_widget_get_toplevel(cancel_bt);
953 static GList *filter_list;
956 window_destroy(GTK_WIDGET(main_w));
958 /* if this was the last open filter dialog, revert the changes made */
959 filter_list = get_filter_dialog_list(list_type);
960 if(g_list_length(filter_list) == 0) {
961 /* revert changes in the edited list */
963 case CFILTER_EDITED_LIST:
964 copy_filter_list(CFILTER_EDITED_LIST, CFILTER_LIST);
966 case DFILTER_EDITED_LIST:
967 copy_filter_list(DFILTER_EDITED_LIST, DFILTER_LIST);
970 g_assert_not_reached();
976 /* update other open filter dialogs */
977 g_list_foreach(get_filter_dialog_list(list_type), filter_dlg_update_list_cb, &list_type);
981 /* Treat this as a cancel, by calling "filter_dlg_cancel_cb()" */
983 filter_dlg_delete_event_cb(GtkWidget *main_w, GdkEvent *event _U_,
986 filter_dlg_cancel_cb(main_w, data);
992 filter_dlg_destroy_cb(GtkWidget *win, gpointer data)
994 filter_list_type_t list_type = *(filter_list_type_t *)data;
997 /* Get the button that requested that we be popped up, if any.
998 (It should arrange to destroy us if it's destroyed, so
999 that we don't get a pointer to a non-existent window here.) */
1000 button = OBJECT_GET_DATA(win, E_FILT_BUTTON_PTR_KEY);
1002 if (button != NULL) {
1003 /* Tell it we no longer exist. */
1004 OBJECT_SET_DATA(button, E_FILT_DIALOG_PTR_KEY, NULL);
1006 /* This is an editing dialog popped up from, for example,
1007 a menu item; note that we no longer have one. */
1008 switch (list_type) {
1011 case CFILTER_EDITED_LIST:
1012 g_assert(win == global_cfilter_w);
1013 global_cfilter_w = NULL;
1017 g_assert_not_reached();
1022 /* Remove this from the list of filter dialog windows. */
1023 forget_filter_dialog(win, list_type);
1026 #if GTK_MAJOR_VERSION < 2
1028 filter_sel_list_button_cb(GtkWidget *widget, GdkEventButton *event,
1032 filter_sel_list_button_cb(GtkWidget *list, GdkEventButton *event,
1036 #if GTK_MAJOR_VERSION < 2
1037 GtkWidget *list = func_data;
1039 void (* func)(GtkWidget *, gpointer, gpointer);
1041 gpointer func_activate;
1043 #if GTK_MAJOR_VERSION < 2
1044 if (!GTK_IS_LIST_ITEM(widget)) return FALSE;
1046 if (event->type == GDK_2BUTTON_PRESS) {
1047 func = OBJECT_GET_DATA(list, E_FILT_DBLFUNC_KEY);
1048 func_arg = OBJECT_GET_DATA(list, E_FILT_DBLARG_KEY);
1049 func_activate = OBJECT_GET_DATA(list, E_FILT_DBLACTIVATE_KEY);
1052 (*func)(list, func_arg, func_activate);
1058 #if GTK_MAJOR_VERSION < 2
1060 filter_sel_list_cb(GtkWidget *l, gpointer data _U_)
1063 filter_sel_list_cb(GtkTreeSelection *sel, gpointer data _U_)
1066 #if GTK_MAJOR_VERSION < 2
1067 GtkWidget *main_w = gtk_widget_get_toplevel(l);
1071 GtkWidget *filter_l = GTK_WIDGET(gtk_tree_selection_get_tree_view(sel));
1072 GtkWidget *main_w = gtk_widget_get_toplevel(filter_l);
1073 GtkTreeModel *model;
1076 GtkWidget *name_te = OBJECT_GET_DATA(main_w, E_FILT_NAME_TE_KEY);
1077 GtkWidget *filter_te = OBJECT_GET_DATA(main_w, E_FILT_FILTER_TE_KEY);
1078 GtkWidget *chg_bt = OBJECT_GET_DATA(main_w, E_FILT_CHG_BT_KEY);
1079 GtkWidget *copy_bt = OBJECT_GET_DATA(main_w, E_FILT_COPY_BT_KEY);
1080 GtkWidget *del_bt = OBJECT_GET_DATA(main_w, E_FILT_DEL_BT_KEY);
1082 gchar *name = NULL, *strval = NULL;
1084 gint sensitivity = FALSE;
1086 #if GTK_MAJOR_VERSION < 2
1088 sl = GTK_LIST(l)->selection;
1092 if (sl) { /* Something was selected */
1093 l_item = GTK_OBJECT(sl->data);
1094 flp = (GList *) OBJECT_GET_DATA(l_item, E_FILT_LIST_ITEM_MODEL_KEY);
1096 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
1097 gtk_tree_model_get(model, &iter, 1, &flp, -1);
1100 filt = (filter_def *) flp->data;
1101 name = g_strdup(filt->name);
1102 strval = g_strdup(filt->strval);
1108 * Did you know that this function is called when the window is destroyed?
1110 * This means that we have to:
1112 * attach to the top-level window data items containing pointers to
1113 * the widgets we affect here;
1115 * give each of those widgets their own destroy callbacks;
1117 * clear that pointer when the widget is destroyed;
1119 * don't do anything to the widget if the pointer we get back is
1122 * so that if we're called after any of the widgets we'd affect are
1123 * destroyed, we know that we shouldn't do anything to those widgets.
1125 if (name_te != NULL)
1126 gtk_entry_set_text(GTK_ENTRY(name_te), name ? name : "");
1127 if (filter_te != NULL)
1128 gtk_entry_set_text(GTK_ENTRY(filter_te), strval ? strval : "");
1130 gtk_widget_set_sensitive(chg_bt, sensitivity);
1131 if (copy_bt != NULL)
1132 gtk_widget_set_sensitive(copy_bt, sensitivity);
1134 gtk_widget_set_sensitive(del_bt, sensitivity);
1141 /* To do: add input checking to each of these callbacks */
1143 /* Structure containing arguments to be passed to "new_filter_cb()".
1145 "active_filter_l" is the list in the dialog box in which "New" or
1146 "Copy" was clicked; in that dialog box, but not in any other dialog
1147 box, we select the newly created list item.
1149 "nflp" is the GList member in the model (filter list) for the new
1152 GtkWidget *active_filter_l;
1154 } new_filter_cb_args_t;
1157 new_filter_cb(gpointer data, gpointer user_data)
1159 GtkWidget *main_w = data;
1160 #if GTK_MAJOR_VERSION < 2
1161 GtkWidget *filter_l = OBJECT_GET_DATA(main_w, E_FILT_FILTER_L_KEY);
1162 GtkWidget *nl_lb, *nl_item;
1164 GtkTreeView *filter_l;
1165 GtkListStore *store;
1168 new_filter_cb_args_t *args = user_data;
1169 filter_def *nfilt = args->nflp->data;
1171 #if GTK_MAJOR_VERSION < 2
1172 nl_lb = gtk_label_new(nfilt->name);
1173 nl_item = gtk_list_item_new();
1174 gtk_misc_set_alignment(GTK_MISC(nl_lb), 0.0, 0.5);
1175 gtk_container_add(GTK_CONTAINER(nl_item), nl_lb);
1176 gtk_widget_show(nl_lb);
1177 gtk_container_add(GTK_CONTAINER(filter_l), nl_item);
1178 gtk_widget_show(nl_item);
1179 OBJECT_SET_DATA(nl_item, E_FILT_LBL_KEY, nl_lb);
1180 OBJECT_SET_DATA(GTK_OBJECT(nl_item), E_FILT_LIST_ITEM_MODEL_KEY,
1182 if (filter_l == args->active_filter_l) {
1183 /* Select the item. */
1184 gtk_list_select_child(GTK_LIST(filter_l), nl_item);
1187 filter_l = GTK_TREE_VIEW(OBJECT_GET_DATA(main_w, E_FILT_FILTER_L_KEY));
1188 store = GTK_LIST_STORE(gtk_tree_view_get_model(filter_l));
1189 gtk_list_store_append(store, &iter);
1190 gtk_list_store_set(store, &iter, 0, nfilt->name, 1, args->nflp, -1);
1191 if (GTK_WIDGET(filter_l) == args->active_filter_l) {
1192 /* Select the item. */
1193 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(filter_l),
1200 filter_new_bt_clicked_cb(GtkWidget *w, gpointer data)
1202 GtkWidget *main_w = gtk_widget_get_toplevel(w);
1203 GtkWidget *name_te = OBJECT_GET_DATA(main_w, E_FILT_NAME_TE_KEY);
1204 GtkWidget *filter_te = OBJECT_GET_DATA(main_w, E_FILT_FILTER_TE_KEY);
1205 GtkWidget *filter_l = OBJECT_GET_DATA(main_w, E_FILT_FILTER_L_KEY);
1206 filter_list_type_t list_type = *(filter_list_type_t *)data;
1208 const gchar *name, *strval;
1209 new_filter_cb_args_t args;
1211 name = gtk_entry_get_text(GTK_ENTRY(name_te));
1212 strval = gtk_entry_get_text(GTK_ENTRY(filter_te));
1214 /* if the user didn't entered a name, set default one */
1215 if (strlen(name) == 0) {
1219 /* if the user didn't entered a string value, set default one */
1220 if (strlen(strval) == 0) {
1224 /* Add a new entry to the filter list. */
1225 fl_entry = add_to_filter_list(list_type, name, strval);
1227 /* Update all the filter list widgets, not just the one in
1228 the dialog box in which we clicked on "Copy". */
1229 args.active_filter_l = filter_l;
1230 args.nflp = fl_entry;
1231 g_list_foreach(get_filter_dialog_list(list_type), new_filter_cb, &args);
1235 #if GTK_MAJOR_VERSION < 2
1237 chg_list_item_cb(GtkWidget *nl_item, gpointer data)
1240 chg_list_item_cb(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter,
1245 filter_def *filt = flp->data;
1246 #if GTK_MAJOR_VERSION < 2
1248 GTK_LABEL(OBJECT_GET_DATA(nl_item, E_FILT_LBL_KEY));
1250 OBJECT_GET_DATA(nl_item, E_FILT_LIST_ITEM_MODEL_KEY);
1255 #if GTK_MAJOR_VERSION >= 2
1256 gtk_tree_model_get(model, iter, 1, &nl_model, -1);
1258 /* Is this the item corresponding to the filter list item in question? */
1259 if (flp == nl_model) {
1260 /* Yes - change the label to correspond to the new name for the
1262 #if GTK_MAJOR_VERSION < 2
1263 gtk_label_set(nl_lb, filt->name);
1265 gtk_list_store_set(GTK_LIST_STORE(model), iter, 0, filt->name, -1);
1269 #if GTK_MAJOR_VERSION >= 2
1275 chg_filter_cb(gpointer data, gpointer user_data)
1277 GtkWidget *main_w = data;
1278 GtkWidget *filter_l = OBJECT_GET_DATA(main_w, E_FILT_FILTER_L_KEY);
1280 #if GTK_MAJOR_VERSION < 2
1281 gtk_container_foreach(GTK_CONTAINER(filter_l), chg_list_item_cb, user_data);
1283 gtk_tree_model_foreach(gtk_tree_view_get_model(GTK_TREE_VIEW(filter_l)),
1284 chg_list_item_cb, user_data);
1289 filter_name_te_changed_cb(GtkWidget *w, gpointer data)
1291 GtkWidget *main_w = gtk_widget_get_toplevel(w);
1292 GtkWidget *name_te = OBJECT_GET_DATA(main_w, E_FILT_NAME_TE_KEY);
1293 GtkWidget *filter_te = OBJECT_GET_DATA(main_w, E_FILT_FILTER_TE_KEY);
1294 GtkWidget *filter_l = OBJECT_GET_DATA(main_w, E_FILT_FILTER_L_KEY);
1297 filter_list_type_t list_type = *(filter_list_type_t *)data;
1298 const gchar *name = "";
1299 const gchar *strval = "";
1301 #if GTK_MAJOR_VERSION < 2
1306 GtkTreeSelection *sel;
1307 GtkTreeModel *model;
1311 #if GTK_MAJOR_VERSION < 2
1312 sl = GTK_LIST(filter_l)->selection;
1314 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_l));
1316 name = gtk_entry_get_text(GTK_ENTRY(name_te));
1317 strval = gtk_entry_get_text(GTK_ENTRY(filter_te));
1319 if (DFILTER_EDITED_LIST == list_type) {
1320 /* colorize filter string entry */
1321 filter_te_syntax_check_cb(filter_te);
1324 /* if something was selected */
1325 #if GTK_MAJOR_VERSION < 2
1327 l_item = GTK_OBJECT(sl->data);
1328 fl_entry = (GList *) OBJECT_GET_DATA(l_item,
1329 E_FILT_LIST_ITEM_MODEL_KEY);
1330 nl_lb = (GtkLabel *) OBJECT_GET_DATA(l_item, E_FILT_LBL_KEY);
1331 if (fl_entry != NULL && nl_lb != NULL) {
1333 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
1334 gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
1335 if (fl_entry != NULL) {
1337 filt = (filter_def *) fl_entry->data;
1339 if (strlen(name) > 0 && strlen(strval) > 0 && filt) {
1341 g_free(filt->strval);
1342 filt->name = g_strdup(name);
1343 filt->strval = g_strdup(strval);
1345 /* Update all the filter list widgets, not just the one in
1346 the dialog box in which we clicked on "Copy". */
1347 g_list_foreach(get_filter_dialog_list(list_type), chg_filter_cb,
1355 delete_filter_cb(gpointer data, gpointer user_data)
1357 GtkWidget *main_w = data;
1358 GtkWidget *filter_l = OBJECT_GET_DATA(main_w, E_FILT_FILTER_L_KEY);
1359 #if GTK_MAJOR_VERSION < 2
1360 gint pos = *(gint *)user_data;
1362 gchar *pos = (gchar *)user_data;
1363 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(filter_l));
1367 #if GTK_MAJOR_VERSION < 2
1368 gtk_list_clear_items(GTK_LIST(filter_l), pos, pos + 1);
1370 gtk_tree_model_get_iter_from_string(model, &iter, pos);
1371 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
1376 filter_del_bt_clicked_cb(GtkWidget *w, gpointer data)
1378 GtkWidget *main_w = gtk_widget_get_toplevel(w);
1379 GtkWidget *filter_l = OBJECT_GET_DATA(main_w, E_FILT_FILTER_L_KEY);
1380 filter_list_type_t list_type = *(filter_list_type_t *)data;
1382 #if GTK_MAJOR_VERSION < 2
1388 GtkTreeSelection *sel;
1389 GtkTreeModel *model;
1394 #if GTK_MAJOR_VERSION < 2
1395 sl = GTK_LIST(filter_l)->selection;
1396 if (sl) { /* Something was selected */
1397 l_item = GTK_OBJECT(sl->data);
1398 pos = gtk_list_child_position(GTK_LIST(filter_l),
1399 GTK_WIDGET(l_item));
1400 fl_entry = (GList *) OBJECT_GET_DATA(l_item, E_FILT_LIST_ITEM_MODEL_KEY);
1402 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_l));
1403 /* If something was selected */
1404 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
1405 gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
1406 path = gtk_tree_model_get_path(model, &iter);
1407 pos = gtk_tree_path_to_string(path);
1408 gtk_tree_path_free(path);
1410 if (fl_entry != NULL) {
1411 /* Remove the entry from the filter list. */
1412 remove_from_filter_list(list_type, fl_entry);
1414 /* Update all the filter list widgets, not just the one in
1415 the dialog box in which we clicked on "Delete". */
1416 #if GTK_MAJOR_VERSION < 2
1417 g_list_foreach(get_filter_dialog_list(list_type), delete_filter_cb,
1420 g_list_foreach(get_filter_dialog_list(list_type), delete_filter_cb, pos);
1423 #if GTK_MAJOR_VERSION >= 2
1430 filter_add_expr_bt_cb(GtkWidget *w _U_, gpointer main_w_arg)
1432 GtkWidget *main_w = GTK_WIDGET(main_w_arg);
1433 GtkWidget *filter_te, *dfilter_w;
1435 filter_te = OBJECT_GET_DATA(main_w, E_FILT_FILTER_TE_KEY);
1436 dfilter_w = dfilter_expr_dlg_new(filter_te);
1438 #if GTK_MAJOR_VERSION >= 2
1439 /* If we're opening a series of modal dialogs (such as when going
1440 * through file->open, make the latest dialog modal also so that it
1441 * takes over "control" from the other modal dialogs. Also set
1442 * the transient property of the new dialog so the user doesn't try
1443 * to interact with the previous window when they can't.
1444 * XXX: containing widget might be the Filter Toolbar */
1446 if ( GTK_IS_WINDOW(main_w) && gtk_window_get_modal(GTK_WINDOW(main_w))) {
1447 gtk_window_set_modal(GTK_WINDOW(dfilter_w), TRUE);
1448 gtk_window_set_transient_for(GTK_WINDOW(dfilter_w),
1449 GTK_WINDOW(main_w));
1455 color_filter_te(GtkWidget *w, guint16 red, guint16 green, guint16 blue)
1465 style = gtk_style_copy(gtk_widget_get_style(w));
1466 style->base[GTK_STATE_NORMAL] = bg;
1467 gtk_widget_set_style(w, style);
1468 gtk_style_unref(style);
1472 colorize_filter_te_as_empty(GtkWidget *w)
1475 color_filter_te(w, 0xFFFF, 0xFFFF, 0xFFFF);
1479 colorize_filter_te_as_invalid(GtkWidget *w)
1482 color_filter_te(w, 0xFFFF, 0xAFFF, 0xAFFF);
1486 colorize_filter_te_as_valid(GtkWidget *w)
1489 color_filter_te(w, 0xAFFF, 0xFFFF, 0xAFFF);
1493 filter_te_syntax_check_cb(GtkWidget *w)
1495 const gchar *strval;
1498 strval = gtk_entry_get_text(GTK_ENTRY(w));
1500 /* colorize filter string entry */
1501 if (strval && dfilter_compile(strval, &dfp)) {
1504 if (strlen(strval) == 0)
1505 colorize_filter_te_as_empty(w);
1507 colorize_filter_te_as_valid(w);
1509 colorize_filter_te_as_invalid(w);