Add a dialog box for constructing expressions that test a field in the
authorGuy Harris <guy@alum.mit.edu>
Tue, 2 Jan 2001 01:32:21 +0000 (01:32 -0000)
committerGuy Harris <guy@alum.mit.edu>
Tue, 2 Jan 2001 01:32:21 +0000 (01:32 -0000)
display tree, based on Jeff Foster's dialog box for selecting fields.

Make the dialog box for browsing filters into a dialog box for
constructing filters; make the "Apply" button and the "OK" button apply
the filter in the text entry box in the dialog, not the currently
selected filter (selecting a filter puts it in that text entry box, but
the user may edit it afterwards, or may use the aforementioned dialog
box to construct a filter not in the list).

Get rid of extra declarations of "m_r_font" and "m_b_font" in
"proto_draw.c"; they're declared in "gtk/gtkglobals.h", which it includes.

svn path=/trunk/; revision=2805

13 files changed:
AUTHORS
doc/ethereal.pod.template
gtk/Makefile.am
gtk/Makefile.nmake
gtk/capture_dlg.c
gtk/dfilter_expr_dlg.c [new file with mode: 0644]
gtk/dfilter_expr_dlg.h [new file with mode: 0644]
gtk/file_dlg.c
gtk/filter_prefs.c
gtk/filter_prefs.h
gtk/find_dlg.c
gtk/main.c
gtk/proto_draw.c

