2 * Dialog boxes for (display and capture) filter editing
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
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"
40 #include "simple_dialog.h"
41 #include "dfilter_expr_dlg.h"
42 #include "compat_macros.h"
43 #include "gtkglobals.h"
46 #define E_FILT_DIALOG_PTR_KEY "filter_dialog_ptr"
47 #define E_FILT_BUTTON_PTR_KEY "filter_button_ptr"
48 #define E_FILT_PARENT_FILTER_TE_KEY "filter_parent_filter_te"
49 #define E_FILT_CONSTRUCT_ARGS_KEY "filter_construct_args"
50 #define E_FILT_LIST_ITEM_MODEL_KEY "filter_list_item_model"
51 #define E_FILT_LBL_KEY "filter_label"
52 #define E_FILT_FILTER_L_KEY "filter_filter_l"
53 #define E_FILT_CHG_BT_KEY "filter_chg_bt"
54 #define E_FILT_COPY_BT_KEY "filter_copy_bt"
55 #define E_FILT_DEL_BT_KEY "filter_del_bt"
56 #define E_FILT_NAME_TE_KEY "filter_name_te"
57 #define E_FILT_DBLFUNC_KEY "filter_dblfunc"
58 #define E_FILT_DBLARG_KEY "filter_dblarg"
59 #define E_FILT_DBLACTIVATE_KEY "filter_dblactivate"
61 typedef struct _filter_cb_data {
66 static GtkWidget *filter_dialog_new(GtkWidget *button, GtkWidget *filter_te,
67 filter_list_type_t list,
68 construct_args_t *construct_args);
69 static void filter_dlg_dclick(GtkWidget *dummy, gpointer main_w_arg,
71 static void filter_dlg_ok_cb(GtkWidget *ok_bt, gpointer dummy);
72 static void filter_dlg_apply_cb(GtkWidget *apply_bt, gpointer dummy);
73 static void filter_apply(GtkWidget *main_w, gboolean destroy);
74 static void filter_dlg_save_cb(GtkWidget *save_bt, gpointer parent_w);
75 static void filter_dlg_destroy_cb(GtkWidget *win, gpointer data);
77 static gint filter_sel_list_button_cb(GtkWidget *, GdkEventButton *,
79 #if GTK_MAJOR_VERSION < 2
80 static void filter_sel_list_cb(GtkWidget *, gpointer);
82 static void filter_sel_list_cb(GtkTreeSelection *, gpointer);
84 static void filter_new_bt_clicked_cb(GtkWidget *, gpointer);
85 static void filter_del_bt_clicked_cb(GtkWidget *, gpointer);
86 static void filter_name_te_changed_cb(GtkWidget *, gpointer);
89 /* Create a filter dialog for constructing a capture filter.
91 This is to be used as a callback for a button next to a text entry box,
92 which, when clicked, pops up this dialog to allow you to construct a
93 display filter by browsing the list of saved filters (the dialog
94 for constructing expressions assumes display filter syntax, not
95 capture filter syntax). The "OK" button sets the text entry box to the
96 constructed filter and activates that text entry box (which should have
97 no effect in the main capture dialog); this dialog is then dismissed. */
99 capture_filter_construct_cb(GtkWidget *w, gpointer user_data _U_)
101 GtkWidget *filter_browse_w;
102 GtkWidget *parent_filter_te;
103 /* No Apply button, and "OK" just sets our text widget, it doesn't
104 activate it (i.e., it doesn't cause us to try to open the file). */
105 static construct_args_t args = {
106 "Ethereal: Capture Filter",
111 /* Has a filter dialog box already been opened for that button? */
112 filter_browse_w = OBJECT_GET_DATA(w, E_FILT_DIALOG_PTR_KEY);
114 if (filter_browse_w != NULL) {
115 /* Yes. Just re-activate that dialog box. */
116 reactivate_window(filter_browse_w);
120 /* No. Get the text entry attached to the button. */
121 parent_filter_te = OBJECT_GET_DATA(w, E_FILT_TE_PTR_KEY);
123 /* Now create a new dialog, without an "Add Expression..." button. */
124 filter_browse_w = filter_dialog_new(w, parent_filter_te,
125 CFILTER_LIST, &args);
129 /* Create a filter dialog for constructing a display filter.
131 This is to be used as a callback for a button next to a text entry box,
132 which, when clicked, pops up this dialog to allow you to construct a
133 display filter by browsing the list of saved filters and/or by adding
134 test expressions constructed with another dialog. The "OK" button
135 sets the text entry box to the constructed filter and activates that
136 text entry box, causing the filter to be used; this dialog is then
139 If "wants_apply_button" is non-null, we add an "Apply" button that
140 acts like "OK" but doesn't dismiss this dialog. */
142 display_filter_construct_cb(GtkWidget *w, gpointer construct_args_ptr)
144 construct_args_t *construct_args = construct_args_ptr;
145 GtkWidget *filter_browse_w;
146 GtkWidget *parent_filter_te;
148 /* Has a filter dialog box already been opened for the button? */
149 filter_browse_w = OBJECT_GET_DATA(w, E_FILT_DIALOG_PTR_KEY);
151 if (filter_browse_w != NULL) {
152 /* Yes. Just re-activate that dialog box. */
153 reactivate_window(filter_browse_w);
157 /* No. Get the text entry attached to the button. */
158 parent_filter_te = OBJECT_GET_DATA(w, E_FILT_TE_PTR_KEY);
160 /* Now create a new dialog, possibly with an "Apply" button, and
161 definitely with an "Add Expression..." button. */
162 filter_browse_w = filter_dialog_new(w, parent_filter_te,
163 DFILTER_LIST, construct_args);
166 /* Should be called when a button that creates filters is destroyed; it
167 destroys any filter dialog created by that button. */
169 filter_button_destroy_cb(GtkWidget *button, gpointer user_data _U_)
173 /* Is there a filter edit/selection dialog associated with this
175 filter_w = OBJECT_GET_DATA(button, E_FILT_DIALOG_PTR_KEY);
177 if (filter_w != NULL) {
178 /* Yes. Break the association, and destroy the dialog. */
179 OBJECT_SET_DATA(button, E_FILT_DIALOG_PTR_KEY, NULL);
180 window_destroy(filter_w);
185 static GtkWidget *global_cfilter_w;
187 /* Create a filter dialog for editing capture filters; this is to be used
188 as a callback for menu items, toolbars, etc.. */
190 cfilter_dialog_cb(GtkWidget *w _U_)
192 /* No Apply button, and there's no text widget to set, much less
193 activate, on "OK". */
194 static construct_args_t args = {
195 "Ethereal: Capture Filter",
200 /* Has a filter dialog box already been opened for editing
202 if (global_cfilter_w != NULL) {
203 /* Yes. Just reactivate it. */
204 reactivate_window(global_cfilter_w);
209 * No. Create one; we didn't pop this up as a result of pressing
210 * a button next to some text entry field, so don't associate it
211 * with a text entry field or button.
213 global_cfilter_w = filter_dialog_new(NULL, NULL, CFILTER_LIST, &args);
217 /* Create a filter dialog for editing display filters; this is to be used
218 as a callback for menu items, toolbars, etc.. */
220 dfilter_dialog_cb(GtkWidget *w _U_)
222 static construct_args_t args = {
223 "Ethereal: Display Filter",
228 display_filter_construct_cb(OBJECT_GET_DATA(top_level, E_FILT_BT_PTR_KEY), &args);
231 /* List of capture filter dialogs, so that if the list of filters changes
232 (the model, if you will), we can update all of their lists displaying
233 the filters (the views). */
234 static GList *cfilter_dialogs;
236 /* List of display filter dialogs, so that if the list of filters changes
237 (the model, if you will), we can update all of their lists displaying
238 the filters (the views). */
239 static GList *dfilter_dialogs;
242 remember_filter_dialog(GtkWidget *main_w, GList **filter_dialogs)
244 *filter_dialogs = g_list_append(*filter_dialogs, main_w);
247 /* Remove a filter dialog from the specified list of filter_dialogs. */
249 forget_filter_dialog(GtkWidget *main_w, filter_list_type_t list)
254 cfilter_dialogs = g_list_remove(cfilter_dialogs, main_w);
258 dfilter_dialogs = g_list_remove(dfilter_dialogs, main_w);
262 g_assert_not_reached();
267 /* Get the dialog list corresponding to a particular filter list. */
269 get_filter_dialog_list(filter_list_type_t list)
274 return cfilter_dialogs;
277 return dfilter_dialogs;
280 g_assert_not_reached();
286 filter_dialog_new(GtkWidget *button, GtkWidget *parent_filter_te,
287 filter_list_type_t list, construct_args_t *construct_args)
289 GtkWidget *main_w, /* main window */
290 *main_vb, /* main container */
291 *bbox, /* button container */
292 *ok_bt, /* "OK" button */
293 *apply_bt, /* "Apply" button */
294 *save_bt, /* "Save" button */
295 *close_bt, /* "Cancel" button */
296 *help_bt; /* "Help" button */
297 GtkWidget *filter_vb, /* filter settings box */
315 GtkTooltips *tooltips;
318 static filter_list_type_t cfilter_list_type = CFILTER_LIST;
319 static filter_list_type_t dfilter_list_type = DFILTER_LIST;
320 filter_list_type_t *filter_list_type_p;
321 GList **filter_dialogs;
322 const gchar *filter_te_str = NULL;
323 #if GTK_MAJOR_VERSION < 2
328 gboolean l_select = FALSE;
330 GtkCellRenderer *renderer;
331 GtkTreeViewColumn *column;
332 GtkTreeSelection *sel;
334 GtkTreeIter sel_iter;
337 /* Get a pointer to a static variable holding the type of filter on
338 which we're working, so we can pass that pointer to callback
343 filter_dialogs = &cfilter_dialogs;
344 filter_list_type_p = &cfilter_list_type;
348 filter_dialogs = &dfilter_dialogs;
349 filter_list_type_p = &dfilter_list_type;
353 g_assert_not_reached();
354 filter_dialogs = NULL;
355 filter_list_type_p = NULL;
359 tooltips = gtk_tooltips_new ();
361 main_w = dlg_window_new(construct_args->title);
362 gtk_window_set_default_size(GTK_WINDOW(main_w), 400, 400);
363 OBJECT_SET_DATA(main_w, E_FILT_CONSTRUCT_ARGS_KEY, construct_args);
365 main_vb = gtk_vbox_new(FALSE, 0);
366 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
367 gtk_container_add(GTK_CONTAINER(main_w), main_vb);
368 gtk_widget_show(main_vb);
370 /* Make sure everything is set up */
371 if (parent_filter_te)
372 filter_te_str = gtk_entry_get_text(GTK_ENTRY(parent_filter_te));
374 /* Container for each row of widgets */
375 filter_vb = gtk_vbox_new(FALSE, 0);
376 gtk_container_border_width(GTK_CONTAINER(filter_vb), 0);
377 gtk_container_add(GTK_CONTAINER(main_vb), filter_vb);
378 gtk_widget_show(filter_vb);
380 /* Top row: Buttons and filter list */
381 top_hb = gtk_hbox_new(FALSE, 0);
382 gtk_container_add(GTK_CONTAINER(filter_vb), top_hb);
383 gtk_widget_show(top_hb);
385 edit_fr = gtk_frame_new("Edit");
386 gtk_box_pack_start(GTK_BOX(top_hb), edit_fr, FALSE, FALSE, 0);
387 gtk_widget_show(edit_fr);
389 list_bb = gtk_vbox_new(TRUE, 0);
390 gtk_container_border_width(GTK_CONTAINER(list_bb), 5);
391 gtk_container_add(GTK_CONTAINER(edit_fr), list_bb);
392 gtk_widget_show(list_bb);
394 new_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_NEW);
395 SIGNAL_CONNECT(new_bt, "clicked", filter_new_bt_clicked_cb, filter_list_type_p);
396 #if GTK_MAJOR_VERSION < 2
397 WIDGET_SET_SIZE(new_bt, 50, 20);
399 gtk_widget_show(new_bt);
400 gtk_box_pack_start (GTK_BOX (list_bb), new_bt, FALSE, FALSE, 0);
401 gtk_tooltips_set_tip (tooltips, new_bt,
402 "Create a new filter at the end of the list (with the current properties)", NULL);
404 del_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_DELETE);
405 gtk_widget_set_sensitive(del_bt, FALSE);
406 SIGNAL_CONNECT(del_bt, "clicked", filter_del_bt_clicked_cb, filter_list_type_p);
407 OBJECT_SET_DATA(main_w, E_FILT_DEL_BT_KEY, del_bt);
408 #if GTK_MAJOR_VERSION < 2
409 WIDGET_SET_SIZE(del_bt, 50, 20);
411 gtk_widget_show(del_bt);
412 gtk_box_pack_start (GTK_BOX (list_bb), del_bt, FALSE, FALSE, 0);
413 gtk_tooltips_set_tip (tooltips, del_bt, ("Delete the selected filter"), NULL);
415 filter_fr = gtk_frame_new("Filter");
416 gtk_box_pack_start(GTK_BOX(top_hb), filter_fr, TRUE, TRUE, 0);
417 gtk_widget_show(filter_fr);
419 filter_sc = scrolled_window_new(NULL, NULL);
420 #if GTK_MAJOR_VERSION >= 2
421 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(filter_sc),
425 gtk_container_set_border_width (GTK_CONTAINER (filter_sc), 5);
426 gtk_container_add(GTK_CONTAINER(filter_fr), filter_sc);
427 gtk_widget_show(filter_sc);
429 #if GTK_MAJOR_VERSION < 2
430 filter_l = gtk_list_new();
431 gtk_list_set_selection_mode(GTK_LIST(filter_l), GTK_SELECTION_SINGLE);
432 SIGNAL_CONNECT(filter_l, "selection_changed", filter_sel_list_cb,
435 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
436 filter_l = tree_view_new(GTK_TREE_MODEL(store));
437 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(filter_l), FALSE);
438 renderer = gtk_cell_renderer_text_new();
439 column = gtk_tree_view_column_new_with_attributes("", renderer, "text",
441 gtk_tree_view_column_set_sort_column_id(column, 0);
442 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_l), column);
443 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_l));
444 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
445 SIGNAL_CONNECT(sel, "changed", filter_sel_list_cb, filter_vb);
446 SIGNAL_CONNECT(filter_l, "button_press_event", filter_sel_list_button_cb,
449 OBJECT_SET_DATA(main_w, E_FILT_FILTER_L_KEY, filter_l);
450 #if GTK_MAJOR_VERSION < 2
451 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(filter_sc),
454 gtk_container_add(GTK_CONTAINER(filter_sc), filter_l);
456 gtk_widget_show(filter_l);
458 OBJECT_SET_DATA(filter_l, E_FILT_DBLFUNC_KEY, filter_dlg_dclick);
459 OBJECT_SET_DATA(filter_l, E_FILT_DBLARG_KEY, main_w);
460 /* This is a Boolean, but we make it a non-null pointer for TRUE
461 and a null pointer for FALSE, as object data is a pointer. */
462 OBJECT_SET_DATA(filter_l, E_FILT_DBLACTIVATE_KEY,
463 construct_args->activate_on_ok ? "" : NULL);
466 fl_entry = get_filter_list_first(list);
467 while (fl_entry != NULL) {
468 filt = (filter_def *) fl_entry->data;
469 #if GTK_MAJOR_VERSION < 2
470 nl_lb = gtk_label_new(filt->name);
471 nl_item = gtk_list_item_new();
473 SIGNAL_CONNECT(nl_item, "button_press_event", filter_sel_list_button_cb,
476 gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5);
477 gtk_container_add(GTK_CONTAINER(nl_item), nl_lb);
478 gtk_widget_show(nl_lb);
479 gtk_container_add(GTK_CONTAINER(filter_l), nl_item);
480 gtk_widget_show(nl_item);
481 OBJECT_SET_DATA(nl_item, E_FILT_LBL_KEY, nl_lb);
482 OBJECT_SET_DATA(nl_item, E_FILT_LIST_ITEM_MODEL_KEY, fl_entry);
484 gtk_list_store_append(store, &iter);
485 gtk_list_store_set(store, &iter, 0, filt->name,
489 if (filter_te_str && filt->strval) {
490 if (strcmp(filter_te_str, filt->strval) == 0) {
491 #if GTK_MAJOR_VERSION < 2
500 fl_entry = fl_entry->next;
502 #if GTK_MAJOR_VERSION >= 2
503 g_object_unref(G_OBJECT(store));
507 props_fr = gtk_frame_new("Properties");
508 gtk_box_pack_start(GTK_BOX(filter_vb), props_fr, FALSE, FALSE, 0);
509 gtk_widget_show(props_fr);
511 props_vb = gtk_vbox_new(FALSE, 3);
512 gtk_container_border_width(GTK_CONTAINER(props_vb), 5);
513 gtk_container_add(GTK_CONTAINER(props_fr), props_vb);
514 gtk_widget_show(props_vb);
516 /* row: Filter name entry */
517 middle_hb = gtk_hbox_new(FALSE, 3);
518 gtk_container_add(GTK_CONTAINER(props_vb), middle_hb);
519 gtk_widget_show(middle_hb);
521 name_lb = gtk_label_new("Filter name:");
522 gtk_box_pack_start(GTK_BOX(middle_hb), name_lb, FALSE, FALSE, 0);
523 gtk_widget_show(name_lb);
525 name_te = gtk_entry_new();
526 gtk_box_pack_start(GTK_BOX(middle_hb), name_te, TRUE, TRUE, 0);
527 OBJECT_SET_DATA(main_w, E_FILT_NAME_TE_KEY, name_te);
528 SIGNAL_CONNECT(name_te, "changed", filter_name_te_changed_cb, filter_list_type_p);
529 gtk_widget_show(name_te);
531 /* row: Filter text entry */
532 bottom_hb = gtk_hbox_new(FALSE, 3);
533 gtk_container_add(GTK_CONTAINER(props_vb), bottom_hb);
534 gtk_widget_show(bottom_hb);
536 filter_lb = gtk_label_new("Filter string:");
537 gtk_box_pack_start(GTK_BOX(bottom_hb), filter_lb, FALSE, FALSE, 0);
538 gtk_widget_show(filter_lb);
540 filter_te = gtk_entry_new();
541 gtk_box_pack_start(GTK_BOX(bottom_hb), filter_te, TRUE, TRUE, 0);
542 OBJECT_SET_DATA(main_w, E_FILT_FILTER_TE_KEY, filter_te);
543 SIGNAL_CONNECT(filter_te, "changed", filter_name_te_changed_cb, filter_list_type_p);
544 gtk_widget_show(filter_te);
546 OBJECT_SET_DATA(main_w, E_FILT_PARENT_FILTER_TE_KEY, parent_filter_te);
548 if (list == DFILTER_LIST) {
549 gtk_tooltips_set_tip(tooltips, filter_te,
550 "Enter a display filter. "
551 "The background color of this field is changed by a continuous syntax check (green is valid, red is invalid).",
554 /* Create the "Add Expression..." button, to pop up a dialog
555 for constructing filter comparison expressions. */
556 add_expression_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_ADD_EXPRESSION);
557 SIGNAL_CONNECT(add_expression_bt, "clicked", filter_add_expr_bt_cb, main_w);
558 gtk_box_pack_start(GTK_BOX(bottom_hb), add_expression_bt, FALSE, FALSE, 0);
559 gtk_widget_show(add_expression_bt);
560 gtk_tooltips_set_tip (tooltips, add_expression_bt, ("Add an expression to the filter string"), NULL);
565 if (parent_filter_te != NULL) {
566 if (construct_args->wants_apply_button) {
567 bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_SAVE, GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
569 bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_SAVE, GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
572 if (construct_args->wants_apply_button) {
573 bbox = dlg_button_row_new(GTK_STOCK_APPLY, GTK_STOCK_SAVE, GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
575 bbox = dlg_button_row_new(GTK_STOCK_SAVE, GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
578 gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 5);
579 gtk_widget_show(bbox);
582 if (parent_filter_te != NULL) {
584 * We have a filter text entry that we can fill in if
585 * the "OK" button is clicked, so put in an "OK" button.
587 ok_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_OK);
588 SIGNAL_CONNECT(ok_bt, "clicked", filter_dlg_ok_cb, NULL);
589 gtk_tooltips_set_tip (tooltips, ok_bt, ("Apply the filters and close this dialog"), NULL);
591 /* Catch the "activate" signal on the filter name and filter
592 expression text entries, so that if the user types Return
593 there, we act as if the "OK" button had been selected, as
594 happens if Return is typed if some widget that *doesn't*
595 handle the Return key has the input focus. */
596 dlg_set_activate(name_te, ok_bt);
597 dlg_set_activate(filter_te, ok_bt);
600 if (construct_args->wants_apply_button) {
601 apply_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_APPLY);
602 SIGNAL_CONNECT(apply_bt, "clicked", filter_dlg_apply_cb, NULL);
603 gtk_tooltips_set_tip (tooltips, apply_bt, ("Apply the filters and keep this dialog open"), NULL);
606 save_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_SAVE);
607 SIGNAL_CONNECT(save_bt, "clicked", filter_dlg_save_cb, filter_list_type_p);
608 gtk_tooltips_set_tip (tooltips, save_bt, ("Save the filters permanently and keep this dialog open"), NULL);
610 close_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CLOSE);
611 gtk_tooltips_set_tip (tooltips, close_bt, ("Close this dialog but don't apply the filter changes"), NULL);
612 if (parent_filter_te == NULL)
613 gtk_widget_grab_default(close_bt);
615 help_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_HELP);
616 if (list == CFILTER_LIST) {
617 SIGNAL_CONNECT(help_bt, "clicked", help_topic_cb, "Capture Filters");
619 SIGNAL_CONNECT(help_bt, "clicked", help_topic_cb, "Display Filters");
621 gtk_tooltips_set_tip (tooltips, help_bt, ("Show topic specific help"), NULL);
623 window_set_cancel_button(main_w, close_bt, window_cancel_button_cb);
626 gtk_widget_grab_default(ok_bt);
629 remember_filter_dialog(main_w, filter_dialogs);
631 SIGNAL_CONNECT(main_w, "delete_event", window_delete_event_cb, NULL);
632 /* Call a handler when we're destroyed, so we can detach ourselves
634 SIGNAL_CONNECT(main_w, "destroy", filter_dlg_destroy_cb, filter_list_type_p);
636 if (button != NULL) {
637 /* This dialog box was created by a "Filter" button.
638 Set the E_FILT_BUTTON_PTR_KEY for the new dialog to point to
640 OBJECT_SET_DATA(main_w, E_FILT_BUTTON_PTR_KEY, button);
642 /* Set the E_FILT_DIALOG_PTR_KEY for the button to point to us */
643 OBJECT_SET_DATA(button, E_FILT_DIALOG_PTR_KEY, main_w);
646 /* DO SELECTION THINGS *AFTER* SHOWING THE DIALOG! */
647 /* otherwise the updatings can get confused */
648 #if GTK_MAJOR_VERSION < 2
650 gtk_list_select_child(GTK_LIST(filter_l), l_select);
651 } else if (filter_te_str && filter_te_str[0]) {
652 gtk_entry_set_text(GTK_ENTRY(name_te), "New filter");
653 gtk_entry_set_text(GTK_ENTRY(filter_te), filter_te_str);
657 gtk_tree_selection_select_iter(sel, &sel_iter);
658 } else if (filter_te_str && filter_te_str[0]) {
659 gtk_entry_set_text(GTK_ENTRY(name_te), "New filter");
660 gtk_entry_set_text(GTK_ENTRY(filter_te), filter_te_str);
664 gtk_widget_show(main_w);
665 window_present(main_w);
671 filter_dlg_dclick(GtkWidget *filter_l, gpointer main_w_arg, gpointer activate)
673 GtkWidget *main_w = GTK_WIDGET(main_w_arg);
674 GtkWidget *parent_filter_te =
675 OBJECT_GET_DATA(main_w, E_FILT_PARENT_FILTER_TE_KEY);
678 #if GTK_MAJOR_VERSION < 2
682 GtkTreeSelection *sel;
686 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_l));
689 if (parent_filter_te != NULL) {
691 * We have a text entry widget associated with this dialog
692 * box; is one of the filters in the list selected?
694 #if GTK_MAJOR_VERSION < 2
695 sl = GTK_LIST(filter_l)->selection;
698 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
701 * Yes. Is there a filter definition for that filter?
703 #if GTK_MAJOR_VERSION < 2
704 l_item = GTK_OBJECT(sl->data);
705 flp = (GList *)OBJECT_GET_DATA(l_item,
706 E_FILT_LIST_ITEM_MODEL_KEY);
708 gtk_tree_model_get(model, &iter, 1, &flp, -1);
712 * Yes - put it in the text entry widget.
714 filt = (filter_def *) flp->data;
715 gtk_entry_set_text(GTK_ENTRY(parent_filter_te),
719 * Are we supposed to cause the filter we
720 * put there to be applied?
722 if (activate != NULL) {
726 SIGNAL_EMIT_BY_NAME(parent_filter_te, "activate", NULL);
732 window_destroy(main_w);
736 filter_dlg_ok_cb(GtkWidget *ok_bt, gpointer data _U_)
739 * Destroy the dialog box and apply the filter.
741 filter_apply(gtk_widget_get_toplevel(ok_bt), TRUE);
745 filter_dlg_apply_cb(GtkWidget *apply_bt, gpointer dummy _U_)
748 * Apply the filter, but don't destroy the dialog box.
750 filter_apply(gtk_widget_get_toplevel(apply_bt), FALSE);
754 filter_apply(GtkWidget *main_w, gboolean destroy)
756 construct_args_t *construct_args =
757 OBJECT_GET_DATA(main_w, E_FILT_CONSTRUCT_ARGS_KEY);
758 GtkWidget *parent_filter_te =
759 OBJECT_GET_DATA(main_w, E_FILT_PARENT_FILTER_TE_KEY);
760 GtkWidget *filter_te;
761 const gchar *filter_string;
763 if (parent_filter_te != NULL) {
765 * We have a text entry widget associated with this dialog
766 * box; put the filter in our text entry widget into that
769 filter_te = OBJECT_GET_DATA(main_w, E_FILT_FILTER_TE_KEY);
771 (const gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
772 gtk_entry_set_text(GTK_ENTRY(parent_filter_te), filter_string);
778 * Destroy the filter dialog box.
780 window_destroy(main_w);
783 if (parent_filter_te != NULL) {
785 * We have a text entry widget associated with this dialog
786 * box; activate that widget to cause the filter we put
787 * there to be applied if we're supposed to do so.
789 * We do this after dismissing the filter dialog box,
790 * as activating the widget the dialog box to which
791 * it belongs to be dismissed, and that may cause it
792 * to destroy our dialog box if the filter succeeds.
793 * This means that our subsequent attempt to destroy
796 * We don't know whether it'll destroy our dialog box,
797 * so we can't rely on it to do so. Instead, we
798 * destroy it ourselves, which will clear the
799 * E_FILT_DIALOG_PTR_KEY pointer for their dialog box,
800 * meaning they won't think it has one and won't try
803 if (construct_args->activate_on_ok) {
804 SIGNAL_EMIT_BY_NAME(parent_filter_te, "activate", NULL);
810 filter_dlg_save_cb(GtkWidget *save_bt _U_, gpointer data)
812 filter_list_type_t list = *(filter_list_type_t *)data;
818 /* Create the directory that holds personal configuration files,
820 if (create_persconffile_dir(&pf_dir_path) == -1) {
821 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
822 "Can't create directory\n\"%s\"\nfor filter files: %s.",
823 pf_dir_path, strerror(errno));
828 save_filter_list(list, &f_path, &f_save_errno);
829 if (f_path != NULL) {
830 /* We had an error saving the filter. */
834 filter_type = "capture";
838 filter_type = "display";
842 g_assert_not_reached();
846 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
847 "Could not save to your %s filter file\n\"%s\": %s.",
848 filter_type, f_path, strerror(f_save_errno));
854 filter_dlg_destroy_cb(GtkWidget *win, gpointer data)
856 filter_list_type_t list = *(filter_list_type_t *)data;
859 /* Get the button that requested that we be popped up, if any.
860 (It should arrange to destroy us if it's destroyed, so
861 that we don't get a pointer to a non-existent window here.) */
862 button = OBJECT_GET_DATA(win, E_FILT_BUTTON_PTR_KEY);
864 if (button != NULL) {
865 /* Tell it we no longer exist. */
866 OBJECT_SET_DATA(button, E_FILT_DIALOG_PTR_KEY, NULL);
868 /* This is an editing dialog popped up from, for example,
869 a menu item; note that we no longer have one. */
874 g_assert(win == global_cfilter_w);
875 global_cfilter_w = NULL;
879 g_assert_not_reached();
884 /* Remove this from the list of filter dialog windows. */
885 forget_filter_dialog(win, list);
888 #if GTK_MAJOR_VERSION < 2
890 filter_sel_list_button_cb(GtkWidget *widget, GdkEventButton *event,
894 filter_sel_list_button_cb(GtkWidget *list, GdkEventButton *event,
898 #if GTK_MAJOR_VERSION < 2
899 GtkWidget *list = func_data;
901 void (* func)(GtkWidget *, gpointer, gpointer);
903 gpointer func_activate;
905 #if GTK_MAJOR_VERSION < 2
906 if (!GTK_IS_LIST_ITEM(widget)) return FALSE;
908 if (event->type == GDK_2BUTTON_PRESS) {
909 func = OBJECT_GET_DATA(list, E_FILT_DBLFUNC_KEY);
910 func_arg = OBJECT_GET_DATA(list, E_FILT_DBLARG_KEY);
911 func_activate = OBJECT_GET_DATA(list, E_FILT_DBLACTIVATE_KEY);
914 (*func)(list, func_arg, func_activate);
920 #if GTK_MAJOR_VERSION < 2
922 filter_sel_list_cb(GtkWidget *l, gpointer data _U_)
925 filter_sel_list_cb(GtkTreeSelection *sel, gpointer data _U_)
928 #if GTK_MAJOR_VERSION < 2
929 GtkWidget *main_w = gtk_widget_get_toplevel(l);
933 GtkWidget *filter_l = GTK_WIDGET(gtk_tree_selection_get_tree_view(sel));
934 GtkWidget *main_w = gtk_widget_get_toplevel(filter_l);
938 GtkWidget *name_te = OBJECT_GET_DATA(main_w, E_FILT_NAME_TE_KEY);
939 GtkWidget *filter_te = OBJECT_GET_DATA(main_w, E_FILT_FILTER_TE_KEY);
940 GtkWidget *chg_bt = OBJECT_GET_DATA(main_w, E_FILT_CHG_BT_KEY);
941 GtkWidget *copy_bt = OBJECT_GET_DATA(main_w, E_FILT_COPY_BT_KEY);
942 GtkWidget *del_bt = OBJECT_GET_DATA(main_w, E_FILT_DEL_BT_KEY);
944 gchar *name = NULL, *strval = NULL;
946 gint sensitivity = FALSE;
948 #if GTK_MAJOR_VERSION < 2
950 sl = GTK_LIST(l)->selection;
954 if (sl) { /* Something was selected */
955 l_item = GTK_OBJECT(sl->data);
956 flp = (GList *) OBJECT_GET_DATA(l_item, E_FILT_LIST_ITEM_MODEL_KEY);
958 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
959 gtk_tree_model_get(model, &iter, 1, &flp, -1);
962 filt = (filter_def *) flp->data;
963 name = g_strdup(filt->name);
964 strval = g_strdup(filt->strval);
970 * Did you know that this function is called when the window is destroyed?
972 * This means that we have to:
974 * attach to the top-level window data items containing pointers to
975 * the widgets we affect here;
977 * give each of those widgets their own destroy callbacks;
979 * clear that pointer when the widget is destroyed;
981 * don't do anything to the widget if the pointer we get back is
984 * so that if we're called after any of the widgets we'd affect are
985 * destroyed, we know that we shouldn't do anything to those widgets.
988 gtk_entry_set_text(GTK_ENTRY(name_te), name ? name : "");
989 if (filter_te != NULL)
990 gtk_entry_set_text(GTK_ENTRY(filter_te), strval ? strval : "");
992 gtk_widget_set_sensitive(chg_bt, sensitivity);
994 gtk_widget_set_sensitive(copy_bt, sensitivity);
996 gtk_widget_set_sensitive(del_bt, sensitivity);
1003 /* To do: add input checking to each of these callbacks */
1005 /* Structure containing arguments to be passed to "new_filter_cb()".
1007 "active_filter_l" is the list in the dialog box in which "New" or
1008 "Copy" was clicked; in that dialog box, but not in any other dialog
1009 box, we select the newly created list item.
1011 "nflp" is the GList member in the model (filter list) for the new
1014 GtkWidget *active_filter_l;
1016 } new_filter_cb_args_t;
1019 new_filter_cb(gpointer data, gpointer user_data)
1021 GtkWidget *main_w = data;
1022 #if GTK_MAJOR_VERSION < 2
1023 GtkWidget *filter_l = OBJECT_GET_DATA(main_w, E_FILT_FILTER_L_KEY);
1024 GtkWidget *nl_lb, *nl_item;
1026 GtkTreeView *filter_l;
1027 GtkListStore *store;
1030 new_filter_cb_args_t *args = user_data;
1031 filter_def *nfilt = args->nflp->data;
1033 #if GTK_MAJOR_VERSION < 2
1034 nl_lb = gtk_label_new(nfilt->name);
1035 nl_item = gtk_list_item_new();
1036 gtk_misc_set_alignment(GTK_MISC(nl_lb), 0.0, 0.5);
1037 gtk_container_add(GTK_CONTAINER(nl_item), nl_lb);
1038 gtk_widget_show(nl_lb);
1039 gtk_container_add(GTK_CONTAINER(filter_l), nl_item);
1040 gtk_widget_show(nl_item);
1041 OBJECT_SET_DATA(nl_item, E_FILT_LBL_KEY, nl_lb);
1042 OBJECT_SET_DATA(GTK_OBJECT(nl_item), E_FILT_LIST_ITEM_MODEL_KEY,
1044 if (filter_l == args->active_filter_l) {
1045 /* Select the item. */
1046 gtk_list_select_child(GTK_LIST(filter_l), nl_item);
1049 filter_l = GTK_TREE_VIEW(OBJECT_GET_DATA(main_w, E_FILT_FILTER_L_KEY));
1050 store = GTK_LIST_STORE(gtk_tree_view_get_model(filter_l));
1051 gtk_list_store_append(store, &iter);
1052 gtk_list_store_set(store, &iter, 0, nfilt->name, 1, args->nflp, -1);
1053 if (GTK_WIDGET(filter_l) == args->active_filter_l) {
1054 /* Select the item. */
1055 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(filter_l),
1062 filter_new_bt_clicked_cb(GtkWidget *w, gpointer data)
1064 GtkWidget *main_w = gtk_widget_get_toplevel(w);
1065 GtkWidget *name_te = OBJECT_GET_DATA(main_w, E_FILT_NAME_TE_KEY);
1066 GtkWidget *filter_te = OBJECT_GET_DATA(main_w, E_FILT_FILTER_TE_KEY);
1067 GtkWidget *filter_l = OBJECT_GET_DATA(main_w, E_FILT_FILTER_L_KEY);
1068 filter_list_type_t list = *(filter_list_type_t *)data;
1070 const gchar *name, *strval;
1071 new_filter_cb_args_t args;
1073 name = gtk_entry_get_text(GTK_ENTRY(name_te));
1074 strval = gtk_entry_get_text(GTK_ENTRY(filter_te));
1076 /* if the user didn't entered a name, set default one */
1077 if (strlen(name) == 0) {
1081 /* if the user didn't entered a string value, set default one */
1082 if (strlen(strval) == 0) {
1086 /* Add a new entry to the filter list. */
1087 fl_entry = add_to_filter_list(list, name, strval);
1089 /* Update all the filter list widgets, not just the one in
1090 the dialog box in which we clicked on "Copy". */
1091 args.active_filter_l = filter_l;
1092 args.nflp = fl_entry;
1093 g_list_foreach(get_filter_dialog_list(list), new_filter_cb, &args);
1097 #if GTK_MAJOR_VERSION < 2
1099 chg_list_item_cb(GtkWidget *nl_item, gpointer data)
1102 chg_list_item_cb(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter,
1107 filter_def *filt = flp->data;
1108 #if GTK_MAJOR_VERSION < 2
1110 GTK_LABEL(OBJECT_GET_DATA(nl_item, E_FILT_LBL_KEY));
1112 OBJECT_GET_DATA(nl_item, E_FILT_LIST_ITEM_MODEL_KEY);
1117 #if GTK_MAJOR_VERSION >= 2
1118 gtk_tree_model_get(model, iter, 1, &nl_model, -1);
1120 /* Is this the item corresponding to the filter list item in question? */
1121 if (flp == nl_model) {
1122 /* Yes - change the label to correspond to the new name for the
1124 #if GTK_MAJOR_VERSION < 2
1125 gtk_label_set(nl_lb, filt->name);
1127 gtk_list_store_set(GTK_LIST_STORE(model), iter, 0, filt->name, -1);
1131 #if GTK_MAJOR_VERSION >= 2
1137 chg_filter_cb(gpointer data, gpointer user_data)
1139 GtkWidget *main_w = data;
1140 GtkWidget *filter_l = OBJECT_GET_DATA(main_w, E_FILT_FILTER_L_KEY);
1142 #if GTK_MAJOR_VERSION < 2
1143 gtk_container_foreach(GTK_CONTAINER(filter_l), chg_list_item_cb, user_data);
1145 gtk_tree_model_foreach(gtk_tree_view_get_model(GTK_TREE_VIEW(filter_l)),
1146 chg_list_item_cb, user_data);
1151 filter_name_te_changed_cb(GtkWidget *w, gpointer data)
1153 GtkWidget *main_w = gtk_widget_get_toplevel(w);
1154 GtkWidget *name_te = OBJECT_GET_DATA(main_w, E_FILT_NAME_TE_KEY);
1155 GtkWidget *filter_te = OBJECT_GET_DATA(main_w, E_FILT_FILTER_TE_KEY);
1156 GtkWidget *filter_l = OBJECT_GET_DATA(main_w, E_FILT_FILTER_L_KEY);
1159 filter_list_type_t list = *(filter_list_type_t *)data;
1160 const gchar *name = "";
1161 const gchar *strval = "";
1163 #if GTK_MAJOR_VERSION < 2
1168 GtkTreeSelection *sel;
1169 GtkTreeModel *model;
1173 #if GTK_MAJOR_VERSION < 2
1174 sl = GTK_LIST(filter_l)->selection;
1176 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_l));
1178 name = gtk_entry_get_text(GTK_ENTRY(name_te));
1179 strval = gtk_entry_get_text(GTK_ENTRY(filter_te));
1181 if (DFILTER_LIST == list) {
1182 /* colorize filter string entry */
1183 filter_te_syntax_check_cb(filter_te);
1186 /* if something was selected */
1187 #if GTK_MAJOR_VERSION < 2
1189 l_item = GTK_OBJECT(sl->data);
1190 fl_entry = (GList *) OBJECT_GET_DATA(l_item,
1191 E_FILT_LIST_ITEM_MODEL_KEY);
1192 nl_lb = (GtkLabel *) OBJECT_GET_DATA(l_item, E_FILT_LBL_KEY);
1193 if (fl_entry != NULL && nl_lb != NULL) {
1195 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
1196 gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
1197 if (fl_entry != NULL) {
1199 filt = (filter_def *) fl_entry->data;
1201 if (strlen(name) > 0 && strlen(strval) > 0 && filt) {
1203 g_free(filt->strval);
1204 filt->name = g_strdup(name);
1205 filt->strval = g_strdup(strval);
1207 /* Update all the filter list widgets, not just the one in
1208 the dialog box in which we clicked on "Copy". */
1209 g_list_foreach(get_filter_dialog_list(list), chg_filter_cb,
1217 delete_filter_cb(gpointer data, gpointer user_data)
1219 GtkWidget *main_w = data;
1220 GtkWidget *filter_l = OBJECT_GET_DATA(main_w, E_FILT_FILTER_L_KEY);
1221 #if GTK_MAJOR_VERSION < 2
1222 gint pos = *(gint *)user_data;
1224 gchar *pos = (gchar *)user_data;
1225 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(filter_l));
1229 #if GTK_MAJOR_VERSION < 2
1230 gtk_list_clear_items(GTK_LIST(filter_l), pos, pos + 1);
1232 gtk_tree_model_get_iter_from_string(model, &iter, pos);
1233 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
1238 filter_del_bt_clicked_cb(GtkWidget *w, gpointer data)
1240 GtkWidget *main_w = gtk_widget_get_toplevel(w);
1241 GtkWidget *filter_l = OBJECT_GET_DATA(main_w, E_FILT_FILTER_L_KEY);
1242 filter_list_type_t list = *(filter_list_type_t *)data;
1244 #if GTK_MAJOR_VERSION < 2
1250 GtkTreeSelection *sel;
1251 GtkTreeModel *model;
1256 #if GTK_MAJOR_VERSION < 2
1257 sl = GTK_LIST(filter_l)->selection;
1258 if (sl) { /* Something was selected */
1259 l_item = GTK_OBJECT(sl->data);
1260 pos = gtk_list_child_position(GTK_LIST(filter_l),
1261 GTK_WIDGET(l_item));
1262 fl_entry = (GList *) OBJECT_GET_DATA(l_item, E_FILT_LIST_ITEM_MODEL_KEY);
1264 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_l));
1265 /* If something was selected */
1266 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
1267 gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
1268 path = gtk_tree_model_get_path(model, &iter);
1269 pos = gtk_tree_path_to_string(path);
1270 gtk_tree_path_free(path);
1272 if (fl_entry != NULL) {
1273 /* Remove the entry from the filter list. */
1274 remove_from_filter_list(list, fl_entry);
1276 /* Update all the filter list widgets, not just the one in
1277 the dialog box in which we clicked on "Delete". */
1278 #if GTK_MAJOR_VERSION < 2
1279 g_list_foreach(get_filter_dialog_list(list), delete_filter_cb,
1282 g_list_foreach(get_filter_dialog_list(list), delete_filter_cb, pos);
1285 #if GTK_MAJOR_VERSION >= 2
1292 filter_add_expr_bt_cb(GtkWidget *w _U_, gpointer main_w_arg)
1294 GtkWidget *main_w = GTK_WIDGET(main_w_arg);
1295 GtkWidget *filter_te;
1297 filter_te = OBJECT_GET_DATA(main_w, E_FILT_FILTER_TE_KEY);
1298 dfilter_expr_dlg_new(filter_te);
1302 color_filter_te(GtkWidget *w, guint16 red, guint16 green, guint16 blue)
1312 style = gtk_style_copy(gtk_widget_get_style(w));
1313 style->base[GTK_STATE_NORMAL] = bg;
1314 gtk_widget_set_style(w, style);
1318 colorize_filter_te_as_empty(GtkWidget *w)
1321 color_filter_te(w, 0xFFFF, 0xFFFF, 0xFFFF);
1325 colorize_filter_te_as_invalid(GtkWidget *w)
1328 color_filter_te(w, 0xFFFF, 0xAFFF, 0xAFFF);
1332 colorize_filter_te_as_valid(GtkWidget *w)
1335 color_filter_te(w, 0xAFFF, 0xFFFF, 0xAFFF);
1339 filter_te_syntax_check_cb(GtkWidget *w)
1341 const gchar *strval;
1344 strval = gtk_entry_get_text(GTK_ENTRY(w));
1346 /* colorize filter string entry */
1347 if (strval && dfilter_compile(strval, &dfp)) {
1350 if (strlen(strval) == 0)
1351 colorize_filter_te_as_empty(w);
1353 colorize_filter_te_as_valid(w);
1355 colorize_filter_te_as_invalid(w);