2 * Dialog boxes for filter editing
3 * (This used to be a notebook page under "Preferences", hence the
4 * "prefs" in the file name.)
6 * $Id: filter_prefs.c,v 1.5 2002/09/14 10:07:39 oabad Exp $
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@ethereal.com>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35 #include <epan/filesystem.h>
39 #include "filter_prefs.h"
40 #include "dlg_utils.h"
42 #include "simple_dialog.h"
43 #include "dfilter_expr_dlg.h"
45 #define E_FILT_PARENT_FILTER_TE_KEY "filter_parent_filter_te"
46 #define E_FILT_CONSTRUCT_ARGS_KEY "filter_construct_args"
47 #define E_FILT_LIST_ITEM_MODEL_KEY "filter_list_item_model"
48 #define E_FILT_LBL_KEY "filter_label"
49 #define E_FILT_FILTER_L_KEY "filter_filter_l"
50 #define E_FILT_CHG_BT_KEY "filter_chg_bt"
51 #define E_FILT_COPY_BT_KEY "filter_copy_bt"
52 #define E_FILT_DEL_BT_KEY "filter_del_bt"
53 #define E_FILT_NAME_TE_KEY "filter_name_te"
54 #define E_FILT_FILTER_TE_KEY "filter_filter_te"
55 #define E_FILT_DBLFUNC_KEY "filter_dblfunc"
56 #define E_FILT_DBLARG_KEY "filter_dblarg"
57 #define E_FILT_DBLACTIVATE_KEY "filter_dblactivate"
59 typedef struct _filter_cb_data {
64 static GtkWidget *filter_dialog_new(GtkWidget *caller, GtkWidget *filter_te,
65 filter_list_type_t list,
66 construct_args_t *construct_args);
67 static void filter_dlg_dclick(GtkWidget *dummy, gpointer main_w_arg,
69 static void filter_dlg_ok_cb(GtkWidget *ok_bt, gpointer dummy);
70 static void filter_dlg_apply_cb(GtkWidget *apply_bt, gpointer dummy);
71 static void filter_apply(GtkWidget *main_w, gboolean destroy);
72 static void filter_dlg_save_cb(GtkWidget *save_bt, gpointer parent_w);
73 static void filter_dlg_close_cb(GtkWidget *close_bt, gpointer parent_w);
74 static void filter_dlg_destroy(GtkWidget *win, gpointer data);
76 static gint filter_sel_list_button_cb(GtkWidget *, GdkEventButton *,
78 static void filter_sel_list_cb(GtkTreeSelection *, gpointer);
79 static void filter_list_destroy_cb(GtkWidget *, gpointer);
80 static void filter_new_bt_clicked_cb(GtkWidget *, gpointer);
81 static void filter_chg_bt_clicked_cb(GtkWidget *, gpointer);
82 static void filter_chg_bt_destroy_cb(GtkWidget *, gpointer);
83 static void filter_copy_bt_clicked_cb(GtkWidget *, gpointer);
84 static void filter_copy_bt_destroy_cb(GtkWidget *, gpointer);
85 static void filter_del_bt_clicked_cb(GtkWidget *, gpointer);
86 static void filter_del_bt_destroy_cb(GtkWidget *, gpointer);
87 static void filter_expr_cb(GtkWidget *, gpointer);
88 static void filter_name_te_destroy_cb(GtkWidget *, gpointer);
89 static void filter_filter_te_destroy_cb(GtkWidget *, gpointer);
92 /* Create a filter dialog for constructing a capture filter.
94 This is to be used as a callback for a button next to a text entry box,
95 which, when clicked, pops up this dialog to allow you to construct a
96 display filter by browsing the list of saved filters (the dialog
97 for constructing expressions assumes display filter syntax, not
98 capture filter syntax). The "OK" button sets the text entry box to the
99 constructed filter and activates that text entry box (which should have
100 no effect in the main capture dialog); this dialog is then dismissed. */
102 capture_filter_construct_cb(GtkWidget *w, gpointer user_data _U_)
104 GtkWidget *caller = gtk_widget_get_toplevel(w);
105 GtkWidget *filter_browse_w;
106 GtkWidget *parent_filter_te;
107 /* No Apply button, and "OK" just sets our text widget, it doesn't
108 activate it (i.e., it doesn't cause us to try to open the file). */
109 static construct_args_t args = {
110 "Ethereal: Capture Filter",
115 /* Has a filter dialog box already been opened for that top-level
117 filter_browse_w = gtk_object_get_data(GTK_OBJECT(caller),
118 E_FILT_DIALOG_PTR_KEY);
120 if (filter_browse_w != NULL) {
121 /* Yes. Just re-activate that dialog box. */
122 reactivate_window(filter_browse_w);
126 /* No. Get the text entry attached to the button. */
127 parent_filter_te = gtk_object_get_data(GTK_OBJECT(w), E_FILT_TE_PTR_KEY);
129 /* Now create a new dialog, without an "Add Expression..." button. */
130 filter_browse_w = filter_dialog_new(caller, parent_filter_te,
131 CFILTER_LIST, &args);
133 /* Set the E_FILT_CALLER_PTR_KEY for the new dialog to point to
135 gtk_object_set_data(GTK_OBJECT(filter_browse_w), E_FILT_CALLER_PTR_KEY,
138 /* Set the E_FILT_DIALOG_PTR_KEY for the caller to point to us */
139 gtk_object_set_data(GTK_OBJECT(caller), E_FILT_DIALOG_PTR_KEY,
144 /* Create a filter dialog for constructing a display filter.
146 This is to be used as a callback for a button next to a text entry box,
147 which, when clicked, pops up this dialog to allow you to construct a
148 display filter by browsing the list of saved filters and/or by adding
149 test expressions constructed with another dialog. The "OK" button
150 sets the text entry box to the constructed filter and activates that
151 text entry box, causing the filter to be used; this dialog is then
154 If "wants_apply_button" is non-null, we add an "Apply" button that
155 acts like "OK" but doesn't dismiss this dialog. */
157 display_filter_construct_cb(GtkWidget *w, gpointer construct_args_ptr)
159 construct_args_t *construct_args = construct_args_ptr;
160 GtkWidget *caller = gtk_widget_get_toplevel(w);
161 GtkWidget *filter_browse_w;
162 GtkWidget *parent_filter_te;
164 /* Has a filter dialog box already been opened for that top-level
166 filter_browse_w = gtk_object_get_data(GTK_OBJECT(caller),
167 E_FILT_DIALOG_PTR_KEY);
169 if (filter_browse_w != NULL) {
170 /* Yes. Just re-activate that dialog box. */
171 reactivate_window(filter_browse_w);
175 /* No. Get the text entry attached to the button. */
176 parent_filter_te = gtk_object_get_data(GTK_OBJECT(w), E_FILT_TE_PTR_KEY);
178 /* Now create a new dialog, possibly with an "Apply" button, and
179 definitely with an "Add Expression..." button. */
180 filter_browse_w = filter_dialog_new(caller, parent_filter_te,
181 DFILTER_LIST, construct_args);
183 /* Set the E_FILT_CALLER_PTR_KEY for the new dialog to point to
185 gtk_object_set_data(GTK_OBJECT(filter_browse_w), E_FILT_CALLER_PTR_KEY,
188 /* Set the E_FILT_DIALOG_PTR_KEY for the caller to point to us */
189 gtk_object_set_data(GTK_OBJECT(caller), E_FILT_DIALOG_PTR_KEY,
194 static GtkWidget *global_cfilter_w;
196 /* Create a filter dialog for editing capture filters; this is to be used
197 as a callback for menu items, toolbars, etc.. */
199 cfilter_dialog_cb(GtkWidget *w _U_)
201 /* No Apply button, and there's no text widget to set, much less
202 activate, on "OK". */
203 static construct_args_t args = {
204 "Ethereal: Edit Capture Filter List",
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.
222 global_cfilter_w = filter_dialog_new(NULL, NULL, CFILTER_LIST, &args);
226 static GtkWidget *global_dfilter_w;
228 /* Create a filter dialog for editing display filters; this is to be used
229 as a callback for menu items, toolbars, etc.. */
231 dfilter_dialog_cb(GtkWidget *w _U_)
233 /* No Apply button, and there's no text widget to set, much less
234 activate, on "OK". */
235 static construct_args_t args = {
236 "Ethereal: Edit Display Filter List",
241 /* Has a filter dialog box already been opened for editing
243 if (global_dfilter_w != NULL) {
244 /* Yes. Just reactivate it. */
245 reactivate_window(global_dfilter_w);
250 * No. Create one; we didn't pop this up as a result of pressing
251 * a button next to some text entry field, so don't associate it
252 * with a text entry field.
254 global_dfilter_w = filter_dialog_new(NULL, NULL, DFILTER_LIST, &args);
257 /* List of capture filter dialogs, so that if the list of filters changes
258 (the model, if you will), we can update all of their lists displaying
259 the filters (the views). */
260 static GList *cfilter_dialogs;
262 /* List of display filter dialogs, so that if the list of filters changes
263 (the model, if you will), we can update all of their lists displaying
264 the filters (the views). */
265 static GList *dfilter_dialogs;
268 remember_filter_dialog(GtkWidget *main_w, GList **filter_dialogs)
270 *filter_dialogs = g_list_append(*filter_dialogs, main_w);
273 /* Remove a filter dialog from the specified list of filter_dialogs. */
275 forget_filter_dialog(GtkWidget *main_w, filter_list_type_t list)
280 cfilter_dialogs = g_list_remove(cfilter_dialogs, main_w);
284 dfilter_dialogs = g_list_remove(dfilter_dialogs, main_w);
288 g_assert_not_reached();
293 /* Get the dialog list corresponding to a particular filter list. */
295 get_filter_dialog_list(filter_list_type_t list)
300 return cfilter_dialogs;
303 return dfilter_dialogs;
306 g_assert_not_reached();
312 filter_dialog_new(GtkWidget *caller _U_, GtkWidget *parent_filter_te,
313 filter_list_type_t list, construct_args_t *construct_args)
315 GtkWidget *main_w, /* main window */
316 *main_vb, /* main container */
317 *bbox, /* button container */
318 *ok_bt, /* "OK" button */
319 *apply_bt, /* "Apply" button */
320 *save_bt, /* "Save" button */
321 *close_bt; /* "Cancel" button */
322 GtkWidget *filter_pg = NULL; /* filter settings box */
338 gboolean l_select = FALSE;
341 const gchar *filter_te_str = NULL;
342 GList **filter_dialogs;
343 static filter_list_type_t cfilter_list = CFILTER_LIST;
344 static filter_list_type_t dfilter_list = DFILTER_LIST;
345 filter_list_type_t *filter_list_p;
347 GtkCellRenderer *renderer;
348 GtkTreeViewColumn *column;
349 GtkTreeSelection *sel;
352 /* Get a pointer to a static variable holding the type of filter on
353 which we're working, so we can pass that pointer to callback
358 filter_dialogs = &cfilter_dialogs;
359 filter_list_p = &cfilter_list;
363 filter_dialogs = &dfilter_dialogs;
364 filter_list_p = &dfilter_list;
368 g_assert_not_reached();
369 filter_dialogs = NULL;
370 filter_list_p = NULL;
374 main_w = dlg_window_new(construct_args->title);
375 gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_CONSTRUCT_ARGS_KEY,
378 /* Call a handler when we're destroyed, so we can inform
379 our caller, if any, that we've been destroyed. */
380 g_signal_connect(G_OBJECT(main_w), "destroy",
381 G_CALLBACK(filter_dlg_destroy), filter_list_p);
383 main_vb = gtk_vbox_new(FALSE, 5);
384 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
385 gtk_container_add(GTK_CONTAINER(main_w), main_vb);
386 gtk_widget_show(main_vb);
388 /* Make sure everything is set up */
389 if (parent_filter_te)
390 filter_te_str = gtk_entry_get_text(GTK_ENTRY(parent_filter_te));
392 /* Container for each row of widgets */
393 filter_pg = gtk_vbox_new(FALSE, 5);
394 gtk_container_border_width(GTK_CONTAINER(filter_pg), 5);
395 gtk_widget_show(filter_pg);
397 /* Top row: Filter list and buttons */
398 top_hb = gtk_hbox_new(FALSE, 5);
399 gtk_container_add(GTK_CONTAINER(filter_pg), top_hb);
400 gtk_widget_show(top_hb);
402 list_bb = gtk_vbutton_box_new();
403 gtk_button_box_set_layout (GTK_BUTTON_BOX (list_bb), GTK_BUTTONBOX_START);
404 gtk_container_add(GTK_CONTAINER(top_hb), list_bb);
405 gtk_widget_show(list_bb);
407 new_bt = gtk_button_new_from_stock(GTK_STOCK_NEW);
408 g_signal_connect(G_OBJECT(new_bt), "clicked",
409 G_CALLBACK(filter_new_bt_clicked_cb), filter_list_p);
410 gtk_container_add(GTK_CONTAINER(list_bb), new_bt);
411 gtk_widget_show(new_bt);
413 chg_bt = gtk_button_new_with_label ("Change");
414 gtk_widget_set_sensitive(chg_bt, FALSE);
415 g_signal_connect(G_OBJECT(chg_bt), "clicked",
416 G_CALLBACK(filter_chg_bt_clicked_cb), filter_list_p);
417 gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_CHG_BT_KEY, chg_bt);
418 g_signal_connect(G_OBJECT(chg_bt), "destroy",
419 G_CALLBACK(filter_chg_bt_destroy_cb), NULL);
420 gtk_container_add(GTK_CONTAINER(list_bb), chg_bt);
421 gtk_widget_show(chg_bt);
423 copy_bt = gtk_button_new_from_stock(GTK_STOCK_COPY);
424 gtk_widget_set_sensitive(copy_bt, FALSE);
425 g_signal_connect(G_OBJECT(copy_bt), "clicked",
426 G_CALLBACK(filter_copy_bt_clicked_cb), filter_list_p);
427 gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_COPY_BT_KEY, copy_bt);
428 g_signal_connect(G_OBJECT(copy_bt), "destroy",
429 G_CALLBACK(filter_copy_bt_destroy_cb), NULL);
430 gtk_container_add(GTK_CONTAINER(list_bb), copy_bt);
431 gtk_widget_show(copy_bt);
433 del_bt = gtk_button_new_from_stock(GTK_STOCK_DELETE);
434 gtk_widget_set_sensitive(del_bt, FALSE);
435 g_signal_connect(G_OBJECT(del_bt), "clicked",
436 G_CALLBACK(filter_del_bt_clicked_cb), filter_list_p);
437 gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_DEL_BT_KEY, del_bt);
438 g_signal_connect(G_OBJECT(del_bt), "destroy",
439 G_CALLBACK(filter_del_bt_destroy_cb), NULL);
440 gtk_container_add(GTK_CONTAINER(list_bb), del_bt);
441 gtk_widget_show(del_bt);
443 if (list == DFILTER_LIST) {
444 /* Create the "Add Expression..." button, to pop up a dialog
445 for constructing filter comparison expressions. */
446 add_expression_bt = gtk_button_new_with_label("Add Expression...");
447 g_signal_connect(G_OBJECT(add_expression_bt), "clicked",
448 G_CALLBACK(filter_expr_cb), main_w);
449 gtk_container_add(GTK_CONTAINER(list_bb), add_expression_bt);
450 gtk_widget_show(add_expression_bt);
453 filter_sc = gtk_scrolled_window_new(NULL, NULL);
454 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(filter_sc),
455 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
456 gtk_widget_set_size_request(filter_sc, 250, 150);
457 gtk_container_add(GTK_CONTAINER(top_hb), filter_sc);
458 gtk_widget_show(filter_sc);
460 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
461 filter_l = tree_view_new(GTK_TREE_MODEL(store));
462 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(filter_l), FALSE);
463 renderer = gtk_cell_renderer_text_new();
464 column = gtk_tree_view_column_new_with_attributes("", renderer, "text",
466 gtk_tree_view_column_set_sort_column_id(column, 0);
467 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_l), column);
468 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_l));
469 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
470 g_signal_connect(G_OBJECT(sel), "changed",
471 G_CALLBACK(filter_sel_list_cb), filter_pg);
472 gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_FILTER_L_KEY, filter_l);
473 g_signal_connect(G_OBJECT(filter_l), "destroy",
474 G_CALLBACK(filter_list_destroy_cb), NULL);
475 g_signal_connect(G_OBJECT(filter_l), "button_press_event",
476 G_CALLBACK(filter_sel_list_button_cb), NULL);
477 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(filter_sc),
479 gtk_widget_show(filter_l);
481 gtk_object_set_data(GTK_OBJECT(filter_l), E_FILT_DBLFUNC_KEY,
483 gtk_object_set_data(GTK_OBJECT(filter_l), E_FILT_DBLARG_KEY, main_w);
484 /* This is a Boolean, but we make it a non-null pointer for TRUE
485 and a null pointer for FALSE, as object data is a pointer. */
486 gtk_object_set_data(GTK_OBJECT(filter_l), E_FILT_DBLACTIVATE_KEY,
487 construct_args->activate_on_ok? "" : NULL);
489 fl_entry = get_filter_list_first(list);
490 while (fl_entry != NULL) {
491 filt = (filter_def *) fl_entry->data;
492 gtk_list_store_append(store, &iter);
493 gtk_list_store_set(store, &iter, 0, filt->name,
495 if (filter_te_str && filt->strval) {
496 if (strcmp(filter_te_str, filt->strval) == 0)
498 gtk_tree_selection_select_iter(sel, &iter);
503 fl_entry = fl_entry->next;
505 g_object_unref(G_OBJECT(store));
507 /* Middle row: Filter name entry */
508 middle_hb = gtk_hbox_new(FALSE, 5);
509 gtk_container_add(GTK_CONTAINER(filter_pg), middle_hb);
510 gtk_widget_show(middle_hb);
512 name_lb = gtk_label_new("Filter name:");
513 gtk_box_pack_start(GTK_BOX(middle_hb), name_lb, FALSE, FALSE, 3);
514 gtk_widget_show(name_lb);
516 name_te = gtk_entry_new();
517 gtk_box_pack_start(GTK_BOX(middle_hb), name_te, TRUE, TRUE, 3);
518 gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_NAME_TE_KEY, name_te);
519 g_signal_connect(G_OBJECT(name_te), "destroy",
520 G_CALLBACK(filter_name_te_destroy_cb), NULL);
521 gtk_widget_show(name_te);
523 /* Bottom row: Filter text entry */
524 bottom_hb = gtk_hbox_new(FALSE, 5);
525 gtk_container_add(GTK_CONTAINER(filter_pg), bottom_hb);
526 gtk_widget_show(bottom_hb);
528 filter_lb = gtk_label_new("Filter string:");
529 gtk_box_pack_start(GTK_BOX(bottom_hb), filter_lb, FALSE, FALSE, 3);
530 gtk_widget_show(filter_lb);
532 filter_te = gtk_entry_new();
533 gtk_box_pack_start(GTK_BOX(bottom_hb), filter_te, TRUE, TRUE, 3);
534 gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_FILTER_TE_KEY, filter_te);
536 g_signal_connect(G_OBJECT(filter_te), "destroy",
537 G_CALLBACK(filter_filter_te_destroy_cb), NULL);
538 gtk_widget_show(filter_te);
540 if (!l_select && filter_te_str && filter_te_str[0]) {
541 gtk_entry_set_text(GTK_ENTRY(name_te), "New filter");
542 gtk_entry_set_text(GTK_ENTRY(filter_te), filter_te_str);
545 gtk_box_pack_start(GTK_BOX(main_vb), filter_pg, TRUE, TRUE, 0);
546 gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_PARENT_FILTER_TE_KEY,
549 bbox = gtk_hbutton_box_new();
550 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
551 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
552 gtk_container_add(GTK_CONTAINER(main_vb), bbox);
553 gtk_widget_show(bbox);
555 if (parent_filter_te != NULL) {
557 * We have a filter text entry that we can fill in if
558 * the "OK" button is clicked, so put in an "OK" button.
560 ok_bt = gtk_button_new_from_stock(GTK_STOCK_OK);
561 g_signal_connect(G_OBJECT(ok_bt), "clicked",
562 G_CALLBACK(filter_dlg_ok_cb), NULL);
563 GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
564 gtk_box_pack_start(GTK_BOX(bbox), ok_bt, TRUE, TRUE, 0);
565 gtk_widget_grab_default(ok_bt);
566 gtk_widget_show(ok_bt);
568 /* Catch the "activate" signal on the filter name and filter
569 expression text entries, so that if the user types Return
570 there, we act as if the "OK" button had been selected, as
571 happens if Return is typed if some widget that *doesn't*
572 handle the Return key has the input focus. */
573 dlg_set_activate(name_te, ok_bt);
574 dlg_set_activate(filter_te, ok_bt);
577 if (construct_args->wants_apply_button) {
578 apply_bt = gtk_button_new_from_stock(GTK_STOCK_APPLY);
579 g_signal_connect(G_OBJECT(apply_bt), "clicked",
580 G_CALLBACK(filter_dlg_apply_cb), NULL);
581 GTK_WIDGET_SET_FLAGS(apply_bt, GTK_CAN_DEFAULT);
582 gtk_box_pack_start(GTK_BOX(bbox), apply_bt, TRUE, TRUE, 0);
583 gtk_widget_show(apply_bt);
586 save_bt = gtk_button_new_from_stock(GTK_STOCK_SAVE);
587 g_signal_connect(G_OBJECT(save_bt), "clicked",
588 G_CALLBACK(filter_dlg_save_cb), filter_list_p);
589 GTK_WIDGET_SET_FLAGS(save_bt, GTK_CAN_DEFAULT);
590 gtk_box_pack_start(GTK_BOX(bbox), save_bt, TRUE, TRUE, 0);
591 gtk_widget_show(save_bt);
593 close_bt = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
594 g_signal_connect(G_OBJECT(close_bt), "clicked",
595 G_CALLBACK(filter_dlg_close_cb), GTK_OBJECT(main_w));
596 GTK_WIDGET_SET_FLAGS(close_bt, GTK_CAN_DEFAULT);
597 gtk_box_pack_start(GTK_BOX(bbox), close_bt, TRUE, TRUE, 0);
598 gtk_widget_show(close_bt);
601 * Catch the "key_press_event" signal in the window, so that we can
602 * catch the ESC key being pressed and act as if the "Close" button
605 dlg_set_cancel(main_w, close_bt);
607 remember_filter_dialog(main_w, filter_dialogs);
609 gtk_widget_show(main_w);
615 filter_dlg_dclick(GtkWidget *filter_l, gpointer main_w_arg, gpointer activate)
617 GtkWidget *main_w = GTK_WIDGET(main_w_arg);
618 GtkWidget *parent_filter_te =
619 gtk_object_get_data(GTK_OBJECT(main_w), E_FILT_PARENT_FILTER_TE_KEY);
622 GtkTreeSelection *sel;
626 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_l));
628 if (parent_filter_te != NULL) {
630 * We have a text entry widget associated with this dialog
631 * box; is one of the filters in the list selected?
634 /* if something was selected */
635 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
637 * Yes. Is there a filter definition for that filter?
639 gtk_tree_model_get(model, &iter, 1, &flp, -1);
642 * Yes - put it in the text entry widget.
644 filt = (filter_def *) flp->data;
645 gtk_entry_set_text(GTK_ENTRY(parent_filter_te),
649 * Are we supposed to cause the filter we
650 * put there to be applied?
652 if (activate != NULL) {
656 g_signal_emit_by_name(G_OBJECT(parent_filter_te),
663 gtk_widget_destroy(main_w);
667 filter_dlg_ok_cb(GtkWidget *ok_bt, gpointer data _U_)
670 * Destroy the dialog box and apply the filter.
672 filter_apply(gtk_widget_get_toplevel(ok_bt), TRUE);
676 filter_dlg_apply_cb(GtkWidget *apply_bt, gpointer dummy _U_)
679 * Apply the filter, but don't destroy the dialog box.
681 filter_apply(gtk_widget_get_toplevel(apply_bt), FALSE);
685 filter_apply(GtkWidget *main_w, gboolean destroy)
687 construct_args_t *construct_args =
688 gtk_object_get_data(GTK_OBJECT(main_w), E_FILT_CONSTRUCT_ARGS_KEY);
689 GtkWidget *parent_filter_te =
690 gtk_object_get_data(GTK_OBJECT(main_w), E_FILT_PARENT_FILTER_TE_KEY);
691 GtkWidget *filter_te;
692 const gchar *filter_string;
694 if (parent_filter_te != NULL) {
696 * We have a text entry widget associated with this dialog
697 * box; put the filter in our text entry widget into that
700 filter_te = gtk_object_get_data(GTK_OBJECT(main_w),
701 E_FILT_FILTER_TE_KEY);
702 filter_string = gtk_entry_get_text(GTK_ENTRY(filter_te));
703 gtk_entry_set_text(GTK_ENTRY(parent_filter_te), filter_string);
709 * Destroy the filter dialog box.
711 gtk_widget_destroy(main_w);
714 if (parent_filter_te != NULL) {
716 * We have a text entry widget associated with this dialog
717 * box; activate that widget to cause the filter we put
718 * there to be applied if we're supposed to do so.
720 * We do this after dismissing the filter dialog box,
721 * as activating the widget the dialog box to which
722 * it belongs to be dismissed, and that may cause it
723 * to destroy our dialog box if the filter succeeds.
724 * This means that our subsequent attempt to destroy
727 * We don't know whether it'll destroy our dialog box,
728 * so we can't rely on it to do so. Instead, we
729 * destroy it ourselves, which will clear the
730 * E_FILT_DIALOG_PTR_KEY pointer for their dialog box,
731 * meaning they won't think it has one and won't try
734 if (construct_args->activate_on_ok) {
735 g_signal_emit_by_name(G_OBJECT(parent_filter_te), "activate");
741 filter_dlg_save_cb(GtkWidget *save_bt _U_, gpointer data)
743 filter_list_type_t list = *(filter_list_type_t *)data;
749 /* Create the directory that holds personal configuration files,
751 if (create_persconffile_dir(&pf_dir_path) == -1) {
752 simple_dialog(ESD_TYPE_WARN, NULL,
753 "Can't create directory\n\"%s\"\nfor filter files: %s.",
754 pf_dir_path, strerror(errno));
759 save_filter_list(list, &f_path, &f_save_errno);
760 if (f_path != NULL) {
761 /* We had an error saving the filter. */
765 filter_type = "capture";
769 filter_type = "display";
773 g_assert_not_reached();
777 simple_dialog(ESD_TYPE_CRIT, NULL,
778 "Could not save to your %s filter file\n\"%s\": %s.",
779 filter_type, f_path, strerror(f_save_errno));
785 filter_dlg_close_cb(GtkWidget *close_bt _U_, gpointer parent_w)
787 gtk_widget_destroy(GTK_WIDGET(parent_w));
791 filter_dlg_destroy(GtkWidget *win, gpointer data)
793 filter_list_type_t list = *(filter_list_type_t *)data;
796 /* Get the widget that requested that we be popped up, if any.
797 (It should arrange to destroy us if it's destroyed, so
798 that we don't get a pointer to a non-existent window here.) */
799 caller = gtk_object_get_data(GTK_OBJECT(win), E_FILT_CALLER_PTR_KEY);
801 if (caller != NULL) {
802 /* Tell it we no longer exist. */
803 gtk_object_set_data(GTK_OBJECT(caller), E_FILT_DIALOG_PTR_KEY,
806 /* This is an editing dialog popped up from, for example,
807 a menu item; note that we no longer have one. */
812 g_assert(win == global_cfilter_w);
813 global_cfilter_w = NULL;
818 g_assert(win == global_dfilter_w);
819 global_dfilter_w = NULL;
823 g_assert_not_reached();
828 /* Remove this from the list of filter dialog windows. */
829 forget_filter_dialog(win, list);
831 /* Now nuke this window. */
832 gtk_grab_remove(GTK_WIDGET(win));
833 gtk_widget_destroy(GTK_WIDGET(win));
837 filter_sel_list_button_cb(GtkWidget *list, GdkEventButton *event,
840 void (* func)(GtkWidget *, gpointer, gpointer);
842 gpointer func_activate;
844 if (event->type == GDK_2BUTTON_PRESS) {
845 func = gtk_object_get_data(GTK_OBJECT(list), E_FILT_DBLFUNC_KEY);
846 func_arg = gtk_object_get_data(GTK_OBJECT(list), E_FILT_DBLARG_KEY);
847 func_activate = gtk_object_get_data(GTK_OBJECT(list),
848 E_FILT_DBLACTIVATE_KEY);
851 (*func)(list, func_arg, func_activate);
858 filter_sel_list_cb(GtkTreeSelection *sel, gpointer data _U_)
860 GtkWidget *filter_l = GTK_WIDGET(gtk_tree_selection_get_tree_view(sel));
861 GtkWidget *main_w = gtk_widget_get_toplevel(filter_l);
862 GtkWidget *name_te = gtk_object_get_data(GTK_OBJECT(main_w),
864 GtkWidget *filter_te = gtk_object_get_data(GTK_OBJECT(main_w),
865 E_FILT_FILTER_TE_KEY);
866 GtkWidget *chg_bt = gtk_object_get_data(GTK_OBJECT(main_w),
868 GtkWidget *copy_bt = gtk_object_get_data(GTK_OBJECT(main_w),
870 GtkWidget *del_bt = gtk_object_get_data(GTK_OBJECT(main_w),
873 gchar *name = "", *strval = "";
875 gint sensitivity = FALSE;
879 /* if something was selected */
880 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
881 gtk_tree_model_get(model, &iter, 1, &flp, -1);
883 filt = (filter_def *) flp->data;
885 strval = filt->strval;
891 * Did you know that this function is called when the window is destroyed?
893 * This means that we have to:
895 * attach to the top-level window data items containing pointers to
896 * the widgets we affect here;
898 * give each of those widgets their own destroy callbacks;
900 * clear that pointer when the widget is destroyed;
902 * don't do anything to the widget if the pointer we get back is
905 * so that if we're called after any of the widgets we'd affect are
906 * destroyed, we know that we shouldn't do anything to those widgets.
909 gtk_entry_set_text(GTK_ENTRY(name_te), name);
910 if (filter_te != NULL)
911 gtk_entry_set_text(GTK_ENTRY(filter_te), strval);
913 gtk_widget_set_sensitive(chg_bt, sensitivity);
915 gtk_widget_set_sensitive(copy_bt, sensitivity);
917 gtk_widget_set_sensitive(del_bt, sensitivity);
921 filter_list_destroy_cb(GtkWidget *l, gpointer data _U_)
923 GtkWidget *main_w = gtk_widget_get_toplevel(l);
925 gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_FILTER_L_KEY, NULL);
928 /* To do: add input checking to each of these callbacks */
930 /* Structure containing arguments to be passed to "new_filter_cb()".
932 "active_filter_l" is the list in the dialog box in which "New" or
933 "Copy" was clicked; in that dialog box, but not in any other dialog
934 box, we select the newly created list item.
936 "nflp" is the GList member in the model (filter list) for the new
939 GtkWidget *active_filter_l;
941 } new_filter_cb_args_t;
944 new_filter_cb(gpointer data, gpointer user_data)
946 GtkWidget *main_w = data;
947 GtkTreeView *filter_l;
948 new_filter_cb_args_t *args = user_data;
949 filter_def *nfilt = args->nflp->data;
953 filter_l = GTK_TREE_VIEW(gtk_object_get_data(GTK_OBJECT(main_w),
954 E_FILT_FILTER_L_KEY));
955 store = GTK_LIST_STORE(gtk_tree_view_get_model(filter_l));
956 gtk_list_store_append(store, &iter);
957 gtk_list_store_set(store, &iter, 0, nfilt->name, 1, args->nflp, -1);
958 if (GTK_WIDGET(filter_l) == args->active_filter_l) {
959 /* Select the item. */
960 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(filter_l),
966 filter_new_bt_clicked_cb(GtkWidget *w, gpointer data)
968 GtkWidget *main_w = gtk_widget_get_toplevel(w);
969 GtkWidget *name_te = gtk_object_get_data(GTK_OBJECT(main_w),
971 GtkWidget *filter_te = gtk_object_get_data(GTK_OBJECT(main_w),
972 E_FILT_FILTER_TE_KEY);
973 GtkWidget *filter_l = gtk_object_get_data(GTK_OBJECT(main_w),
974 E_FILT_FILTER_L_KEY);
975 filter_list_type_t list = *(filter_list_type_t *)data;
977 const gchar *name, *strval;
978 new_filter_cb_args_t args;
980 name = gtk_entry_get_text(GTK_ENTRY(name_te));
981 strval = gtk_entry_get_text(GTK_ENTRY(filter_te));
983 if (strlen(name) > 0 && strlen(strval) > 0) {
984 /* Add a new entry to the filter list. */
985 fl_entry = add_to_filter_list(list, (char *)name, (char *)strval);
987 /* Update all the filter list widgets, not just the one in
988 the dialog box in which we clicked on "Copy". */
989 args.active_filter_l = filter_l;
990 args.nflp = fl_entry;
991 g_list_foreach(get_filter_dialog_list(list), new_filter_cb, &args);
993 /* Give the user some basic directions on how to use the 'new' button */
994 simple_dialog(ESD_TYPE_WARN, NULL,
995 "You have left either the 'Filter name' or 'Filter string' field empty.\n"
996 "To add a new filter, enter a name for the filter, and enter the expression\n"
997 "for the filter or use the 'Add Expression...' button to construct an\n"
998 "expression, then click 'New'.");
1003 chg_list_item_cb(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter,
1007 filter_def *filt = flp->data;
1010 gtk_tree_model_get(model, iter, 1, &nl_model, -1);
1011 /* Is this the item corresponding to the filter list item in question? */
1012 if (flp == nl_model) {
1013 /* Yes - change the label to correspond to the new name for the
1015 gtk_list_store_set(GTK_LIST_STORE(model), iter, 0, filt->name, -1);
1022 chg_filter_cb(gpointer data, gpointer user_data)
1024 GtkWidget *main_w = data;
1025 GtkWidget *filter_l = gtk_object_get_data(GTK_OBJECT(main_w),
1026 E_FILT_FILTER_L_KEY);
1028 gtk_tree_model_foreach(gtk_tree_view_get_model(GTK_TREE_VIEW(filter_l)),
1029 chg_list_item_cb, user_data);
1033 filter_chg_bt_clicked_cb(GtkWidget *w, gpointer data)
1035 GtkWidget *main_w = gtk_widget_get_toplevel(w);
1036 GtkWidget *name_te = gtk_object_get_data(GTK_OBJECT(main_w),
1037 E_FILT_NAME_TE_KEY);
1038 GtkWidget *filter_te = gtk_object_get_data(GTK_OBJECT(main_w),
1039 E_FILT_FILTER_TE_KEY);
1040 GtkWidget *filter_l = gtk_object_get_data(GTK_OBJECT(main_w),
1041 E_FILT_FILTER_L_KEY);
1043 const gchar *name, *strval;
1045 filter_list_type_t list = *(filter_list_type_t *)data;
1046 GtkTreeSelection *sel;
1047 GtkTreeModel *model;
1050 name = gtk_entry_get_text(GTK_ENTRY(name_te));
1051 strval = gtk_entry_get_text(GTK_ENTRY(filter_te));
1053 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_l));
1055 /* if something was selected */
1056 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
1057 gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
1058 if (fl_entry != NULL) {
1059 filt = (filter_def *) fl_entry->data;
1061 if (strlen(name) > 0 && strlen(strval) > 0 && filt) {
1063 g_free(filt->strval);
1064 filt->name = g_strdup(name);
1065 filt->strval = g_strdup(strval);
1067 /* Update all the filter list widgets, not just the one in
1068 the dialog box in which we clicked on "Copy". */
1069 g_list_foreach(get_filter_dialog_list(list), chg_filter_cb,
1077 filter_chg_bt_destroy_cb(GtkWidget *chg_bt, gpointer data _U_)
1079 GtkWidget *main_w = gtk_widget_get_toplevel(chg_bt);
1081 gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_CHG_BT_KEY, NULL);
1085 filter_copy_bt_clicked_cb(GtkWidget *w, gpointer data)
1087 GtkWidget *main_w = gtk_widget_get_toplevel(w);
1088 GtkWidget *filter_l = gtk_object_get_data(GTK_OBJECT(main_w),
1089 E_FILT_FILTER_L_KEY);
1090 GList *fl_entry, *nfl_entry;
1091 gchar *prefix = "Copy of ", *name;
1093 filter_list_type_t list = *(filter_list_type_t *)data;
1094 new_filter_cb_args_t args;
1095 GtkTreeSelection *sel;
1096 GtkTreeModel *model;
1099 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_l));
1101 /* if something was selected */
1102 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
1103 gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
1104 if (fl_entry != NULL) {
1105 /* Add a new entry, copying the existing entry, to the
1107 filt = (filter_def *) fl_entry->data;
1108 name = g_malloc(strlen(prefix) + strlen(filt->name) + 1);
1109 sprintf(name, "%s%s", prefix, filt->name);
1110 nfl_entry = add_to_filter_list(list, name, filt->strval);
1113 /* Update all the filter list widgets, not just the one in
1114 the dialog box in which we clicked on "Copy". */
1115 args.active_filter_l = filter_l;
1116 args.nflp = nfl_entry;
1117 g_list_foreach(get_filter_dialog_list(list), new_filter_cb, &args);
1123 filter_copy_bt_destroy_cb(GtkWidget *copy_bt, gpointer data _U_)
1125 GtkWidget *main_w = gtk_widget_get_toplevel(copy_bt);
1127 gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_COPY_BT_KEY, NULL);
1131 delete_filter_cb(gpointer data, gpointer user_data)
1133 GtkWidget *main_w = data;
1134 GtkWidget *filter_l = gtk_object_get_data(GTK_OBJECT(main_w),
1135 E_FILT_FILTER_L_KEY);
1136 gchar *pos = (gchar *)user_data;
1137 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(filter_l));
1140 gtk_tree_model_get_iter_from_string(model, &iter, pos);
1141 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
1145 filter_del_bt_clicked_cb(GtkWidget *w, gpointer data)
1147 GtkWidget *main_w = gtk_widget_get_toplevel(w);
1148 GtkWidget *filter_l = gtk_object_get_data(GTK_OBJECT(main_w),
1149 E_FILT_FILTER_L_KEY);
1150 filter_list_type_t list = *(filter_list_type_t *)data;
1153 GtkTreeSelection *sel;
1154 GtkTreeModel *model;
1158 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_l));
1159 /* If something was selected */
1160 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
1161 gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
1162 path = gtk_tree_model_get_path(model, &iter);
1163 pos = gtk_tree_path_to_string(path);
1164 gtk_tree_path_free(path);
1165 if (fl_entry != NULL) {
1166 /* Remove the entry from the filter list. */
1167 remove_from_filter_list(list, fl_entry);
1169 /* Update all the filter list widgets, not just the one in
1170 the dialog box in which we clicked on "Delete". */
1171 g_list_foreach(get_filter_dialog_list(list), delete_filter_cb, pos);
1178 filter_del_bt_destroy_cb(GtkWidget *del_bt, gpointer data _U_)
1180 GtkWidget *main_w = gtk_widget_get_toplevel(del_bt);
1182 gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_DEL_BT_KEY, NULL);
1186 filter_expr_cb(GtkWidget *w _U_, gpointer main_w_arg)
1188 GtkWidget *main_w = GTK_WIDGET(main_w_arg);
1189 GtkWidget *filter_te;
1191 filter_te = gtk_object_get_data(GTK_OBJECT(main_w),
1192 E_FILT_FILTER_TE_KEY);
1193 dfilter_expr_dlg_new(filter_te);
1197 filter_name_te_destroy_cb(GtkWidget *name_te, gpointer data _U_)
1199 GtkWidget *main_w = gtk_widget_get_toplevel(name_te);
1201 gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_NAME_TE_KEY, NULL);
1205 filter_filter_te_destroy_cb(GtkWidget *filter_te, gpointer data _U_)
1207 GtkWidget *main_w = gtk_widget_get_toplevel(filter_te);
1209 gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_FILTER_TE_KEY, NULL);