diff --git a/AUTHORS b/AUTHORS
index 7410f2e0fd3a12ba47ec69498f575e271f1bc2af..2e373c633ce08d3965a344cb60ccd05388f7d8e8 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -158,6 +158,7 @@ Jeff Foster <jfoste@woodward.com> {
        Microsoft Proxy protocol support
        Support for conversations with "wildcard" destination addresses
           and/or ports
+       Initial support for constructing filter expressions
 }
 
 Peter Torvals <petertv@xoommail.com> {
index 7b4ea8124a64423a08283a0ed37465cd17a9bd90..f7f55ff9d40a8f9372a3d5be6cdb2e271cdc131e 100644 (file)
@@ -583,17 +583,24 @@ Makes a copy of the currently selected list item.
 
 Deletes the currently selected list item.
 
-=item Apply
+=item Add Expression...
 
-Sets the currently selected list item as the active filter, and applies
-it to the current capture, if any.
-(The currently selected list item must be a display filter, not a
-capture filter.)  If nothing is selected, turns filtering off.
+Pops up a dialog box to allow you to construct a filter expression to
+test a particular field; it offers lists of field names, and, when
+appropriate, lists from which to select tests to perform on the field
+and values with which to compare it.
 
 =item OK
 
-Sets the currently selected list item as the active filter.  If nothing
-is selected, turns filtering off.
+Sets the filter in the I<Filter string> entry as the active filter.  If
+nothing is selected, turns filtering off.
+
+=item Apply
+
+Sets the filter in the I<Filter string> entry as the active filter, and
+applies it to the current capture, if any.  (The currently selected list
+item must be a display filter, not a capture filter.) If nothing is
+selected, turns filtering off.
 
 =item Save
 
index f60afbaec4fcb084bcae3d8e8d2caa6b457aff65..15093d984c8e8d824a2ea62d3ffc0749ae97e4a5 100644 (file)
@@ -1,7 +1,7 @@
 # Makefile.am
 # Automake file for the GTK interface routines for Ethereal
 #
-# $Id: Makefile.am,v 1.31 2000/11/21 23:54:09 guy Exp $
+# $Id: Makefile.am,v 1.32 2001/01/02 01:32:21 guy Exp $
 #
 # Ethereal - Network traffic analyzer
 # By Gerald Combs <gerald@zing.org>
@@ -39,6 +39,8 @@ libui_a_SOURCES = \
        color_utils.h   \
        column_prefs.c  \
        column_prefs.h  \
+       dfilter_expr_dlg.c \
+       dfilter_expr_dlg.h \
        display_opts.c  \
        display_opts.h  \
        dlg_utils.c     \
index fe9c2397a91e0864dd7e1fb835419c91d9c477fe..cd4a646ee0e3b8bfb8c86beb77b8696a24fa618b 100644 (file)
@@ -19,6 +19,7 @@ OBJECTS=capture_dlg.obj \
        colors.obj       \
        color_utils.obj  \
        column_prefs.obj \
+       dfilter_expr_dlg.obj \
        display_opts.obj \
        dlg_utils.obj   \
        file_dlg.obj \
index dc5d55824388f12400dd531852ee3ea9fe0db47d..8ed93d9077599e17a0723bf7e9af2406d843325c 100644 (file)
@@ -1,7 +1,7 @@
 /* capture_dlg.c
  * Routines for packet capture windows
  *
- * $Id: capture_dlg.c,v 1.35 2000/10/19 22:59:24 guy Exp $
+ * $Id: capture_dlg.c,v 1.36 2001/01/02 01:32:21 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -198,7 +198,7 @@ capture_prep_cb(GtkWidget *w, gpointer d)
   
   filter_bt = gtk_button_new_with_label("Filter:");
   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
-    GTK_SIGNAL_FUNC(filter_browse_cb), NULL);
+    GTK_SIGNAL_FUNC(capture_filter_construct_cb), NULL);
   gtk_table_attach_defaults(GTK_TABLE(table), filter_bt, 0, 1, 2, 3);
   gtk_widget_show(filter_bt);
   
diff --git a/gtk/dfilter_expr_dlg.c b/gtk/dfilter_expr_dlg.c
new file mode 100644 (file)
index 0000000..7d029ea
--- /dev/null
@@ -0,0 +1,1221 @@
+/* dfilter_expr_dlg.c
+ *
+ * Allow the user to construct a subexpression of a display filter
+ * expression, testing a particular field; display the tree of fields
+ * and the relations and values with which it can be compared.
+ *
+ * Copyright 2000, Jeffrey C. Foster<jfoste@woodward.com> and
+ * Guy Harris <guy@alum.mit.edu>
+ *
+ * $Id: dfilter_expr_dlg.c,v 1.1 2001/01/02 01:32:21 guy Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@zing.org>
+ * Copyright 2000 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+/* Todo - 
+ * may want to check the enable field to decide if protocol should be in tree
+ * improve speed of dialog box creation
+ *     - I believe this is slow because of tree widget creation.
+ *             1) could improve the widget 
+ *             2) keep a copy in memory after the first time.
+ * user can pop multiple tree dialogs by pressing the "Tree" button multiple
+ *     time.  not a good thing.
+ * Sort the protocols and children
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gtk/gtk.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "prefs.h"
+#include "globals.h"
+#include "gtkglobals.h"
+#include "main.h"
+#include "util.h"
+#include "ui_util.h"
+#include "simple_dialog.h"
+#include "dlg_utils.h"
+#include "proto_dlg.h"
+#include "filter_prefs.h"
+#include "dfilter_expr_dlg.h"
+
+#define E_DFILTER_EXPR_TREE_KEY                        "dfilter_expr_tree"
+#define E_DFILTER_EXPR_CURRENT_VAR_KEY         "dfilter_expr_current_var"
+#define E_DFILTER_EXPR_RELATION_LABEL_KEY      "dfilter_expr_relation_label"
+#define E_DFILTER_EXPR_RELATION_LIST_KEY       "dfilter_expr_relation_list"
+#define E_DFILTER_EXPR_RANGE_LABEL_KEY         "dfilter_expr_range_label"
+#define E_DFILTER_EXPR_RANGE_ENTRY_KEY         "dfilter_expr_range_entry"
+#define E_DFILTER_EXPR_VALUE_LABEL_KEY         "dfilter_expr_value_label"
+#define E_DFILTER_EXPR_VALUE_ENTRY_KEY         "dfilter_expr_value_entry"
+#define E_DFILTER_EXPR_VALUE_LIST_KEY          "dfilter_expr_value_list"
+#define E_DFILTER_EXPR_VALUE_LIST_SW_KEY       "dfilter_expr_value_list_sw"
+#define E_DFILTER_EXPR_ACCEPT_BT_KEY           "dfilter_expr_accept_bt"
+#define E_DFILTER_EXPR_VALUE_KEY               "dfilter_expr_value"
+
+typedef struct protocol_data {
+  char         *abbrev;
+  int          hfinfo_index;
+} protocol_data_t;
+
+static void show_relations(GtkWidget *relation_label, GtkWidget *relation_list,
+    GtkWidget *range_label, GtkWidget *range_entry, guint32 relations);
+static void add_relation_list(GtkWidget *relation_list, char *relation);
+static void build_boolean_values(GtkWidget *value_list_scrolled_win,
+    GtkWidget *value_list, const true_false_string *values);
+static void build_enum_values(GtkWidget *value_list_scrolled_win,
+    GtkWidget *value_list, const value_string *values);
+static void add_value_list_item(GtkWidget *value_list, gchar *string,
+    gpointer data);
+static void display_value_fields(header_field_info *hfinfo,
+    gboolean is_comparison, GtkWidget *value_label, GtkWidget *value_entry,
+    GtkWidget *value_list, GtkWidget *value_list_scrolled_win);
+
+/*
+ * What relations are supported?
+ */
+#define EXISTENCE_OK           0x00000001
+#define EQUALITY_OK            0x00000002
+#define ORDER_OK               0x00000004
+#define ORDER_EQUALITY_OK      0x00000008
+#define RANGES_OK              0x00000010
+
+/*
+ * Note that this is called every time the user clicks on an item,
+ * whether it is already selected or not.
+ */
+static void
+field_select_row_cb(GtkWidget *tree, GList *node, gint column,
+    gpointer user_data)
+{
+       GtkWidget *window = gtk_widget_get_toplevel(tree);
+       GtkWidget *relation_label = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_RELATION_LABEL_KEY);
+       GtkWidget *relation_list = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_RELATION_LIST_KEY);
+       GtkWidget *range_label = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_RANGE_LABEL_KEY);
+       GtkWidget *range_entry = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_RANGE_ENTRY_KEY);
+       GtkWidget *value_label = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_VALUE_LABEL_KEY);
+       GtkWidget *value_entry = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_VALUE_ENTRY_KEY);
+       GtkWidget *value_list = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_VALUE_LIST_KEY);
+       GtkWidget *value_list_scrolled_win = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_VALUE_LIST_SW_KEY);
+       GtkWidget *accept_bt = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_ACCEPT_BT_KEY);
+       header_field_info *hfinfo, *cur_hfinfo;
+       guint32 relations;
+       char *value_type;
+       char value_label_string[1024+1];        /* XXX - should be large enough */
+
+       hfinfo = gtk_ctree_node_get_row_data(GTK_CTREE(tree),
+           GTK_CTREE_NODE(node));
+
+       /*
+        * What was the item that was last selected?
+        */
+       cur_hfinfo = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_CURRENT_VAR_KEY);
+       if (cur_hfinfo == hfinfo) {
+               /*
+                * It's still selected; no need to change anything.
+                */
+               return;
+       }
+
+       /*
+        * Mark it as currently selected.
+        */
+       gtk_object_set_data(GTK_OBJECT(window), E_DFILTER_EXPR_CURRENT_VAR_KEY,
+           hfinfo);
+
+       /*
+        * Set the relation list column to show all the comparison
+        * operators supported on it, if any.
+        */
+       switch (hfinfo->type) {
+
+       case FT_NONE:
+               /*
+                * You can only test for the field's presence;
+                * hide the relation stuff.
+                * XXX - what about "tcp[xx:yy]"?
+                */
+               relations = 0;
+               break;
+
+       case FT_BOOLEAN:
+               /*
+                * You can only test whether the field is true or false;
+                * hide the relation stuff.
+                */
+               relations = 0;
+               break;
+
+       case FT_UINT8:
+       case FT_UINT16:
+       case FT_UINT24:
+       case FT_UINT32:
+       case FT_INT8:
+       case FT_INT16:
+       case FT_INT24:
+       case FT_INT32:
+       case FT_IPv4:
+               /*
+                * All comparison operators are allowed, but you can't
+                * select a subrange of bytes in it.
+                */
+               relations = EXISTENCE_OK|EQUALITY_OK|ORDER_OK|ORDER_EQUALITY_OK;
+               break;
+
+       case FT_STRING:
+       case FT_STRINGZ:
+       case FT_UINT_STRING:
+       case FT_ETHER:
+       case FT_IPv6:
+       case FT_IPXNET:
+               /*
+                * Only equality comparisons are allowed, and you can't
+                * select a subrange of bytes.
+                */
+               relations = EXISTENCE_OK|EQUALITY_OK;
+               break;
+
+       case FT_DOUBLE:
+       case FT_ABSOLUTE_TIME:
+       case FT_RELATIVE_TIME:
+               /*
+                * We don't support filtering on these.
+                */
+               relations = 0;
+               break;
+
+       case FT_BYTES:
+               /*
+                * Equality and "greater than" and "less than", but *not*
+                * "greater than or equal to" or "less than or equal to",
+                * are supported.  XXX - is that an error?
+                * Ranges are supported.
+                */
+               relations = EXISTENCE_OK|EQUALITY_OK|ORDER_OK|RANGES_OK;
+               break;
+
+       default:
+               g_assert_not_reached();
+               relations = 0;
+               break;
+       }
+       show_relations(relation_label, relation_list, range_label,
+           range_entry, relations);
+
+       /*
+        * Set the label for the value to indicate what type of value
+        * it is.
+        */
+       switch (hfinfo->type) {
+
+       case FT_NONE:
+               /*
+                * You can only test for the field's presence; hide
+                * the value stuff.
+                */
+               value_type = NULL;
+               break;
+
+       case FT_BOOLEAN:
+               value_type = "Boolean";
+               break;
+
+       case FT_UINT8:
+               value_type = "unsigned, byte";
+               break;
+
+       case FT_UINT16:
+               value_type = "unsigned, 2 bytes";
+               break;
+
+       case FT_UINT24:
+               value_type = "unsigned, 3 bytes";
+               break;
+
+       case FT_UINT32:
+               value_type = "unsigned, 4 bytes";
+               break;
+
+       case FT_INT8:
+               value_type = "signed, byte";
+               break;
+
+       case FT_INT16:
+               value_type = "signed, 2 bytes";
+               break;
+
+       case FT_INT24:
+               value_type = "signed, 3 bytes";
+               break;
+
+       case FT_INT32:
+               value_type = "signed, 4 bytes";
+               break;
+
+       case FT_DOUBLE:
+               value_type = "floating point";
+               break;
+
+       case FT_ABSOLUTE_TIME:
+               value_type = "date and time";
+               break;
+
+       case FT_RELATIVE_TIME:
+               value_type = "time";
+               break;
+
+       case FT_STRING:
+       case FT_STRINGZ:
+       case FT_UINT_STRING:
+               value_type = "character string";
+               break;
+
+       case FT_ETHER:
+               value_type = "Ethernet or other MAC address";
+               break;
+
+       case FT_BYTES:
+               value_type = "sequence of bytes";
+               break;
+
+       case FT_IPv4:
+               value_type = "IPv4 address";
+               break;
+
+       case FT_IPv6:
+               value_type = "IPv6 address";
+               break;
+
+       case FT_IPXNET:
+               value_type = "IPX network address";
+               break;
+
+       default:
+               g_assert_not_reached();
+               value_type = NULL;
+               break;
+       }
+       if (value_type != NULL) {
+               /*
+                * Indicate what type of value it is.
+                */
+               snprintf(value_label_string, sizeof value_label_string,
+                   "Value (%s)", value_type);
+               gtk_label_set_text(GTK_LABEL(value_label), value_label_string);
+       }
+
+       /*
+        * Clear the entry widget for the value, as whatever
+        * was there before doesn't apply.
+        */
+       gtk_entry_set_text(GTK_ENTRY(value_entry), "");
+
+       switch (hfinfo->type) {
+
+       case FT_BOOLEAN:
+               /*
+                * The list of values should be the strings for "true"
+                * and "false"; show them in the value list.
+                */
+               build_boolean_values(value_list_scrolled_win, value_list,
+                   hfinfo->strings);
+               break;
+
+       case FT_UINT8:
+       case FT_UINT16:
+       case FT_UINT24:
+       case FT_UINT32:
+       case FT_INT8:
+       case FT_INT16:
+       case FT_INT24:
+       case FT_INT32:
+               /*
+                * If this has a value_string table associated with it,
+                * fill up the list of values, otherwise clear the list
+                * of values.
+                */
+               if (hfinfo->strings != NULL) {
+                       build_enum_values(value_list_scrolled_win, value_list,
+                           hfinfo->strings);
+               } else
+                       gtk_list_clear_items(GTK_LIST(value_list), 0, -1);
+               break;
+
+       default:
+               /*
+                * Clear the list of values.
+                */
+               gtk_list_clear_items(GTK_LIST(value_list), 0, -1);
+               break;
+       }
+
+       /*
+        * Display various items for the value, as appropriate.
+        * The relation we start out with is never a comparison.
+        */
+       display_value_fields(hfinfo, FALSE, value_label, value_entry,
+           value_list, value_list_scrolled_win);
+
+       /*
+        * XXX - in browse mode, there always has to be something
+        * selected, so this should always be sensitive.
+        */
+       gtk_widget_set_sensitive(accept_bt, TRUE);
+}
+
+static void
+show_relations(GtkWidget *relation_label, GtkWidget *relation_list,
+    GtkWidget *range_label, GtkWidget *range_entry, guint32 relations)
+{
+       /*
+        * Clear out the currently displayed list of relations.
+        */
+       gtk_list_clear_items(GTK_LIST(relation_list), 0, -1);
+       if (relations == 0) {
+               /*
+                * No relational operators are supported; hide the relation
+                * and range stuff.
+                */
+               gtk_widget_hide(relation_label);
+               gtk_widget_hide(relation_list);
+               gtk_widget_hide(range_label);
+               gtk_widget_hide(range_entry);
+       } else {
+               /*
+                * Add the supported relations.
+                */
+               if (relations & EXISTENCE_OK)
+                       add_relation_list(relation_list, "is present");
+               if (relations & EQUALITY_OK) {
+                       add_relation_list(relation_list, "==");
+                       add_relation_list(relation_list, "!=");
+               }
+               if (relations & ORDER_OK) {
+                       add_relation_list(relation_list, ">");
+                       add_relation_list(relation_list, "<");
+               }
+               if (relations & ORDER_EQUALITY_OK) {
+                       add_relation_list(relation_list, ">=");
+                       add_relation_list(relation_list, "<=");
+               }
+
+               /*
+                * And show the list.
+                */
+               gtk_widget_show(relation_label);
+               gtk_widget_show(relation_list);
+
+               /*
+                * Are range supported?  If so, show the range stuff,
+                * otherwise hide it.
+                */
+               if (relations & RANGES_OK) {
+                       gtk_widget_show(range_label);
+                       gtk_widget_show(range_entry);
+               } else {
+                       gtk_widget_hide(range_label);
+                       gtk_widget_hide(range_entry);
+               }
+
+       }
+}
+
+static void
+add_relation_list(GtkWidget *relation_list, char *relation)
+{
+       GtkWidget *label, *item;
+
+       label = gtk_label_new(relation);
+       item = gtk_list_item_new();
+
+       gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+       gtk_container_add(GTK_CONTAINER(item), label);
+       gtk_widget_show(label);
+       gtk_container_add(GTK_CONTAINER(relation_list), item);
+       gtk_widget_show(item);
+}
+
+static void
+relation_list_sel_cb(GtkList *relation_list, GtkWidget *child,
+    gpointer user_data)
+{
+       GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(relation_list));
+       GtkWidget *value_label = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_VALUE_LABEL_KEY);
+       GtkWidget *value_entry = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_VALUE_ENTRY_KEY);
+       GtkWidget *value_list = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_VALUE_LIST_KEY);
+       GtkWidget *value_list_scrolled_win = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_VALUE_LIST_SW_KEY);
+       header_field_info *hfinfo = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_CURRENT_VAR_KEY);
+       GList *sl;
+       GtkWidget *item, *item_label;
+       gchar *item_str;
+
+       /*
+        * What's the relation?
+        */
+       sl = GTK_LIST(relation_list)->selection;
+       item = GTK_WIDGET(sl->data);
+       item_label = GTK_BIN(item)->child;
+       gtk_label_get(GTK_LABEL(item_label), &item_str);
+
+       /*
+        * Update the display of various items for the value, as appropriate.
+        */
+       display_value_fields(hfinfo,
+           (strcmp(item_str, "is present") != 0),
+           value_label, value_entry, value_list, value_list_scrolled_win);
+}
+
+static void
+build_boolean_values(GtkWidget *value_list_scrolled_win, GtkWidget *value_list,
+    const true_false_string *values)
+{
+       static const true_false_string true_false = { "True", "False" };
+
+       /*
+        * Clear out the items for the list, and put in the names
+        * from the value_string list.
+        */
+       gtk_list_clear_items(GTK_LIST(value_list), 0, -1);
+
+       /*
+        * Put the list in single mode, so we don't get any selection
+        * events while we're building it (i.e., so we don't get any
+        * on a list item BEFORE WE GET TO SET THE DATA FOR THE LIST
+        * ITEM SO THAT THE HANDLER CAN HANDLE IT).
+        */
+       gtk_list_set_selection_mode(GTK_LIST(value_list), GTK_SELECTION_SINGLE);
+
+       /*
+        * Build the list.
+        */
+       if (values == NULL)
+               values = &true_false;
+       add_value_list_item(value_list, values->true_string, (gpointer)values);
+       add_value_list_item(value_list, values->false_string, NULL);
+
+       /*
+        * OK, we're done, so we can finally put it in browse mode.
+        * Select the first item, so that the user doesn't have to, under
+        * the assumption that they're most likely to test if something
+        * is true, not false.
+        */
+       gtk_list_set_selection_mode(GTK_LIST(value_list), GTK_SELECTION_BROWSE);
+       gtk_list_select_item(GTK_LIST(value_list), 0);
+
+       gtk_widget_show_all(value_list_scrolled_win);
+}
+
+static void
+build_enum_values(GtkWidget *value_list_scrolled_win, GtkWidget *value_list,
+    const value_string *values)
+{
+       /*
+        * Clear out the items for the list, and put in the names
+        * from the value_string list.
+        */
+       gtk_list_clear_items(GTK_LIST(value_list), 0, -1);
+
+       /*
+        * Put the list in single mode, so we don't get any selection
+        * events while we're building it (i.e., so we don't get any
+        * on a list item BEFORE WE GET TO SET THE DATA FOR THE LIST
+        * ITEM SO THAT THE HANDLER CAN HANDLE IT).
+        */
+       gtk_list_set_selection_mode(GTK_LIST(value_list), GTK_SELECTION_SINGLE);
+
+       /*
+        * Build the list.
+        */
+       while (values->strptr != NULL) {
+               add_value_list_item(value_list, values->strptr,
+                   (gpointer)values);
+               values++;
+       }
+
+       /*
+        * OK, we're done, so we can finally put it in browse mode.
+        */
+       gtk_list_set_selection_mode(GTK_LIST(value_list), GTK_SELECTION_BROWSE);
+}
+
+static void
+add_value_list_item(GtkWidget *value_list, gchar *string, gpointer data)
+{
+       GtkWidget *label, *item;
+
+       label = gtk_label_new(string);
+       item = gtk_list_item_new();
+
+       gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+       gtk_container_add(GTK_CONTAINER(item), label);
+       gtk_widget_show(label);
+       gtk_container_add(GTK_CONTAINER(value_list), item);
+       gtk_object_set_data(GTK_OBJECT(item), E_DFILTER_EXPR_VALUE_KEY, data);
+       gtk_widget_show(item);
+}
+
+/*
+ * Show or hide the various values fields as appropriate for the field
+ * and currently-selected relation.
+ */
+static void
+display_value_fields(header_field_info *hfinfo, gboolean is_comparison,
+    GtkWidget *value_label, GtkWidget *value_entry, GtkWidget *value_list,
+    GtkWidget *value_list_scrolled_win)
+{
+       gboolean show_value_label = FALSE;
+
+       /*
+        * Either:
+        *
+        *      this is an FT_NONE variable, in which case you can
+        *      only check whether it's present or absent in the
+        *      protocol tree
+        *
+        * or
+        *
+        *      this is a Boolean variable, in which case you
+        *      can't specify a value to compare with, you can
+        *      only specify whether to test for the Boolean
+        *      being true or to test for it being false
+        *
+        * or
+        *
+        *      this isn't a Boolean variable, in which case you
+        *      can test for its presence in the protocol tree,
+        *      and the default relation is such a test, in
+        *      which case you don't compare with a value
+        *
+        * so we hide the value entry.
+        */
+       if (is_comparison) {
+               /*
+                * The relation is a comparison; display the entry for
+                * the value with which to compare.
+                */
+               gtk_widget_show(value_entry);
+
+               /*
+                * We're showing the entry; show the label as well.
+                */
+               show_value_label = TRUE;
+       } else {
+               /*
+                * The relation isn't a comparison; there's no value with
+                * which to compare, so don't show the entry for it.
+                */
+               gtk_widget_hide(value_entry);
+       }
+
+       switch (hfinfo->type) {
+
+       case FT_BOOLEAN:
+               /*
+                * The list of values should be the strings for "true"
+                * and "false"; show the value list.
+                */
+               gtk_widget_show_all(value_list_scrolled_win);
+
+               /*
+                * We're showing the entry; show the label as well.
+                */
+               show_value_label = TRUE;
+               break;
+
+       case FT_UINT8:
+       case FT_UINT16:
+       case FT_UINT24:
+       case FT_UINT32:
+       case FT_INT8:
+       case FT_INT16:
+       case FT_INT24:
+       case FT_INT32:
+               if (hfinfo->strings != NULL) {
+                       /*
+                        * We have a list of values to show.
+                        */
+                       if (is_comparison) {
+                               /*
+                                * The relation is a comparison, so we're
+                                * showing an entry for the value with
+                                * which to compare; show the list of
+                                * names for values as well.
+                                */
+                               gtk_widget_show_all(value_list_scrolled_win);
+
+                               /*
+                                * We're showing the entry; show the label
+                                * as well.
+                                */
+                               show_value_label = TRUE;
+                       } else {
+                               /*
+                                * It's not a comparison, so we're not showing
+                                * the entry for the value; don't show the
+                                * list of names for values, either.
+                                */
+                               gtk_widget_hide_all(value_list_scrolled_win);
+                       }
+               } else {
+                       /*
+                        * There is no list of names for values, so don't
+                        * show it.
+                        */
+                       gtk_widget_hide_all(value_list_scrolled_win);
+               }
+               break;
+
+       default:
+               /*
+                * There is no list of names for values; hide the list.
+                */
+               gtk_widget_hide_all(value_list_scrolled_win);
+               break;
+       }
+
+       if (show_value_label)
+               gtk_widget_show(value_label);
+       else
+               gtk_widget_hide(value_label);
+}
+
+static void
+value_list_sel_cb(GtkList *value_list, GtkWidget *child,
+    gpointer value_entry_arg)
+{
+       GtkWidget *value_entry = value_entry_arg;
+       GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(value_list));
+       header_field_info *hfinfo = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_CURRENT_VAR_KEY);
+       const value_string *value;
+       char value_string[11+1];        /* long enough for 32-bit octal value */
+
+       /*
+        * If the value entry is shown, it's an enumerated type (i.e.,
+        * we have a "value_string" list associated with the field);
+        * set the value entry to the numerical value for this item.
+        *
+        * If it's not shown, it's a Boolean type, and there is no value
+        * to use in a test of the field.
+        */
+       if (GTK_WIDGET_VISIBLE(value_entry)) {
+               value = gtk_object_get_data(GTK_OBJECT(child),
+                   E_DFILTER_EXPR_VALUE_KEY);
+               switch (hfinfo->display) {
+
+               case BASE_DEC:
+                       switch (hfinfo->type) {
+
+                       case FT_UINT8:
+                       case FT_UINT16:
+                       case FT_UINT32:
+                               snprintf(value_string, sizeof value_string,
+                                   "%u", value->value);
+                               break;
+
+                       case FT_INT8:
+                       case FT_INT16:
+                       case FT_INT32:
+                               snprintf(value_string, sizeof value_string,
+                                   "%d", value->value);
+                               break;
+
+                       default:
+                               g_assert_not_reached();
+                       }
+                       break;
+
+               case BASE_HEX:
+                       snprintf(value_string, sizeof value_string, "0x%x",
+                           value->value);
+                       break;
+
+               case BASE_OCT:
+                       snprintf(value_string, sizeof value_string, "%#o",
+                           value->value);
+                       break;
+
+               default:
+                       g_assert_not_reached();
+               }
+               gtk_entry_set_text(GTK_ENTRY(value_entry), value_string);
+       }
+}
+
+static void
+dfilter_expr_dlg_accept_cb(GtkWidget *w, gpointer filter_te_arg)
+{
+       GtkWidget *filter_te = filter_te_arg;
+       GtkWidget *window = gtk_widget_get_toplevel(w);
+       GtkWidget *relation_list = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_RELATION_LIST_KEY);
+       GtkWidget *range_entry = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_RANGE_ENTRY_KEY);
+       GtkWidget *value_entry = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_VALUE_ENTRY_KEY);
+       GtkWidget *value_list = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_VALUE_LIST_KEY);
+       header_field_info *hfinfo;
+       GList *sl;
+       GtkWidget *item, *item_label;
+       gchar *item_str;
+       gchar *range_str, *stripped_range_str;
+       gchar *value_str, *stripped_value_str;
+       int pos;
+       gchar *chars;
+
+       /*
+        * Get the variable to be tested.
+        */
+       hfinfo = gtk_object_get_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_CURRENT_VAR_KEY);
+
+       /*
+        * Get the relation to use, if any.
+        */
+       if (GTK_WIDGET_VISIBLE(relation_list)) {
+               /*
+                * The list of relations is visible, so we can get a
+                * relation operator from it.
+                */
+               sl = GTK_LIST(relation_list)->selection;
+               item = GTK_WIDGET(sl->data);
+               item_label = GTK_BIN(item)->child;
+               gtk_label_get(GTK_LABEL(item_label), &item_str);
+       } else
+               item_str = NULL;        /* no relation operator */
+
+       /*
+        * Get the range to use, if any.
+        */
+       if (GTK_WIDGET_VISIBLE(range_entry)) {
+               range_str = g_strdup(gtk_entry_get_text(GTK_ENTRY(range_entry)));
+               stripped_range_str = g_strstrip(range_str);
+               if (strcmp(stripped_range_str, "") == 0) {
+                       /*
+                        * No range was specified.
+                        */
+                       g_free(range_str);
+                       range_str = NULL;
+                       stripped_range_str = NULL;
+               }
+
+               /*
+                * XXX - check it for validity?
+                */
+       } else {
+               range_str = NULL;
+               stripped_range_str = NULL;
+       }
+
+       /*
+        * Get the value to use, if any.
+        */
+       if (GTK_WIDGET_VISIBLE(value_entry)) {
+               value_str = g_strdup(gtk_entry_get_text(GTK_ENTRY(value_entry)));
+               stripped_value_str = g_strstrip(value_str);
+               if (strcmp(stripped_value_str, "") == 0) {
+                       /*
+                        * This field takes a value, but they didn't supply
+                        * one.
+                        */
+                       simple_dialog(ESD_TYPE_CRIT | ESD_TYPE_MODAL, NULL,
+                           "That field must be compared with a value, "
+                           "but you didn't specify a value with which to "
+                           "compare it.");
+                       g_free(value_str);
+                       return;
+               }
+       } else {
+               value_str = NULL;
+               stripped_value_str = NULL;
+       }
+       
+       /*
+        * Insert the expression at the current cursor position.
+        * If there's a non-whitespace character to the left of it,
+        * insert a blank first; if there's a non-whitespace character
+        * to the right of it, insert a blank after it.
+        */
+       pos = gtk_editable_get_position(GTK_EDITABLE(filter_te));
+       chars = gtk_editable_get_chars(GTK_EDITABLE(filter_te), pos, pos + 1);
+       if (strcmp(chars, "") != 0 && !isspace((unsigned char)chars[0]))
+               gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
+       g_free(chars);
+
+       /*
+        * If this is a Boolean, check if item in the value list has
+        * a null pointer as the data attached to it; if so, put a "!"
+        * in front of the variable name, as we're testing whether it's
+        * false.
+        */
+       if (hfinfo->type == FT_BOOLEAN) {
+               sl = GTK_LIST(value_list)->selection;
+               item = GTK_WIDGET(sl->data);
+               if (gtk_object_get_data(GTK_OBJECT(item),
+                   E_DFILTER_EXPR_VALUE_KEY) == NULL)
+                       gtk_editable_insert_text(GTK_EDITABLE(filter_te), "!",
+                           1, &pos);
+       }
+
+       gtk_editable_insert_text(GTK_EDITABLE(filter_te), hfinfo->abbrev,
+           strlen(hfinfo->abbrev), &pos);
+       if (range_str != NULL) {
+               gtk_editable_insert_text(GTK_EDITABLE(filter_te), "[", 1, &pos);
+               gtk_editable_insert_text(GTK_EDITABLE(filter_te),
+                   stripped_range_str, strlen(stripped_range_str), &pos);
+               gtk_editable_insert_text(GTK_EDITABLE(filter_te), "]", 1, &pos);
+               g_free(range_str);
+       }
+       if (item_str != NULL && strcmp(item_str, "is present") != 0) {
+               gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
+               gtk_editable_insert_text(GTK_EDITABLE(filter_te), item_str,
+                   strlen(item_str), &pos);
+       }
+       if (value_str != NULL) {
+               gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
+               switch (hfinfo->type) {
+
+               case FT_STRING:
+               case FT_STRINGZ:
+               case FT_UINT_STRING:
+                       /*
+                        * Put quotes around the string.
+                        */
+                       gtk_editable_insert_text(GTK_EDITABLE(filter_te), "\"",
+                           1, &pos);
+
+               default:
+                       break;
+               }
+               gtk_editable_insert_text(GTK_EDITABLE(filter_te),
+                   stripped_value_str, strlen(stripped_value_str), &pos);
+               switch (hfinfo->type) {
+
+               case FT_STRING:
+               case FT_STRINGZ:
+               case FT_UINT_STRING:
+                       /*
+                        * Put quotes around the string.
+                        */
+                       gtk_editable_insert_text(GTK_EDITABLE(filter_te), "\"",
+                           1, &pos);
+
+               default:
+                       break;
+               }
+               g_free(value_str);
+       }
+       chars = gtk_editable_get_chars(GTK_EDITABLE(filter_te), pos + 1, pos + 2);
+       if (strcmp(chars, "") != 0 && !isspace((unsigned char)chars[0]))
+               gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
+       g_free(chars);
+
+       /*
+        * Put the cursor after the expression we just entered into
+        * the text entry widget.
+        */
+       gtk_editable_set_position(GTK_EDITABLE(filter_te), pos);
+
+       /*
+        * We're done; destroy the dialog box (which is the top-level
+        * widget for the "Accept" button).
+        */
+       gtk_widget_destroy(window);
+}
+
+static void
+dfilter_expr_dlg_cancel_cb(GtkWidget *w, gpointer parent_w)
+{
+       /*
+        * User pressed the cancel button; close the dialog box.
+        */
+       gtk_widget_destroy(GTK_WIDGET(parent_w));
+}
+
+void
+dfilter_expr_dlg_new(GtkWidget *filter_te)
+{
+       GtkWidget *window;
+       GtkWidget *main_vb;
+       GtkWidget *hb;
+       GtkWidget *col1_vb;
+       GtkWidget *tree_label, *tree, *tree_scrolled_win;
+       GtkWidget *col2_vb;
+       GtkWidget *relation_label, *relation_list;
+       GtkWidget *range_label, *range_entry;
+       GtkWidget *value_vb;
+       GtkWidget *value_label, *value_entry, *value_list_scrolled_win, *value_list;
+       GtkWidget *list_bb, *accept_bt, *close_bt;
+       GtkCTreeNode *protocol_node, *item_node;
+       header_field_info       *hfinfo;
+       int     i, len;
+       GHashTable *proto_array;
+
+       window = dlg_window_new("Ethereal: Filter Expression");
+       gtk_container_set_border_width(GTK_CONTAINER(window), 5);
+
+       main_vb = gtk_vbox_new(FALSE, 5);
+       gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
+       gtk_container_add(GTK_CONTAINER(window), main_vb);
+       gtk_widget_show(main_vb);
+
+       hb = gtk_hbox_new(FALSE, 5);
+       gtk_container_border_width(GTK_CONTAINER(hb), 5);
+       gtk_container_add(GTK_CONTAINER(main_vb), hb);
+       gtk_widget_show(hb);
+
+       col1_vb = gtk_vbox_new(FALSE, 5);
+       gtk_container_border_width(GTK_CONTAINER(col1_vb), 5);
+       gtk_container_add(GTK_CONTAINER(hb), col1_vb);
+       gtk_widget_show(col1_vb);
+
+       tree_label = gtk_label_new("Field name");
+       gtk_misc_set_alignment(GTK_MISC(tree_label), 0.0, 0.0);
+       gtk_box_pack_start(GTK_BOX(col1_vb), tree_label, FALSE, FALSE, 0);
+       gtk_widget_show(tree_label);
+
+       tree_scrolled_win = gtk_scrolled_window_new(NULL, NULL);
+       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tree_scrolled_win),
+                       GTK_POLICY_AUTOMATIC,
+                       GTK_POLICY_AUTOMATIC);
+       gtk_widget_set_usize(tree_scrolled_win, 300, 400);
+       gtk_box_pack_start(GTK_BOX(col1_vb), tree_scrolled_win, FALSE, FALSE, 0);
+       gtk_widget_show(tree_scrolled_win);
+
+       tree = gtk_ctree_new(1, 0);
+       gtk_ctree_set_line_style(GTK_CTREE(tree), GTK_CTREE_LINES_NONE);
+       gtk_signal_connect(GTK_OBJECT(tree), "tree-select-row",
+                            GTK_SIGNAL_FUNC(field_select_row_cb), tree);
+       gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(tree_scrolled_win),
+                                               tree);
+
+       /*
+        * GTK's annoying CTree widget will deliver a selection event
+        * the instant you add an item to the tree, *the fact that you
+        * haven't even had time to set the item's row data nonwithstanding*.
+        *
+        * We'll put the widget into GTK_SELECTION_SINGLE mode in the
+        * hopes that it's *STOP DOING THAT*.
+        */
+       gtk_clist_set_selection_mode(GTK_CLIST(tree),
+                                     GTK_SELECTION_SINGLE);
+
+       col2_vb = gtk_vbox_new(FALSE, 5);
+       gtk_container_border_width(GTK_CONTAINER(col2_vb), 5);
+       gtk_container_add(GTK_CONTAINER(hb), col2_vb);
+       gtk_widget_show(col2_vb);
+
+       relation_label = gtk_label_new("Relation");
+       gtk_misc_set_alignment(GTK_MISC(relation_label), 0.0, 0.0);
+       gtk_box_pack_start(GTK_BOX(col2_vb), relation_label, FALSE, FALSE, 0);
+
+       relation_list = gtk_list_new();
+       gtk_box_pack_start(GTK_BOX(col2_vb), relation_list, TRUE, TRUE, 0);
+       gtk_list_set_selection_mode(GTK_LIST(relation_list),
+           GTK_SELECTION_BROWSE);
+
+       range_label = gtk_label_new("Range (offset:length)");
+       gtk_misc_set_alignment(GTK_MISC(range_label), 0.0, 0.0);
+       gtk_box_pack_start(GTK_BOX(col2_vb), range_label, FALSE, FALSE, 0);
+
+       range_entry = gtk_entry_new();
+       gtk_box_pack_start(GTK_BOX(col2_vb), range_entry, FALSE, FALSE, 0);
+       
+       /*
+        * OK, show the relation label and range stuff as it would be
+        * with everything turned on, so it'll request as much space
+        * as it'll ever need, so the dialog box and widgets start out
+        * with the right sizes.
+        *
+        * XXX - this doesn't work.
+        */
+       show_relations(relation_label, relation_list, range_label, range_entry,
+           EXISTENCE_OK|EQUALITY_OK|ORDER_OK|ORDER_EQUALITY_OK|RANGES_OK);
+
+       value_vb = gtk_vbox_new(FALSE, 5);
+       gtk_container_border_width(GTK_CONTAINER(value_vb), 5);
+       gtk_container_add(GTK_CONTAINER(hb), value_vb);
+       gtk_widget_show(value_vb);
+
+       value_label = gtk_label_new("Value");
+       gtk_misc_set_alignment(GTK_MISC(value_label), 0.0, 0.0);
+       gtk_box_pack_start(GTK_BOX(value_vb), value_label, FALSE, FALSE, 0);
+       gtk_widget_show(value_label);
+
+       value_entry = gtk_entry_new();
+       gtk_box_pack_start(GTK_BOX(value_vb), value_entry, FALSE, FALSE, 0);
+       gtk_widget_show(value_entry);
+       
+       value_list_scrolled_win = gtk_scrolled_window_new(NULL, NULL);
+       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(value_list_scrolled_win),
+                       GTK_POLICY_AUTOMATIC,
+                       GTK_POLICY_AUTOMATIC);
+       gtk_box_pack_start(GTK_BOX(value_vb), value_list_scrolled_win, TRUE,
+           TRUE, 0);
+       gtk_widget_show(value_list_scrolled_win);
+
+       value_list = gtk_list_new();
+       gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(value_list_scrolled_win),
+                                               value_list);
+       gtk_signal_connect(GTK_OBJECT(value_list), "select-child",
+           GTK_SIGNAL_FUNC(value_list_sel_cb), value_entry);
+       gtk_list_set_selection_mode(GTK_LIST(value_list), GTK_SELECTION_SINGLE);
+       /* This remains hidden until an enumerated field is selected */
+
+       /*
+        * The value stuff may be hidden or shown depending on what
+        * relation was selected; connect to the "select-child" signal
+        * for the relation list, so we can make that happen.
+        */
+       gtk_signal_connect(GTK_OBJECT(relation_list), "select-child",
+           GTK_SIGNAL_FUNC(relation_list_sel_cb), NULL);
+
+       list_bb = gtk_hbutton_box_new();
+       gtk_box_pack_start(GTK_BOX(main_vb), list_bb, FALSE, FALSE, 0);
+       gtk_widget_show(list_bb);
+
+       accept_bt = gtk_button_new_with_label("Accept");
+       gtk_widget_set_sensitive(accept_bt, FALSE);
+       gtk_signal_connect(GTK_OBJECT(accept_bt), "clicked",
+           GTK_SIGNAL_FUNC(dfilter_expr_dlg_accept_cb), filter_te);
+       gtk_box_pack_start(GTK_BOX(list_bb), accept_bt, FALSE, FALSE, 0);
+       gtk_widget_show(accept_bt);
+
+       /*
+        * Put the items in the CTree; we don't want to do that until
+        * we've constructed the value list and set the tree's
+        * E_DFILTER_EXPR_VALUE_LIST_KEY data to point to it, and
+        * constructed the "Accept" button and set the tree's
+        * E_DFILTER_EXPR_ACCEPT_BT_KEY data to point to it, so that
+        * when the list item is "helpfully" automatically selected for us
+        * we're ready to cope with the selection signal.
+        */
+
+       /* a hash table seems excessive, but I don't see support for a
+          sparse array in glib */
+       proto_array = g_hash_table_new( g_direct_hash, g_direct_equal);
+       len = proto_registrar_n();
+       for (i = 0; i < len; i++) {
+               if (proto_registrar_is_protocol(i)) {
+                       hfinfo = proto_registrar_get_nth(i);
+                       /* Create a node for the protocol,
+                          and remember it for later use. */
+                       protocol_node = gtk_ctree_insert_node(GTK_CTREE(tree),
+                           NULL, NULL,
+                           &hfinfo->name, 5,
+                           NULL, NULL, NULL, NULL,
+                           FALSE, FALSE);
+                       gtk_ctree_node_set_row_data(GTK_CTREE(tree),
+                           protocol_node, hfinfo);
+                       g_hash_table_insert(proto_array, (gpointer)i,
+                           protocol_node);
+               }
+       }
+
+       len = proto_registrar_n();
+       for (i = 0; i < len; i++) {
+               if (!proto_registrar_is_protocol(i)) {
+                       hfinfo = proto_registrar_get_nth(i);
+
+                       /* Create a node for the item, and put it
+                          under its parent protocol. */
+                       protocol_node = g_hash_table_lookup(proto_array,
+                                       (gpointer)proto_registrar_get_parent(i));
+                       item_node = gtk_ctree_insert_node(GTK_CTREE(tree),
+                           protocol_node, NULL,
+                           &hfinfo->name, 5,
+                           NULL, NULL, NULL, NULL,
+                           FALSE, FALSE);
+                       gtk_ctree_node_set_row_data(GTK_CTREE(tree),
+                           item_node, hfinfo);
+               }
+       }
+
+       g_hash_table_destroy(proto_array);
+
+       gtk_widget_show_all(tree);
+
+       close_bt = gtk_button_new_with_label("Close");
+       gtk_signal_connect(GTK_OBJECT(close_bt), "clicked",
+           GTK_SIGNAL_FUNC(dfilter_expr_dlg_cancel_cb), window);
+       gtk_box_pack_start(GTK_BOX(list_bb), close_bt, FALSE, FALSE, 0);
+       gtk_widget_show(close_bt);
+
+       /*
+        * Catch the "key_press_event" signal in the window, so that we can
+        * catch the ESC key being pressed and act as if the "Close" button
+        * had been selected.
+        */
+       dlg_set_cancel(window, close_bt);
+
+       gtk_object_set_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_RELATION_LABEL_KEY, relation_label);
+       gtk_object_set_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_RELATION_LIST_KEY, relation_list);
+       gtk_object_set_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_RANGE_LABEL_KEY, range_label);
+       gtk_object_set_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_RANGE_ENTRY_KEY, range_entry);
+       gtk_object_set_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_VALUE_LABEL_KEY, value_label);
+       gtk_object_set_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_VALUE_ENTRY_KEY, value_entry);
+       gtk_object_set_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_VALUE_LIST_KEY, value_list);
+       gtk_object_set_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_VALUE_LIST_SW_KEY, value_list_scrolled_win);
+       gtk_object_set_data(GTK_OBJECT(window),
+           E_DFILTER_EXPR_ACCEPT_BT_KEY, accept_bt);
+
+       /*
+        * OK, we've finally built the entire list, complete with the row data,
+        * and attached to the top-level widget pointers to the relevant
+        * subwidgets, so it's safe to put the list in browse mode.
+        */
+       gtk_clist_set_selection_mode (GTK_CLIST(tree),
+                                     GTK_SELECTION_BROWSE);
+
+       gtk_widget_show(window);
+}
diff --git a/gtk/dfilter_expr_dlg.h b/gtk/dfilter_expr_dlg.h
new file mode 100644 (file)
index 0000000..21ea418
--- /dev/null
@@ -0,0 +1,31 @@
+/* dfilter_expr_dlg.h
+ * Definitions for dialog boxes for display filter expression construction
+ *
+ * $Id: dfilter_expr_dlg.h,v 1.1 2001/01/02 01:32:21 guy Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@zing.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef __DFILTER_EXPR_DLG_H__
+#define __DFILTER_EXPR_DLG_H__
+
+void dfilter_expr_dlg_new(GtkWidget *);
+
+#endif /* dfilter_expr_dlg.h */
index a0f86d08b033e208f5d44ab4b9ba06589a95428a..a8553704ca6f05ababbc75a3cce5d3427ee56168 100644 (file)
@@ -1,7 +1,7 @@
 /* file_dlg.c
  * Dialog boxes for handling files
  *
- * $Id: file_dlg.c,v 1.32 2000/10/19 22:59:24 guy Exp $
+ * $Id: file_dlg.c,v 1.33 2001/01/02 01:32:21 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -112,7 +112,7 @@ file_open_cmd_cb(GtkWidget *w, gpointer data) {
 
   filter_bt = gtk_button_new_with_label("Filter:");
   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
-    GTK_SIGNAL_FUNC(filter_browse_cb), NULL);
+    GTK_SIGNAL_FUNC(display_filter_construct_cb), NULL);
   gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
   gtk_widget_show(filter_bt);
   
index 565b6e0bcef3796a4f8606c7f4905c544eab3a6a..726cb6ffef2adedc6a879024f8837ab955cb05e7 100644 (file)
@@ -3,7 +3,7 @@
  * (This used to be a notebook page under "Preferences", hence the
  * "prefs" in the file name.)
  *
- * $Id: filter_prefs.c,v 1.19 2000/10/25 16:06:50 gram Exp $
+ * $Id: filter_prefs.c,v 1.20 2001/01/02 01:32:21 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -55,6 +55,7 @@
 #include "dlg_utils.h"
 #include "ui_util.h"
 #include "prefs_dlg.h"
+#include "dfilter_expr_dlg.h"
 
 #define E_FILT_NAME_KEY "filter_name"
 #define E_FILT_LBL_KEY  "filter_label"
@@ -74,28 +75,28 @@ typedef struct _filter_cb_data {
 } filter_cb_data;
 
 
-static GtkWidget   *filter_l, *chg_bt, *copy_bt, *del_bt, *name_te, *filter_te, *apply_bt;
+static GtkWidget   *filter_l, *chg_bt, *copy_bt, *del_bt, *name_te, *filter_te;
 static GList       *fl = NULL;
 
 static void get_filter_list(void);
 static GtkWidget *filter_dialog_new(GtkWidget *caller, GtkWidget *filter_te,
-    gboolean wants_apply_button);
-static void filter_dlg_ok(GtkWidget *ok_bt, gpointer parent_w);
-static void filter_dlg_save(GtkWidget *save_bt, gpointer parent_w);
-static void filter_dlg_cancel(GtkWidget *cancel_bt, gpointer parent_w);
+    gboolean wants_apply_button, gboolean wants_add_expression_button);
+static void filter_dlg_dclick(GtkWidget *dummy, gpointer main_w_arg);
+static void filter_dlg_ok_cb(GtkWidget *ok_bt, gpointer main_w_arg);
+static void filter_dlg_apply_cb(GtkWidget *apply_bt, gpointer main_w_arg);
+static void filter_dlg_save_cb(GtkWidget *save_bt, gpointer parent_w);
+static void filter_dlg_cancel_cb(GtkWidget *cancel_bt, gpointer parent_w);
 static void filter_dlg_destroy(GtkWidget *win, gpointer data);
-static void filter_sel_apply_cb(GtkWidget *cancel_bt, gpointer parent_w);
 
-static GtkWidget *filter_prefs_show(GtkWidget *, gboolean,
-                                    GtkSignalFunc, GtkObject *);
+static gint       filter_sel_list_button_cb(GtkWidget *, GdkEventButton *,
+                           gpointer);
 static void       filter_sel_list_cb(GtkWidget *, gpointer);
 static void       filter_sel_new_cb(GtkWidget *, gpointer);
 static void       filter_sel_chg_cb(GtkWidget *, gpointer);
 static void       filter_sel_copy_cb(GtkWidget *, gpointer);
 static void       filter_sel_del_cb(GtkWidget *, gpointer);
-static void       filter_prefs_ok(GtkWidget *);
+static void       filter_expr_cb(GtkWidget *, gpointer);
 static void       filter_prefs_save(GtkWidget *);
-static void       filter_prefs_cancel(GtkWidget *);
 static void       filter_prefs_delete(GtkWidget *);
 
 #define        FILTER_LINE_SIZE        2048
@@ -162,20 +163,72 @@ get_filter_list(void)
    arrange that if a change is made to the filter list, other dialog
    boxes get updated appropriately? */
 
-/* Create a filter dialog for browsing; this is to be used as a callback
-   for a button next to a text entry box, which, when clicked, allows
-   you to browse through the list of filters to select one to be put
-   into the text entry box, and, if you select a filter with this
-   dialog box, enters the text of the filter into a text entry box
-   associated with the button.
-
-   If "wants_apply_button" is non-null, hitting <Enter> in the text entry
-   box causes the filter in that box to be applied to something, so
-   the filter dialog should have an "Apply" button that causes the
-   selected filter to be put into the text entry box and the text
-   entry box activated; otherwise, no "Apply" button need apply. */
+/* Create a filter dialog for constructing a capture filter.
+
+   This is to be used as a callback for a button next to a text entry box,
+   which, when clicked, pops up this dialog to allow you to construct a
+   display filter by browsing the list of saved filters (the dialog
+   for constructing expressions assumes display filter syntax, not
+   capture filter syntax).  The "OK" button sets the text entry box to the
+   constructed filter and activates that text entry box (which should have
+   no effect in the main capture dialog); this dialog is then dismissed.
+
+   XXX - we probably want to have separate capture and display filter
+   lists, but we don't yet have that, so the list of filters this
+   shows is a list of all filters. */
+void
+capture_filter_construct_cb(GtkWidget *w, gpointer user_data)
+{
+       GtkWidget *caller = gtk_widget_get_toplevel(w);
+       GtkWidget *filter_browse_w;
+       GtkWidget *filter_te;
+
+       /* Has a filter dialog box already been opened for that top-level
+          widget? */
+       filter_browse_w = gtk_object_get_data(GTK_OBJECT(caller),
+           E_FILT_DIALOG_PTR_KEY);
+
+       if (filter_browse_w != NULL) {
+               /* Yes.  Just re-activate that dialog box. */
+               reactivate_window(filter_browse_w);
+               return;
+       }
+
+       /* No.  Get the text entry attached to the button. */
+       filter_te = gtk_object_get_data(GTK_OBJECT(w), E_FILT_TE_PTR_KEY);
+
+       /* Now create a new dialog, without either an "Apply" or "Add
+          Expression..." button. */
+       filter_browse_w = filter_dialog_new(caller, filter_te, FALSE, FALSE);
+
+       /* Set the E_FILT_CALLER_PTR_KEY for the new dialog to point to
+          our caller. */
+       gtk_object_set_data(GTK_OBJECT(filter_browse_w), E_FILT_CALLER_PTR_KEY,
+           caller);
+
+       /* Set the E_FILT_DIALOG_PTR_KEY for the caller to point to us */
+       gtk_object_set_data(GTK_OBJECT(caller), E_FILT_DIALOG_PTR_KEY,
+           filter_browse_w);
+}
+
+/* Create a filter dialog for constructing a display filter.
+
+   This is to be used as a callback for a button next to a text entry box,
+   which, when clicked, pops up this dialog to allow you to construct a
+   display filter by browsing the list of saved filters and/or by adding
+   test expressions constructed with another dialog.  The "OK" button
+   sets the text entry box to the constructed filter and activates that
+   text entry box, causing the filter to be used; this dialog is then
+   dismissed.
+
+   If "wants_apply_button" is non-null, we add an "Apply" button that
+   acts like "OK" but doesn't dismiss this dialog.
+
+   XXX - we probably want to have separate capture and display filter
+   lists, but we don't yet have that, so the list of filters this
+   shows is a list of all filters. */
 void
-filter_browse_cb(GtkWidget *w, gpointer wants_apply_button)
+display_filter_construct_cb(GtkWidget *w, gpointer wants_apply_button)
 {
        GtkWidget *caller = gtk_widget_get_toplevel(w);
        GtkWidget *filter_browse_w;
@@ -195,9 +248,10 @@ filter_browse_cb(GtkWidget *w, gpointer wants_apply_button)
        /* No.  Get the text entry attached to the button. */
        filter_te = gtk_object_get_data(GTK_OBJECT(w), E_FILT_TE_PTR_KEY);
 
-       /* Now create a new dialog. */
+       /* Now create a new dialog, possibly with an "Apply" button, and
+          definitely with an "Add Expression..." button. */
        filter_browse_w = filter_dialog_new(caller, filter_te,
-           (wants_apply_button != NULL));
+           (wants_apply_button != NULL), TRUE);
 
        /* Set the E_FILT_CALLER_PTR_KEY for the new dialog to point to
           our caller. */
@@ -216,8 +270,6 @@ static GtkWidget *global_filter_w;
 void
 filter_dialog_cb(GtkWidget *w)
 {
-       GtkWidget *filter_te;
-
        /* Has a filter dialog box already been opened for editing? */
        if (global_filter_w != NULL) {
                /* Yes.  Just reactivate it. */
@@ -225,23 +277,41 @@ filter_dialog_cb(GtkWidget *w)
                return;
        }
 
-       /* No.  Create one. */
-       /* But first, get the text entry attached to the button. */
-       filter_te = gtk_object_get_data(GTK_OBJECT(w), E_FILT_TE_PTR_KEY);
-       global_filter_w = filter_dialog_new(NULL, filter_te, TRUE);
+       /*
+        * No.  Create one; we didn't pop this up as a result of pressing
+        * a button next to some text entry field, so don't associate it
+        * with a text entry field.
+        */
+       global_filter_w = filter_dialog_new(NULL, NULL, FALSE, TRUE);
 }
 
 static GtkWidget *
-filter_dialog_new(GtkWidget *caller, GtkWidget *filter_te,
-    gboolean wants_apply_button)
+filter_dialog_new(GtkWidget *caller, GtkWidget *parent_filter_te,
+    gboolean wants_apply_button, gboolean wants_add_expression_button)
 {
-       GtkWidget       *main_w,        /* main window */
-                       *main_vb,       /* main container */
-                       *bbox,          /* button container */
-                       *ok_bt,         /* ok button */
-                       *save_bt,       /* save button */
-                       *cancel_bt;     /* cancel button */ 
-       GtkWidget *filter_pg = NULL;    /* filter settings box */
+       GtkWidget       *main_w,                /* main window */
+                       *main_vb,               /* main container */
+                       *bbox,                  /* button container */
+                       *ok_bt,                 /* "OK" button */
+                       *apply_bt,              /* "Apply" button */
+                       *save_bt,               /* "Save" button */
+                       *cancel_bt;             /* "Cancel" button */ 
+       GtkWidget       *filter_pg = NULL;      /* filter settings box */
+       GtkWidget       *top_hb,
+                       *list_bb,
+                       *new_bt,
+                       *filter_sc,
+                       *nl_item,
+                       *nl_lb,
+                       *middle_hb,
+                       *name_lb,
+                       *bottom_hb,
+                       *filter_lb,
+                       *add_expression_bt;
+       GtkWidget       *l_select = NULL;
+       GList           *flp = NULL;
+       filter_def      *filt;
+       gchar           *filter_te_str = NULL;
 
        main_w = dlg_window_new("Ethereal: Filters");
 
@@ -255,11 +325,142 @@ filter_dialog_new(GtkWidget *caller, GtkWidget *filter_te,
        gtk_container_add(GTK_CONTAINER(main_w), main_vb);
        gtk_widget_show(main_vb);
 
-       filter_pg = filter_prefs_show(filter_te, wants_apply_button,
-                                      GTK_SIGNAL_FUNC(filter_dlg_ok),
-                                      GTK_OBJECT(main_w));
+       /* Make sure everything is set up */  
+       get_filter_list();
+       if (parent_filter_te)
+               filter_te_str = gtk_entry_get_text(GTK_ENTRY(parent_filter_te));
+
+       /* Container for each row of widgets */
+       filter_pg = gtk_vbox_new(FALSE, 5);
+       gtk_container_border_width(GTK_CONTAINER(filter_pg), 5);
+       gtk_widget_show(filter_pg);
+       gtk_object_set_data(GTK_OBJECT(filter_pg), E_FILT_CM_KEY, (gpointer)FALSE);
+
+       /* Top row: Filter list and buttons */
+       top_hb = gtk_hbox_new(FALSE, 5);
+       gtk_container_add(GTK_CONTAINER(filter_pg), top_hb);
+       gtk_widget_show(top_hb);
+
+       list_bb = gtk_vbutton_box_new();
+       gtk_button_box_set_layout (GTK_BUTTON_BOX (list_bb), GTK_BUTTONBOX_START);
+       gtk_container_add(GTK_CONTAINER(top_hb), list_bb);
+       gtk_widget_show(list_bb);
+
+       new_bt = gtk_button_new_with_label ("New");
+       gtk_signal_connect(GTK_OBJECT(new_bt), "clicked",
+           GTK_SIGNAL_FUNC(filter_sel_new_cb), NULL);
+       gtk_container_add(GTK_CONTAINER(list_bb), new_bt);
+       gtk_widget_show(new_bt);
+
+       chg_bt = gtk_button_new_with_label ("Change");
+       gtk_widget_set_sensitive(chg_bt, FALSE);
+       gtk_signal_connect(GTK_OBJECT(chg_bt), "clicked",
+           GTK_SIGNAL_FUNC(filter_sel_chg_cb), NULL);
+       gtk_container_add(GTK_CONTAINER(list_bb), chg_bt);
+       gtk_widget_show(chg_bt);
+
+       copy_bt = gtk_button_new_with_label ("Copy");
+       gtk_widget_set_sensitive(copy_bt, FALSE);
+       gtk_signal_connect(GTK_OBJECT(copy_bt), "clicked",
+           GTK_SIGNAL_FUNC(filter_sel_copy_cb), NULL);
+       gtk_container_add(GTK_CONTAINER(list_bb), copy_bt);
+       gtk_widget_show(copy_bt);
+
+       del_bt = gtk_button_new_with_label ("Delete");
+       gtk_widget_set_sensitive(del_bt, FALSE);
+       gtk_signal_connect(GTK_OBJECT(del_bt), "clicked",
+           GTK_SIGNAL_FUNC(filter_sel_del_cb), NULL);
+       gtk_container_add(GTK_CONTAINER(list_bb), del_bt);
+       gtk_widget_show(del_bt);
+
+       if (wants_add_expression_button) {
+               /* Create the "Add Expression..." button, to pop up a dialog
+                  for constructing filter comparison expressions. */
+               add_expression_bt = gtk_button_new_with_label("Add Expression...");
+               gtk_signal_connect(GTK_OBJECT(add_expression_bt), "clicked",
+                   GTK_SIGNAL_FUNC(filter_expr_cb), main_w);
+               gtk_container_add(GTK_CONTAINER(list_bb), add_expression_bt);
+               gtk_widget_show(add_expression_bt);
+       }
+
+       filter_sc = gtk_scrolled_window_new(NULL, NULL);
+       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(filter_sc),
+           GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+       gtk_widget_set_usize(filter_sc, 250, 150);
+       gtk_container_add(GTK_CONTAINER(top_hb), filter_sc);
+       gtk_widget_show(filter_sc);
+
+       filter_l = gtk_list_new();
+       gtk_list_set_selection_mode(GTK_LIST(filter_l), GTK_SELECTION_SINGLE);
+       gtk_signal_connect(GTK_OBJECT(filter_l), "selection_changed",
+           GTK_SIGNAL_FUNC(filter_sel_list_cb), filter_pg);
+       gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(filter_sc),
+           filter_l);
+       gtk_widget_show(filter_l);
+
+       gtk_object_set_data(GTK_OBJECT(filter_l), E_FILT_DBLFUNC_KEY, filter_dlg_dclick);
+       gtk_object_set_data(GTK_OBJECT(filter_l), E_FILT_DBLARG_KEY, main_w);
+
+       flp = g_list_first(fl);
+       while (flp) {
+               filt    = (filter_def *) flp->data;
+               nl_lb   = gtk_label_new(filt->name);
+               nl_item = gtk_list_item_new();
+
+               gtk_signal_connect(GTK_OBJECT(nl_item), "button_press_event",
+                   GTK_SIGNAL_FUNC(filter_sel_list_button_cb), filter_l);
+
+               gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5);
+               gtk_container_add(GTK_CONTAINER(nl_item), nl_lb);
+               gtk_widget_show(nl_lb);
+               gtk_container_add(GTK_CONTAINER(filter_l), nl_item);
+               gtk_widget_show(nl_item);
+               gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_LBL_KEY, nl_lb);
+               gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_NAME_KEY, flp);
+
+               if (filter_te_str && filt->strval) {
+                       if (strcmp(filter_te_str, filt->strval) == 0)
+                               l_select = nl_item;
+               }
+
+               flp = flp->next;
+       }
+
+       /* Middle row: Filter name entry */
+       middle_hb = gtk_hbox_new(FALSE, 5);
+       gtk_container_add(GTK_CONTAINER(filter_pg), middle_hb);
+       gtk_widget_show(middle_hb);
+  
+       name_lb = gtk_label_new("Filter name:");
+       gtk_box_pack_start(GTK_BOX(middle_hb), name_lb, FALSE, FALSE, 3);
+       gtk_widget_show(name_lb);
+  
+       name_te = gtk_entry_new();
+       gtk_box_pack_start(GTK_BOX(middle_hb), name_te, TRUE, TRUE, 3);
+       gtk_widget_show(name_te);
+
+       /* Bottom row: Filter text entry */
+       bottom_hb = gtk_hbox_new(FALSE, 5);
+       gtk_container_add(GTK_CONTAINER(filter_pg), bottom_hb);
+       gtk_widget_show(bottom_hb);
+  
+       filter_lb = gtk_label_new("Filter string:");
+       gtk_box_pack_start(GTK_BOX(bottom_hb), filter_lb, FALSE, FALSE, 3);
+       gtk_widget_show(filter_lb);
+  
+       filter_te = gtk_entry_new();
+       gtk_box_pack_start(GTK_BOX(bottom_hb), filter_te, TRUE, TRUE, 3);
+       gtk_widget_show(filter_te);
+
+       if (l_select) {
+               gtk_list_select_child(GTK_LIST(filter_l), l_select);
+       } else if (filter_te_str && filter_te_str[0]) {
+               gtk_entry_set_text(GTK_ENTRY(name_te), "New filter");
+               gtk_entry_set_text(GTK_ENTRY(filter_te), filter_te_str);
+       }
+
        gtk_box_pack_start(GTK_BOX(main_vb), filter_pg, TRUE, TRUE, 0);
-       gtk_object_set_data(GTK_OBJECT(filter_pg), E_FILT_TE_PTR_KEY, filter_te);
+       gtk_object_set_data(GTK_OBJECT(filter_pg), E_FILT_TE_PTR_KEY, parent_filter_te);
        gtk_object_set_data(GTK_OBJECT(main_w), E_FILTER_WIDGET_KEY, filter_pg);
 
        bbox = gtk_hbutton_box_new();
@@ -270,27 +471,37 @@ filter_dialog_new(GtkWidget *caller, GtkWidget *filter_te,
 
        ok_bt = gtk_button_new_with_label ("OK");
        gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
-               GTK_SIGNAL_FUNC(filter_dlg_ok), GTK_OBJECT(main_w));
+               GTK_SIGNAL_FUNC(filter_dlg_ok_cb), main_w);
        GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
        gtk_box_pack_start(GTK_BOX(bbox), ok_bt, TRUE, TRUE, 0);
+       gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_TE_KEY, filter_te);
        gtk_widget_grab_default(ok_bt);
        gtk_widget_show(ok_bt);
 
+       if (wants_apply_button) {
+               apply_bt = gtk_button_new_with_label ("Apply");
+               gtk_signal_connect(GTK_OBJECT(apply_bt), "clicked",
+                   GTK_SIGNAL_FUNC(filter_dlg_apply_cb), main_w);
+               GTK_WIDGET_SET_FLAGS(apply_bt, GTK_CAN_DEFAULT);
+               gtk_box_pack_start(GTK_BOX(bbox), apply_bt, TRUE, TRUE, 0);
+               gtk_widget_show(apply_bt);
+       }
+
        save_bt = gtk_button_new_with_label ("Save");
        gtk_signal_connect(GTK_OBJECT(save_bt), "clicked",
-               GTK_SIGNAL_FUNC(filter_dlg_save), GTK_OBJECT(main_w));
+               GTK_SIGNAL_FUNC(filter_dlg_save_cb), GTK_OBJECT(main_w));
        GTK_WIDGET_SET_FLAGS(save_bt, GTK_CAN_DEFAULT);
        gtk_box_pack_start(GTK_BOX(bbox), save_bt, TRUE, TRUE, 0);
        gtk_widget_show(save_bt);
 
        cancel_bt = gtk_button_new_with_label ("Cancel");
        gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
-               GTK_SIGNAL_FUNC(filter_dlg_cancel), GTK_OBJECT(main_w));
+               GTK_SIGNAL_FUNC(filter_dlg_cancel_cb), GTK_OBJECT(main_w));
        GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
        gtk_box_pack_start(GTK_BOX(bbox), cancel_bt, TRUE, TRUE, 0);
        gtk_widget_show(cancel_bt);
 
-              dlg_set_cancel(main_w, cancel_bt);
+       dlg_set_cancel(main_w, cancel_bt);
 
        gtk_widget_show(main_w);
 
@@ -298,22 +509,96 @@ filter_dialog_new(GtkWidget *caller, GtkWidget *filter_te,
 }
 
 static void
-filter_dlg_ok(GtkWidget *ok_bt, gpointer parent_w)
+filter_dlg_dclick(GtkWidget *dummy, gpointer main_w_arg)
 {
-       filter_prefs_ok(gtk_object_get_data(GTK_OBJECT(parent_w), E_FILTER_WIDGET_KEY));
-       gtk_widget_destroy(GTK_WIDGET(parent_w));
+       GtkWidget  *main_w = GTK_WIDGET(main_w_arg);
+       GtkWidget  *w = gtk_object_get_data(GTK_OBJECT(main_w), E_FILTER_WIDGET_KEY);
+       GList      *flp, *sl;
+       GtkObject  *l_item;
+       filter_def *filt;
+       GtkWidget  *mw_filt = gtk_object_get_data(GTK_OBJECT(w), E_FILT_TE_PTR_KEY);
+
+       if (mw_filt != NULL) {
+               /*
+                * We have a text entry widget associated with this dialog
+                * box; is one of the filters in the list selected?
+                */
+               sl = GTK_LIST(filter_l)->selection;
+               if (sl != NULL) {
+                       /*
+                        * Yes.  Put it in the text entry widget, and then
+                        * activate that widget to cause the filter we
+                        * put there to be applied.
+                        */
+                       l_item = GTK_OBJECT(sl->data);
+                       flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
+                       if (flp) {
+                               filt = (filter_def *) flp->data;
+                               gtk_entry_set_text(GTK_ENTRY(mw_filt),
+                                   filt->strval);
+                               gtk_signal_emit_by_name(GTK_OBJECT(mw_filt),
+                                   "activate");
+                       }
+               }
+       }
+
+       filter_prefs_delete(w);
+
+       gtk_widget_destroy(main_w);
 }
 
 static void
-filter_dlg_save(GtkWidget *save_bt, gpointer parent_w)
+filter_dlg_ok_cb(GtkWidget *ok_bt, gpointer main_w_arg)
+{
+       GtkWidget  *main_w = GTK_WIDGET(main_w_arg);
+       GtkWidget  *w = gtk_object_get_data(GTK_OBJECT(main_w), E_FILTER_WIDGET_KEY);
+
+       /*
+        * Apply the filter.
+        */
+       filter_dlg_apply_cb(NULL, main_w_arg);
+
+       /*
+        * Now dismiss the dialog box.
+        */
+       filter_prefs_delete(w);
+       gtk_widget_destroy(main_w);
+}
+
+static void
+filter_dlg_apply_cb(GtkWidget *apply_bt, gpointer main_w_arg)
+{
+       GtkWidget  *main_w = GTK_WIDGET(main_w_arg);
+       GtkWidget  *w = gtk_object_get_data(GTK_OBJECT(main_w), E_FILTER_WIDGET_KEY);
+       GtkWidget  *mw_filt = gtk_object_get_data(GTK_OBJECT(w), E_FILT_TE_PTR_KEY);
+       GtkWidget  *filter_te;
+       gchar      *filter_string;
+       
+       if (mw_filt != NULL) {
+               /*
+                * We have a text entry widget associated with this dialog
+                * box; put the filter in our text entry widget into that
+                * text entry widget, and then activate that widget to
+                * cause the filter we put there to be applied.
+                */
+               filter_te = gtk_object_get_data(GTK_OBJECT(main_w),
+                   E_FILT_TE_KEY);
+               filter_string = gtk_entry_get_text(GTK_ENTRY(filter_te));
+               gtk_entry_set_text(GTK_ENTRY(mw_filt), filter_string);
+               gtk_signal_emit_by_name(GTK_OBJECT(mw_filt), "activate");
+       }
+}
+
+static void
+filter_dlg_save_cb(GtkWidget *save_bt, gpointer parent_w)
 {
        filter_prefs_save(gtk_object_get_data(GTK_OBJECT(parent_w), E_FILTER_WIDGET_KEY));
 }
 
 static void
-filter_dlg_cancel(GtkWidget *cancel_bt, gpointer parent_w)
+filter_dlg_cancel_cb(GtkWidget *cancel_bt, gpointer parent_w)
 {
-       filter_prefs_cancel(gtk_object_get_data(GTK_OBJECT(parent_w),  E_FILTER_WIDGET_KEY));
+       filter_prefs_delete(gtk_object_get_data(GTK_OBJECT(parent_w),  E_FILTER_WIDGET_KEY));
        gtk_widget_destroy(GTK_WIDGET(parent_w));
 }
 
@@ -362,158 +647,6 @@ filter_sel_list_button_cb (GtkWidget *widget, GdkEventButton *event,
     return FALSE;
 }
 
-/* Create and display the filter selection widgets. */
-static GtkWidget *
-filter_prefs_show(GtkWidget *w, gboolean wants_apply_button,
-                  GtkSignalFunc func, GtkObject *func_arg)
-{
-  GtkWidget  *main_vb, *top_hb, *list_bb, *new_bt, *filter_sc,
-             *nl_item, *nl_lb, *middle_hb, *name_lb, *bottom_hb,
-             *filter_lb;
-  GtkWidget  *l_select = NULL;
-  GList      *flp = NULL;
-  filter_def *filt;
-  gchar      *filter_te_str = NULL;
-
-  /* Make sure everything is set up */  
-  get_filter_list();
-  if (w)
-    filter_te_str = gtk_entry_get_text(GTK_ENTRY(w));
-
-  /* Container for each row of widgets */
-  main_vb = gtk_vbox_new(FALSE, 5);
-  gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
-  gtk_widget_show(main_vb);
-  gtk_object_set_data(GTK_OBJECT(main_vb), E_FILT_CM_KEY, (gpointer)FALSE);
-  
-  /* Top row: Filter list and buttons */
-  top_hb = gtk_hbox_new(FALSE, 5);
-  gtk_container_add(GTK_CONTAINER(main_vb), top_hb);
-  gtk_widget_show(top_hb);
-  
-  list_bb = gtk_vbutton_box_new();
-  gtk_button_box_set_layout (GTK_BUTTON_BOX (list_bb), GTK_BUTTONBOX_START);
-  gtk_container_add(GTK_CONTAINER(top_hb), list_bb);
-  gtk_widget_show(list_bb);
-
-  new_bt = gtk_button_new_with_label ("New");
-  gtk_signal_connect(GTK_OBJECT(new_bt), "clicked",
-    GTK_SIGNAL_FUNC(filter_sel_new_cb), NULL);
-  gtk_container_add(GTK_CONTAINER(list_bb), new_bt);
-  gtk_widget_show(new_bt);
-  
-  chg_bt = gtk_button_new_with_label ("Change");
-  gtk_widget_set_sensitive(chg_bt, FALSE);
-  gtk_signal_connect(GTK_OBJECT(chg_bt), "clicked",
-    GTK_SIGNAL_FUNC(filter_sel_chg_cb), NULL);
-  gtk_container_add(GTK_CONTAINER(list_bb), chg_bt);
-  gtk_widget_show(chg_bt);
-  
-  copy_bt = gtk_button_new_with_label ("Copy");
-  gtk_widget_set_sensitive(copy_bt, FALSE);
-  gtk_signal_connect(GTK_OBJECT(copy_bt), "clicked",
-    GTK_SIGNAL_FUNC(filter_sel_copy_cb), NULL);
-  gtk_container_add(GTK_CONTAINER(list_bb), copy_bt);
-  gtk_widget_show(copy_bt);
-  
-  del_bt = gtk_button_new_with_label ("Delete");
-  gtk_widget_set_sensitive(del_bt, FALSE);
-  gtk_signal_connect(GTK_OBJECT(del_bt), "clicked",
-    GTK_SIGNAL_FUNC(filter_sel_del_cb), NULL);
-  gtk_container_add(GTK_CONTAINER(list_bb), del_bt);
-  gtk_widget_show(del_bt);
-
-  if (wants_apply_button) {
-    apply_bt = gtk_button_new_with_label("Apply");
-    gtk_widget_set_sensitive(apply_bt, FALSE);
-    gtk_signal_connect(GTK_OBJECT(apply_bt), "clicked",
-      GTK_SIGNAL_FUNC(filter_sel_apply_cb), w);
-    gtk_container_add(GTK_CONTAINER(list_bb), apply_bt);
-    gtk_widget_show(apply_bt);
-  } else
-    apply_bt = NULL;
-
-  filter_sc = gtk_scrolled_window_new(NULL, NULL);
-  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(filter_sc),
-    GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-  gtk_widget_set_usize(filter_sc, 250, 150);
-  gtk_container_add(GTK_CONTAINER(top_hb), filter_sc);
-  gtk_widget_show(filter_sc);
-
-  filter_l = gtk_list_new();
-  gtk_list_set_selection_mode(GTK_LIST(filter_l), GTK_SELECTION_SINGLE);
-  gtk_signal_connect(GTK_OBJECT(filter_l), "selection_changed",
-    GTK_SIGNAL_FUNC(filter_sel_list_cb), main_vb);
-  gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(filter_sc),
-    filter_l);
-  gtk_widget_show(filter_l);
-
-  gtk_object_set_data(GTK_OBJECT(filter_l), E_FILT_DBLFUNC_KEY, func);
-  gtk_object_set_data(GTK_OBJECT(filter_l), E_FILT_DBLARG_KEY, func_arg);
-
-  flp = g_list_first(fl);
-  while (flp) {
-    filt    = (filter_def *) flp->data;
-    nl_lb   = gtk_label_new(filt->name);
-    nl_item = gtk_list_item_new();
-
-    gtk_signal_connect(GTK_OBJECT(nl_item),
-                       "button_press_event",
-                       GTK_SIGNAL_FUNC(filter_sel_list_button_cb),
-                       filter_l);
-
-    gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5);
-    gtk_container_add(GTK_CONTAINER(nl_item), nl_lb);
-    gtk_widget_show(nl_lb);
-    gtk_container_add(GTK_CONTAINER(filter_l), nl_item);
-    gtk_widget_show(nl_item);
-    gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_LBL_KEY, nl_lb);
-    gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_NAME_KEY, flp);
-    if (filter_te_str && filt->strval)
-      if (strcmp(filter_te_str, filt->strval) == 0)
-        l_select = nl_item;
-
-    flp = flp->next;
-  }
-  
-  /* Middle row: Filter name entry */
-  middle_hb = gtk_hbox_new(FALSE, 5);
-  gtk_container_add(GTK_CONTAINER(main_vb), middle_hb);
-  gtk_widget_show(middle_hb);
-  
-  name_lb = gtk_label_new("Filter name:");
-  gtk_box_pack_start(GTK_BOX(middle_hb), name_lb, FALSE, FALSE, 3);
-  gtk_widget_show(name_lb);
-  
-  name_te = gtk_entry_new();
-  gtk_box_pack_start(GTK_BOX(middle_hb), name_te, TRUE, TRUE, 3);
-  gtk_widget_show(name_te);
-
-  /* Bottom row: Filter text entry */
-  bottom_hb = gtk_hbox_new(FALSE, 5);
-  gtk_container_add(GTK_CONTAINER(main_vb), bottom_hb);
-  gtk_widget_show(bottom_hb);
-  
-  filter_lb = gtk_label_new("Filter string:");
-  gtk_box_pack_start(GTK_BOX(bottom_hb), filter_lb, FALSE, FALSE, 3);
-  gtk_widget_show(filter_lb);
-  
-  filter_te = gtk_entry_new();
-  gtk_box_pack_start(GTK_BOX(bottom_hb), filter_te, TRUE, TRUE, 3);
-  gtk_widget_show(filter_te);
-
-  if (l_select)
-  {
-    gtk_list_select_child(GTK_LIST(filter_l), l_select);
-  } else if (filter_te_str && filter_te_str[0]) {
-    gtk_entry_set_text(GTK_ENTRY(name_te), "New filter");
-    gtk_entry_set_text(GTK_ENTRY(filter_te), filter_te_str);
-  }
-    
-  return(main_vb);
-}
-
 static void
 filter_sel_list_cb(GtkWidget *l, gpointer data) {
   filter_def *filt;
@@ -546,8 +679,6 @@ filter_sel_list_cb(GtkWidget *l, gpointer data) {
     gtk_widget_set_sensitive(chg_bt, sensitivity);
     gtk_widget_set_sensitive(copy_bt, sensitivity);
     gtk_widget_set_sensitive(del_bt, sensitivity);
-    if (apply_bt != NULL)
-      gtk_widget_set_sensitive(apply_bt, sensitivity);
   }
 }
 
@@ -667,44 +798,14 @@ filter_sel_del_cb(GtkWidget *w, gpointer data) {
   }
 }
 
-void
-filter_sel_apply_cb(GtkWidget *w, gpointer data)
-{
-       GList      *flp, *sl;
-       GtkObject  *l_item;
-       filter_def *filt;
-       GtkWidget  *mw_filt = data;
-       
-       sl = GTK_LIST(filter_l)->selection;
-       if (sl != NULL && mw_filt != NULL) {  /* Place something in the filter box. */
-               l_item = GTK_OBJECT(sl->data);
-               flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
-               if (flp) {
-                       filt = (filter_def *) flp->data;
-                       gtk_entry_set_text(GTK_ENTRY(mw_filt), filt->strval);
-                       gtk_signal_emit_by_name(GTK_OBJECT(mw_filt), "activate");
-               }
-       }
-}
-
 static void
-filter_prefs_ok(GtkWidget *w) {
-  GList      *flp, *sl;
-  GtkObject  *l_item;
-  filter_def *filt;
-  GtkWidget  *mw_filt = gtk_object_get_data(GTK_OBJECT(w), E_FILT_TE_PTR_KEY);
-
-  sl = GTK_LIST(filter_l)->selection;
-  if (sl && mw_filt) {  /* Place something in the filter box. */
-    l_item = GTK_OBJECT(sl->data);
-    flp    = (GList *) gtk_object_get_data(l_item, E_FILT_NAME_KEY);
-    if (flp) {
-      filt = (filter_def *) flp->data;
-      gtk_entry_set_text(GTK_ENTRY(mw_filt), filt->strval);
-    }
-  }
+filter_expr_cb(GtkWidget *w, gpointer main_w_arg)
+{
+       GtkWidget  *main_w = GTK_WIDGET(main_w_arg);
+       GtkWidget  *filter_te;
 
-  filter_prefs_delete(w);
+       filter_te = gtk_object_get_data(GTK_OBJECT(main_w), E_FILT_TE_KEY);
+       dfilter_expr_dlg_new(filter_te);
 }
 
 static void
@@ -741,12 +842,6 @@ filter_prefs_save(GtkWidget *w) {
   g_free(ff_path);
 }
 
-static void
-filter_prefs_cancel(GtkWidget *w) {
-
-  filter_prefs_delete(w);
-}
-
 static void
 filter_prefs_delete(GtkWidget *w) {
  
index 08139ec260a89f5f9e9af53cb07906a29db8decc..91cc783d0e1a40b89ce2e41c7660a664275cf6d9 100644 (file)
@@ -3,7 +3,7 @@
  * (This used to be a notebook page under "Preferences", hence the
  * "prefs" in the file name.)
  *
- * $Id: filter_prefs.h,v 1.6 2000/08/05 07:02:27 guy Exp $
+ * $Id: filter_prefs.h,v 1.7 2001/01/02 01:32:21 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
 #ifndef __FILTER_H__
 #define __FILTER_H__
 
-void filter_browse_cb(GtkWidget *, gpointer);
+void capture_filter_construct_cb(GtkWidget *w, gpointer user_data);
+void display_filter_construct_cb(GtkWidget *w, gpointer wants_apply_button);
 void filter_dialog_cb(GtkWidget *);
 
+#define E_FILT_TE_KEY          "filter_te"
 #define E_FILT_TE_PTR_KEY      "filter_te_ptr"
 #define E_FILT_CALLER_PTR_KEY  "filter_caller_ptr"
 #define E_FILT_DIALOG_PTR_KEY  "filter_dialog_ptr"
index 08dde87f5f5078c2f9bfc562252ecdde7afc1c0a..1cd078bbb692b06ac41f60e3c8a3837a7355f871 100644 (file)
@@ -1,7 +1,7 @@
 /* find_dlg.c
  * Routines for "find frame" window
  *
- * $Id: find_dlg.c,v 1.15 2000/08/23 06:55:49 guy Exp $
+ * $Id: find_dlg.c,v 1.16 2001/01/02 01:32:21 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -104,7 +104,7 @@ find_frame_cb(GtkWidget *w, gpointer d)
   
   filter_bt = gtk_button_new_with_label("Filter:");
   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
-    GTK_SIGNAL_FUNC(filter_browse_cb), NULL);
+    GTK_SIGNAL_FUNC(display_filter_construct_cb), NULL);
   gtk_box_pack_start(GTK_BOX(filter_hb), filter_bt, FALSE, TRUE, 0);
   gtk_widget_show(filter_bt);
   
index 6f84aee1774d28e202724ca95eed136d6eb7cfec..f81a3e19af2194414d0a2e118cdc7a885e400671 100644 (file)
@@ -1,6 +1,6 @@
 /* main.c
  *
- * $Id: main.c,v 1.169 2000/12/22 12:05:38 gram Exp $
+ * $Id: main.c,v 1.170 2001/01/02 01:32:21 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -1589,10 +1589,10 @@ create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
   gtk_widget_show(stat_hbox);
 
   filter_bt = gtk_button_new_with_label("Filter:");
-  /* A non-null pointer passed to "filter_browse_cb()" causes it to
+  /* A non-null pointer passed to "display_filter_construct_cb()" causes it to
      give the dialog box it pops up an "Apply" button. */
   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
-    GTK_SIGNAL_FUNC(filter_browse_cb), "");
+    GTK_SIGNAL_FUNC(display_filter_construct_cb), "");
   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
   gtk_widget_show(filter_bt);
   
index fc892716eefb22a532b4d0f322f8f1815197cbad..cf165e8ca19ce842de7e224f80665d4fba5ea7b9 100644 (file)
@@ -1,7 +1,7 @@
 /* proto_draw.c
  * Routines for GTK+ packet display
  *
- * $Id: proto_draw.c,v 1.23 2000/11/22 04:07:00 gram Exp $
+ * $Id: proto_draw.c,v 1.24 2001/01/02 01:32:21 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -54,8 +54,6 @@
 #define BYTE_VIEW_WIDTH    16
 #define BYTE_VIEW_SEP      8
 
-extern GdkFont      *m_r_font, *m_b_font;
-
 static void
 proto_tree_draw_node(GNode *node, gpointer data);