3 * Allow the user to construct a subexpression of a display filter
4 * expression, testing a particular field; display the tree of fields
5 * and the relations and values with which it can be compared.
7 * Copyright 2000, Jeffrey C. Foster <jfoste@woodward.com> and
8 * Guy Harris <guy@alum.mit.edu>
10 * $Id: dfilter_expr_dlg.c,v 1.42 2003/10/29 23:15:35 guy Exp $
12 * Ethereal - Network traffic analyzer
13 * By Gerald Combs <gerald@ethereal.com>
14 * Copyright 2000 Gerald Combs
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 * may want to check the enable field to decide if protocol should be in tree
33 * improve speed of dialog box creation
34 * - I believe this is slow because of tree widget creation.
35 * 1) could improve the widget
36 * 2) keep a copy in memory after the first time.
37 * user can pop multiple tree dialogs by pressing the "Tree" button multiple
38 * time. not a good thing.
39 * Sort the protocols and children
50 #ifdef NEED_SNPRINTF_H
51 # include "snprintf.h"
57 #include "simple_dialog.h"
58 #include "dlg_utils.h"
59 #include "proto_dlg.h"
60 #include "filter_prefs.h"
61 #include "dfilter_expr_dlg.h"
62 #include "compat_macros.h"
64 #define E_DFILTER_EXPR_TREE_KEY "dfilter_expr_tree"
65 #define E_DFILTER_EXPR_CURRENT_VAR_KEY "dfilter_expr_current_var"
66 #define E_DFILTER_EXPR_RELATION_LIST_KEY "dfilter_expr_relation_list"
67 #define E_DFILTER_EXPR_RANGE_LABEL_KEY "dfilter_expr_range_label"
68 #define E_DFILTER_EXPR_RANGE_ENTRY_KEY "dfilter_expr_range_entry"
69 #define E_DFILTER_EXPR_VALUE_LABEL_KEY "dfilter_expr_value_label"
70 #define E_DFILTER_EXPR_VALUE_ENTRY_KEY "dfilter_expr_value_entry"
71 #define E_DFILTER_EXPR_VALUE_LIST_KEY "dfilter_expr_value_list"
72 #define E_DFILTER_EXPR_VALUE_LIST_SW_KEY "dfilter_expr_value_list_sw"
73 #define E_DFILTER_EXPR_ACCEPT_BT_KEY "dfilter_expr_accept_bt"
74 #define E_DFILTER_EXPR_VALUE_KEY "dfilter_expr_value"
76 typedef struct protocol_data {
81 static void show_relations(GtkWidget *relation_list, ftenum_t ftype);
82 static gboolean relation_is_presence_test(const char *string);
83 static void add_relation_list(GtkWidget *relation_list, char *relation);
84 static void build_boolean_values(GtkWidget *value_list_scrolled_win,
85 GtkWidget *value_list,
86 const true_false_string *values);
87 static void build_enum_values(GtkWidget *value_list_scrolled_win,
88 GtkWidget *value_list,
89 const value_string *values);
90 static void add_value_list_item(GtkWidget *value_list, gchar *string,
92 static void display_value_fields(header_field_info *hfinfo,
93 gboolean is_comparison, GtkWidget *value_label,
94 GtkWidget *value_entry, GtkWidget *value_list,
95 GtkWidget *value_list_scrolled_win,
96 GtkWidget *range_label,
97 GtkWidget *range_entry);
100 * Note that this is called every time the user clicks on an item,
101 * whether it is already selected or not.
103 #if GTK_MAJOR_VERSION < 2
105 field_select_row_cb(GtkWidget *tree, GList *node, gint column _U_,
106 gpointer user_data _U_)
109 field_select_row_cb(GtkTreeSelection *sel, gpointer tree)
112 GtkWidget *window = gtk_widget_get_toplevel(tree);
113 GtkWidget *relation_list = OBJECT_GET_DATA(window,
114 E_DFILTER_EXPR_RELATION_LIST_KEY);
115 GtkWidget *range_label = OBJECT_GET_DATA(window,
116 E_DFILTER_EXPR_RANGE_LABEL_KEY);
117 GtkWidget *range_entry = OBJECT_GET_DATA(window,
118 E_DFILTER_EXPR_RANGE_ENTRY_KEY);
119 GtkWidget *value_label = OBJECT_GET_DATA(window,
120 E_DFILTER_EXPR_VALUE_LABEL_KEY);
121 GtkWidget *value_entry = OBJECT_GET_DATA(window,
122 E_DFILTER_EXPR_VALUE_ENTRY_KEY);
123 GtkWidget *value_list = OBJECT_GET_DATA(window,
124 E_DFILTER_EXPR_VALUE_LIST_KEY);
125 GtkWidget *value_list_scrolled_win = OBJECT_GET_DATA(window,
126 E_DFILTER_EXPR_VALUE_LIST_SW_KEY);
127 GtkWidget *accept_bt = OBJECT_GET_DATA(window,
128 E_DFILTER_EXPR_ACCEPT_BT_KEY);
129 header_field_info *hfinfo, *cur_hfinfo;
130 const char *value_type;
131 char value_label_string[1024+1]; /* XXX - should be large enough */
132 #if GTK_MAJOR_VERSION >= 2
136 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
138 gtk_tree_model_get(model, &iter, 1, &hfinfo, -1);
141 hfinfo = gtk_ctree_node_get_row_data(GTK_CTREE(tree),
142 GTK_CTREE_NODE(node));
146 * What was the item that was last selected?
148 cur_hfinfo = OBJECT_GET_DATA(window, E_DFILTER_EXPR_CURRENT_VAR_KEY);
149 if (cur_hfinfo == hfinfo) {
151 * It's still selected; no need to change anything.
157 * Mark it as currently selected.
159 OBJECT_SET_DATA(window, E_DFILTER_EXPR_CURRENT_VAR_KEY, hfinfo);
161 show_relations(relation_list, hfinfo->type);
164 * Set the label for the value to indicate what type of value
167 value_type = ftype_pretty_name(hfinfo->type);
168 if (value_type != NULL) {
170 * Indicate what type of value it is.
172 snprintf(value_label_string, sizeof value_label_string,
173 "Value (%s)", value_type);
174 gtk_label_set_text(GTK_LABEL(value_label), value_label_string);
178 * Clear the entry widget for the value, as whatever
179 * was there before doesn't apply.
181 gtk_entry_set_text(GTK_ENTRY(value_entry), "");
183 switch (hfinfo->type) {
187 * The list of values should be the strings for "true"
188 * and "false"; show them in the value list.
190 build_boolean_values(value_list_scrolled_win, value_list,
203 * If this has a value_string table associated with it,
204 * fill up the list of values, otherwise clear the list
207 if (hfinfo->strings != NULL) {
208 build_enum_values(value_list_scrolled_win, value_list,
211 #if GTK_MAJOR_VERSION < 2
212 gtk_list_clear_items(GTK_LIST(value_list), 0, -1);
214 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
220 * Clear the list of values.
222 #if GTK_MAJOR_VERSION < 2
223 gtk_list_clear_items(GTK_LIST(value_list), 0, -1);
225 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
231 * Display various items for the value, as appropriate.
232 * The relation we start out with is never a comparison.
234 display_value_fields(hfinfo, FALSE, value_label, value_entry,
235 value_list, value_list_scrolled_win, range_label, range_entry);
238 * XXX - in browse mode, there always has to be something
239 * selected, so this should always be sensitive.
241 gtk_widget_set_sensitive(accept_bt, TRUE);
245 show_relations(GtkWidget *relation_list, ftenum_t ftype)
247 #if GTK_MAJOR_VERSION >= 2
251 * Clear out the currently displayed list of relations.
253 #if GTK_MAJOR_VERSION < 2
254 gtk_list_clear_items(GTK_LIST(relation_list), 0, -1);
256 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(relation_list))));
260 * Add the supported relations.
262 add_relation_list(relation_list, "is present");
263 if (ftype_can_eq(ftype) ||
264 (ftype_can_slice(ftype) && ftype_can_eq(FT_BYTES)))
265 add_relation_list(relation_list, "==");
266 if (ftype_can_ne(ftype) ||
267 (ftype_can_slice(ftype) && ftype_can_ne(FT_BYTES)))
268 add_relation_list(relation_list, "!=");
269 if (ftype_can_gt(ftype) ||
270 (ftype_can_slice(ftype) && ftype_can_gt(FT_BYTES)))
271 add_relation_list(relation_list, ">");
272 if (ftype_can_lt(ftype) ||
273 (ftype_can_slice(ftype) && ftype_can_lt(FT_BYTES)))
274 add_relation_list(relation_list, "<");
275 if (ftype_can_ge(ftype) ||
276 (ftype_can_slice(ftype) && ftype_can_ge(FT_BYTES)))
277 add_relation_list(relation_list, ">=");
278 if (ftype_can_le(ftype) ||
279 (ftype_can_slice(ftype) && ftype_can_le(FT_BYTES)))
280 add_relation_list(relation_list, "<=");
281 if (ftype_can_contains(ftype) ||
282 (ftype_can_slice(ftype) && ftype_can_contains(FT_BYTES)))
283 add_relation_list(relation_list, "contains");
285 #if GTK_MAJOR_VERSION >= 2
286 gtk_tree_model_get_iter_first(gtk_tree_view_get_model(GTK_TREE_VIEW(relation_list)), &iter);
287 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list)), &iter);
292 * Given a string that represents a test to be made on a field, returns
293 * TRUE if it tests for the field's presence, FALSE otherwise.
296 relation_is_presence_test(const char *string)
298 return (strcmp(string, "is present") == 0);
302 add_relation_list(GtkWidget *relation_list, char *relation)
304 #if GTK_MAJOR_VERSION < 2
305 GtkWidget *label, *item;
307 label = gtk_label_new(relation);
308 item = gtk_list_item_new();
310 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
311 gtk_container_add(GTK_CONTAINER(item), label);
312 gtk_widget_show(label);
313 gtk_container_add(GTK_CONTAINER(relation_list), item);
314 gtk_widget_show(item);
316 GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(relation_list)));
319 gtk_list_store_append(store, &iter);
320 gtk_list_store_set(store, &iter, 0, relation, -1);
324 #if GTK_MAJOR_VERSION < 2
326 relation_list_sel_cb(GtkList *relation_list, GtkWidget *child _U_,
327 gpointer user_data _U_)
330 relation_list_sel_cb(GtkTreeSelection *sel, gpointer user_data _U_)
333 #if GTK_MAJOR_VERSION < 2
334 GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(relation_list));
336 GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(gtk_tree_selection_get_tree_view(sel)));
338 GtkWidget *range_label =
339 OBJECT_GET_DATA(window, E_DFILTER_EXPR_RANGE_LABEL_KEY);
340 GtkWidget *range_entry =
341 OBJECT_GET_DATA(window, E_DFILTER_EXPR_RANGE_ENTRY_KEY);
342 GtkWidget *value_label =
343 OBJECT_GET_DATA(window, E_DFILTER_EXPR_VALUE_LABEL_KEY);
344 GtkWidget *value_entry =
345 OBJECT_GET_DATA(window, E_DFILTER_EXPR_VALUE_ENTRY_KEY);
346 GtkWidget *value_list =
347 OBJECT_GET_DATA(window, E_DFILTER_EXPR_VALUE_LIST_KEY);
348 GtkWidget *value_list_scrolled_win =
349 OBJECT_GET_DATA(window, E_DFILTER_EXPR_VALUE_LIST_SW_KEY);
350 header_field_info *hfinfo =
351 OBJECT_GET_DATA(window, E_DFILTER_EXPR_CURRENT_VAR_KEY);
353 #if GTK_MAJOR_VERSION < 2
355 GtkWidget *item, *item_label;
358 * What's the relation?
360 sl = GTK_LIST(relation_list)->selection;
361 item = GTK_WIDGET(sl->data);
362 item_label = GTK_BIN(item)->child;
363 gtk_label_get(GTK_LABEL(item_label), &item_str);
369 * What's the relation?
371 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
373 gtk_tree_model_get(model, &iter, 0, &item_str, -1);
377 * Update the display of various items for the value, as appropriate.
379 display_value_fields(hfinfo,
380 !relation_is_presence_test(item_str),
381 value_label, value_entry, value_list,
382 value_list_scrolled_win, range_label, range_entry);
383 #if GTK_MAJOR_VERSION >= 2
389 build_boolean_values(GtkWidget *value_list_scrolled_win, GtkWidget *value_list,
390 const true_false_string *values)
392 static const true_false_string true_false = { "True", "False" };
393 #if GTK_MAJOR_VERSION >= 2
394 GtkTreeSelection *sel;
397 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list));
401 * Clear out the items for the list, and put in the names
402 * from the value_string list.
404 #if GTK_MAJOR_VERSION < 2
405 gtk_list_clear_items(GTK_LIST(value_list), 0, -1);
407 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
411 * Put the list in single mode, so we don't get any selection
412 * events while we're building it (i.e., so we don't get any
413 * on a list item BEFORE WE GET TO SET THE DATA FOR THE LIST
414 * ITEM SO THAT THE HANDLER CAN HANDLE IT).
416 #if GTK_MAJOR_VERSION < 2
417 gtk_list_set_selection_mode(GTK_LIST(value_list), GTK_SELECTION_SINGLE);
419 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
426 values = &true_false;
427 add_value_list_item(value_list, values->true_string, (gpointer)values);
428 add_value_list_item(value_list, values->false_string, NULL);
431 * OK, we're done, so we can finally put it in browse mode.
432 * Select the first item, so that the user doesn't have to, under
433 * the assumption that they're most likely to test if something
434 * is true, not false.
436 #if GTK_MAJOR_VERSION < 2
437 gtk_list_set_selection_mode(GTK_LIST(value_list), GTK_SELECTION_BROWSE);
438 gtk_list_select_item(GTK_LIST(value_list), 0);
440 gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
441 gtk_tree_model_get_iter_first(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list)), &iter);
442 gtk_tree_selection_select_iter(sel, &iter);
445 gtk_widget_show_all(value_list_scrolled_win);
449 build_enum_values(GtkWidget *value_list_scrolled_win _U_, GtkWidget *value_list,
450 const value_string *values)
452 #if GTK_MAJOR_VERSION >= 2
453 GtkTreeSelection *sel;
455 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list));
458 * Clear out the items for the list, and put in the names
459 * from the value_string list.
461 #if GTK_MAJOR_VERSION < 2
462 gtk_list_clear_items(GTK_LIST(value_list), 0, -1);
464 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
468 * Put the list in single mode, so we don't get any selection
469 * events while we're building it (i.e., so we don't get any
470 * on a list item BEFORE WE GET TO SET THE DATA FOR THE LIST
471 * ITEM SO THAT THE HANDLER CAN HANDLE IT).
473 #if GTK_MAJOR_VERSION < 2
474 gtk_list_set_selection_mode(GTK_LIST(value_list), GTK_SELECTION_SINGLE);
476 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
482 while (values->strptr != NULL) {
483 add_value_list_item(value_list, values->strptr,
489 * OK, we're done, so we can finally put it in browse mode.
491 #if GTK_MAJOR_VERSION < 2
492 gtk_list_set_selection_mode(GTK_LIST(value_list), GTK_SELECTION_BROWSE);
494 gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
499 add_value_list_item(GtkWidget *value_list, gchar *string, gpointer data)
501 #if GTK_MAJOR_VERSION < 2
502 GtkWidget *label, *item;
504 label = gtk_label_new(string);
505 item = gtk_list_item_new();
507 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
508 gtk_container_add(GTK_CONTAINER(item), label);
509 gtk_widget_show(label);
510 gtk_container_add(GTK_CONTAINER(value_list), item);
511 OBJECT_SET_DATA(item, E_DFILTER_EXPR_VALUE_KEY, data);
512 gtk_widget_show(item);
514 GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list)));
517 gtk_list_store_append(store, &iter);
518 gtk_list_store_set(store, &iter, 0, string, 1, data, -1);
523 * Show or hide the various values fields as appropriate for the field
524 * and currently-selected relation.
527 display_value_fields(header_field_info *hfinfo, gboolean is_comparison,
528 GtkWidget *value_label, GtkWidget *value_entry,
529 GtkWidget *value_list _U_,
530 GtkWidget *value_list_scrolled_win, GtkWidget *range_label,
531 GtkWidget *range_entry)
533 gboolean show_value_label = FALSE;
538 * this is an FT_NONE variable, in which case you can
539 * only check whether it's present or absent in the
544 * this is a Boolean variable, in which case you
545 * can't specify a value to compare with, you can
546 * only specify whether to test for the Boolean
547 * being true or to test for it being false
551 * this isn't a Boolean variable, in which case you
552 * can test for its presence in the protocol tree,
553 * and the default relation is such a test, in
554 * which case you don't compare with a value
556 * so we hide the value entry.
560 * The relation is a comparison; display the entry for
561 * the value with which to compare.
563 gtk_widget_show(value_entry);
566 * We're showing the entry; show the label as well.
568 show_value_label = TRUE;
571 * The relation isn't a comparison; there's no value with
572 * which to compare, so don't show the entry for it.
574 gtk_widget_hide(value_entry);
577 switch (hfinfo->type) {
582 * The relation is a comparison, so we're showing
583 * an entry for the value with which to compare;
584 * show the list of names for values as well.
585 * (The list of values contains the strings for
586 * "true" and "false".)
588 gtk_widget_show_all(value_list_scrolled_win);
591 * We're showing the value list; show the label as
594 show_value_label = TRUE;
597 * It's not a comparison, so we're not showing
598 * the entry for the value; don't show the
599 * list of names for values, either.
601 gtk_widget_hide_all(value_list_scrolled_win);
613 if (hfinfo->strings != NULL) {
615 * We have a list of values to show.
619 * The relation is a comparison, so we're
620 * showing an entry for the value with
621 * which to compare; show the list of
622 * names for values as well.
624 gtk_widget_show_all(value_list_scrolled_win);
627 * We're showing the entry; show the label
630 show_value_label = TRUE;
633 * It's not a comparison, so we're not showing
634 * the entry for the value; don't show the
635 * list of names for values, either.
637 gtk_widget_hide_all(value_list_scrolled_win);
641 * There is no list of names for values, so don't
644 gtk_widget_hide_all(value_list_scrolled_win);
650 * There is no list of names for values; hide the list.
652 gtk_widget_hide_all(value_list_scrolled_win);
656 if (show_value_label)
657 gtk_widget_show(value_label);
659 gtk_widget_hide(value_label);
662 * Is this a comparison, and are ranges supported by this type?
663 * If both are true, show the range stuff, otherwise hide it.
665 if (is_comparison && ftype_can_slice(hfinfo->type)) {
666 gtk_widget_show(range_label);
667 gtk_widget_show(range_entry);
669 gtk_widget_hide(range_label);
670 gtk_widget_hide(range_entry);
674 #if GTK_MAJOR_VERSION < 2
676 value_list_sel_cb(GtkList *value_list, GtkWidget *child,
677 gpointer value_entry_arg)
680 value_list_sel_cb(GtkTreeSelection *sel, gpointer value_entry_arg)
683 GtkWidget *value_entry = value_entry_arg;
684 #if GTK_MAJOR_VERSION < 2
685 GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(value_list));
687 GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(gtk_tree_selection_get_tree_view(sel)));
691 header_field_info *hfinfo = OBJECT_GET_DATA(window,
692 E_DFILTER_EXPR_CURRENT_VAR_KEY);
693 const value_string *value = NULL;
694 char value_string[11+1]; /* long enough for 32-bit octal value */
696 #if GTK_MAJOR_VERSION < 2
697 value = OBJECT_GET_DATA(child, E_DFILTER_EXPR_VALUE_KEY);
699 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
701 gtk_tree_model_get(model, &iter, 1, &value, -1);
705 * This should either be a numeric type or a Boolean type.
707 if (hfinfo->type == FT_BOOLEAN) {
709 * Boolean type; if the value key for the selected item
710 * is non-null, it's the item for "true", otherwise it's
711 * the item for "false". Compare with 1 if we're
712 * testing for "true", and compare with 0 if we're
713 * testing for "false".
716 strcpy(value_string, "1");
718 strcpy(value_string, "0");
721 * Numeric type; get the value corresponding to the
722 * selected item, and display it in the base for this
725 switch (hfinfo->display) {
728 switch (hfinfo->type) {
733 snprintf(value_string, sizeof value_string,
740 snprintf(value_string, sizeof value_string,
745 g_assert_not_reached();
750 snprintf(value_string, sizeof value_string, "0x%x",
755 snprintf(value_string, sizeof value_string, "%#o",
760 g_assert_not_reached();
763 gtk_entry_set_text(GTK_ENTRY(value_entry), value_string);
767 dfilter_report_bad_value(char *format, ...)
769 char error_msg_buf[1024];
772 va_start(args, format);
773 vsnprintf(error_msg_buf, sizeof error_msg_buf, format, args);
776 simple_dialog(ESD_TYPE_CRIT | ESD_TYPE_MODAL, NULL,
777 "%s", error_msg_buf);
781 dfilter_expr_dlg_accept_cb(GtkWidget *w, gpointer filter_te_arg)
783 GtkWidget *filter_te = filter_te_arg;
784 GtkWidget *window = gtk_widget_get_toplevel(w);
785 GtkWidget *relation_list =
786 OBJECT_GET_DATA(window, E_DFILTER_EXPR_RELATION_LIST_KEY);
787 GtkWidget *range_entry =
788 OBJECT_GET_DATA(window, E_DFILTER_EXPR_RANGE_ENTRY_KEY);
789 GtkWidget *value_entry =
790 OBJECT_GET_DATA(window, E_DFILTER_EXPR_VALUE_ENTRY_KEY);
791 header_field_info *hfinfo;
793 gchar *range_str, *stripped_range_str;
794 gchar *value_str, *stripped_value_str;
798 gboolean can_compare;
800 #if GTK_MAJOR_VERSION < 2
802 GtkWidget *item, *item_label;
810 * Get the variable to be tested.
812 hfinfo = OBJECT_GET_DATA(window, E_DFILTER_EXPR_CURRENT_VAR_KEY);
815 * Get the relation operator to use.
817 #if GTK_MAJOR_VERSION < 2
818 sl = GTK_LIST(relation_list)->selection;
819 item = GTK_WIDGET(sl->data);
820 item_label = GTK_BIN(item)->child;
821 gtk_label_get(GTK_LABEL(item_label), &item_str);
823 if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list)),
825 gtk_tree_model_get(model, &iter, 0, &item_str, -1);
827 /* XXX - the relation list is in GTK_SELECTION_BROWSE mode; how
828 can this ever be null? */
834 * Get the range to use, if any.
836 if (GTK_WIDGET_VISIBLE(range_entry)) {
837 range_str = g_strdup(gtk_entry_get_text(GTK_ENTRY(range_entry)));
839 * XXX - strip this even for strings?
840 * Doing so for strings mean you can't match a string that has
841 * leading or trailing whitespace, but you can't see trailing
842 * whitespace in a text field, so it's not clear that it's
843 * a good idea to allow that.
845 stripped_range_str = g_strstrip(range_str);
846 if (strcmp(stripped_range_str, "") == 0) {
848 * No range was specified.
852 stripped_range_str = NULL;
856 * XXX - check it for validity?
860 stripped_range_str = NULL;
864 * If a range was specified, the type of the LHS of the
865 * comparison is FT_BYTES; otherwise, it's the type of the field.
867 if (range_str == NULL)
868 ftype = hfinfo->type;
873 * Make sure the relation is valid for the type in question.
874 * We may be offering relations that the type of the field
875 * can't support, because the field's type supports slicing,
876 * and the relation *is* supported on byte strings.
878 if (strcmp(item_str, "==") == 0)
879 can_compare = ftype_can_eq(ftype);
880 else if (strcmp(item_str, "!=") == 0)
881 can_compare = ftype_can_ne(ftype);
882 else if (strcmp(item_str, ">") == 0)
883 can_compare = ftype_can_gt(ftype);
884 else if (strcmp(item_str, "<") == 0)
885 can_compare = ftype_can_lt(ftype);
886 else if (strcmp(item_str, ">=") == 0)
887 can_compare = ftype_can_ge(ftype);
888 else if (strcmp(item_str, "<=") == 0)
889 can_compare = ftype_can_le(ftype);
890 else if (strcmp(item_str, "contains") == 0)
891 can_compare = ftype_can_contains(ftype);
893 can_compare = TRUE; /* not a comparison */
895 if (range_str == NULL) {
896 simple_dialog(ESD_TYPE_CRIT | ESD_TYPE_MODAL, NULL,
897 "That field cannot be tested with \"%s\".",
900 simple_dialog(ESD_TYPE_CRIT | ESD_TYPE_MODAL, NULL,
901 "Ranges of that field cannot be tested with \"%s\".",
904 if (range_str != NULL)
910 * Get the value to use, if any.
912 if (GTK_WIDGET_VISIBLE(value_entry)) {
913 value_str = g_strdup(gtk_entry_get_text(GTK_ENTRY(value_entry)));
914 stripped_value_str = g_strstrip(value_str);
915 if (strcmp(stripped_value_str, "") == 0) {
917 * This field takes a value, but they didn't supply
920 simple_dialog(ESD_TYPE_CRIT | ESD_TYPE_MODAL, NULL,
921 "That field must be compared with a value, "
922 "but you didn't specify a value with which to "
924 if (range_str != NULL)
931 * Make sure the value is valid.
933 * If no range string was specified, it must be valid
934 * for the type of the field; if a range string was
935 * specified, must be valid for FT_BYTES.
937 if (strcmp(item_str, "contains") == 0) {
938 fvalue = fvalue_from_unparsed(ftype, stripped_value_str, TRUE,
939 dfilter_report_bad_value);
942 fvalue = fvalue_from_unparsed(ftype, stripped_value_str, FALSE,
943 dfilter_report_bad_value);
945 if (fvalue == NULL) {
949 * The dialog box was already popped up by
950 * "dfilter_report_bad_value()".
952 if (range_str != NULL)
960 stripped_value_str = NULL;
964 * Insert the expression at the current cursor position.
965 * If there's a non-whitespace character to the left of it,
966 * insert a blank first; if there's a non-whitespace character
967 * to the right of it, insert a blank after it.
969 pos = gtk_editable_get_position(GTK_EDITABLE(filter_te));
970 chars = gtk_editable_get_chars(GTK_EDITABLE(filter_te), pos, pos + 1);
971 if (strcmp(chars, "") != 0 && !isspace((unsigned char)chars[0]))
972 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
975 gtk_editable_insert_text(GTK_EDITABLE(filter_te), hfinfo->abbrev,
976 strlen(hfinfo->abbrev), &pos);
977 if (range_str != NULL) {
978 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "[", 1, &pos);
979 gtk_editable_insert_text(GTK_EDITABLE(filter_te),
980 stripped_range_str, strlen(stripped_range_str), &pos);
981 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "]", 1, &pos);
984 if (item_str != NULL && !relation_is_presence_test(item_str)) {
985 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
986 gtk_editable_insert_text(GTK_EDITABLE(filter_te), item_str,
987 strlen(item_str), &pos);
989 if (value_str != NULL) {
990 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
992 * XXX - we should do this by generating an appropriate display
993 * filter value string for this field; that requires us to have
994 * a "generate display filter string" method for every FT_ type.
996 switch (hfinfo->type) {
1000 case FT_UINT_STRING:
1001 case FT_ABSOLUTE_TIME:
1003 * Always put quotes around the string.
1010 * If the string contains white space, put quotes around it.
1012 quote_it = (strpbrk(stripped_value_str, " \t") != NULL);
1017 * Put quotes around the string.
1019 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "\"",
1022 gtk_editable_insert_text(GTK_EDITABLE(filter_te),
1023 stripped_value_str, strlen(stripped_value_str), &pos);
1026 * Put quotes around the string.
1028 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "\"",
1033 chars = gtk_editable_get_chars(GTK_EDITABLE(filter_te), pos + 1, pos + 2);
1034 if (strcmp(chars, "") != 0 && !isspace((unsigned char)chars[0]))
1035 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
1039 * Put the cursor after the expression we just entered into
1040 * the text entry widget.
1042 gtk_editable_set_position(GTK_EDITABLE(filter_te), pos);
1045 * We're done; destroy the dialog box (which is the top-level
1046 * widget for the "Accept" button).
1048 gtk_widget_destroy(window);
1049 #if GTK_MAJOR_VERSION >= 2
1055 dfilter_expr_dlg_cancel_cb(GtkWidget *w _U_, gpointer parent_w)
1058 * User pressed the cancel button; close the dialog box.
1060 gtk_widget_destroy(GTK_WIDGET(parent_w));
1064 dfilter_expr_dlg_destroy_cb(GtkWidget *w, gpointer filter_te)
1067 * The dialog box is being destroyed; disconnect from the
1068 * "destroy" signal on the text entry box to which we're
1069 * attached, as the handler for that signal is supposed
1070 * to destroy us, but we're already gone.
1072 SIGNAL_DISCONNECT_BY_FUNC(filter_te, dfilter_expr_dlg_cancel_cb, w);
1076 * Length of string used for protocol fields.
1078 #define TAG_STRING_LEN 256
1081 dfilter_expr_dlg_new(GtkWidget *filter_te)
1087 GtkWidget *tree_label, *tree, *tree_scrolled_win;
1089 GtkWidget *relation_label, *relation_list;
1090 GtkWidget *range_label, *range_entry;
1091 GtkWidget *value_vb;
1092 GtkWidget *value_label, *value_entry, *value_list_scrolled_win, *value_list;
1093 GtkWidget *list_bb, *alignment, *accept_bt, *close_bt;
1094 header_field_info *hfinfo;
1096 #if GTK_MAJOR_VERSION < 2
1100 GHashTable *proto_array;
1101 GtkCTreeNode *protocol_node, *item_node;
1103 GtkTreeStore *store;
1104 GtkTreeSelection *selection;
1105 GtkCellRenderer *renderer;
1106 GtkTreeViewColumn *column;
1107 GtkListStore *l_store;
1108 GtkTreeSelection *l_sel;
1111 window = dlg_window_new("Ethereal: Filter Expression");
1112 gtk_container_set_border_width(GTK_CONTAINER(window), 5);
1114 main_vb = gtk_vbox_new(FALSE, 5);
1115 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1116 gtk_container_add(GTK_CONTAINER(window), main_vb);
1117 gtk_widget_show(main_vb);
1119 hb = gtk_hbox_new(FALSE, 5);
1120 gtk_container_border_width(GTK_CONTAINER(hb), 5);
1121 gtk_container_add(GTK_CONTAINER(main_vb), hb);
1122 gtk_widget_show(hb);
1124 col1_vb = gtk_vbox_new(FALSE, 5);
1125 gtk_container_border_width(GTK_CONTAINER(col1_vb), 5);
1126 gtk_container_add(GTK_CONTAINER(hb), col1_vb);
1127 gtk_widget_show(col1_vb);
1129 tree_label = gtk_label_new("Field name");
1130 gtk_misc_set_alignment(GTK_MISC(tree_label), 0.0, 0.0);
1131 gtk_box_pack_start(GTK_BOX(col1_vb), tree_label, FALSE, FALSE, 0);
1132 gtk_widget_show(tree_label);
1134 tree_scrolled_win = gtk_scrolled_window_new(NULL, NULL);
1135 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tree_scrolled_win),
1136 GTK_POLICY_AUTOMATIC,
1137 GTK_POLICY_AUTOMATIC);
1138 WIDGET_SET_SIZE(tree_scrolled_win, 300, 400);
1139 gtk_box_pack_start(GTK_BOX(col1_vb), tree_scrolled_win, FALSE, FALSE, 0);
1140 gtk_widget_show(tree_scrolled_win);
1142 #if GTK_MAJOR_VERSION < 2
1143 tree = ctree_new(1, 0);
1144 SIGNAL_CONNECT(tree, "tree-select-row", field_select_row_cb, tree);
1146 store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
1147 tree = tree_view_new(GTK_TREE_MODEL(store));
1148 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree), FALSE);
1149 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
1150 gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
1151 renderer = gtk_cell_renderer_text_new();
1152 column = gtk_tree_view_column_new_with_attributes("Field name", renderer,
1154 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
1155 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1156 gtk_tree_view_column_set_sort_column_id(column, 0);
1157 SIGNAL_CONNECT(selection, "changed", field_select_row_cb, tree);
1159 gtk_container_add(GTK_CONTAINER(tree_scrolled_win), tree);
1161 #if GTK_MAJOR_VERSION < 2
1163 * GTK's annoying CTree widget will deliver a selection event
1164 * the instant you add an item to the tree, *the fact that you
1165 * haven't even had time to set the item's row data nonwithstanding*.
1167 * We'll put the widget into GTK_SELECTION_SINGLE mode in the
1168 * hopes that it's *STOP DOING THAT*.
1170 gtk_clist_set_selection_mode(GTK_CLIST(tree),
1171 GTK_SELECTION_SINGLE);
1174 col2_vb = gtk_vbox_new(FALSE, 5);
1175 gtk_container_border_width(GTK_CONTAINER(col2_vb), 5);
1176 gtk_container_add(GTK_CONTAINER(hb), col2_vb);
1177 gtk_widget_show(col2_vb);
1179 relation_label = gtk_label_new("Relation");
1180 gtk_misc_set_alignment(GTK_MISC(relation_label), 0.0, 0.0);
1181 gtk_box_pack_start(GTK_BOX(col2_vb), relation_label, FALSE, FALSE, 0);
1183 #if GTK_MAJOR_VERSION < 2
1184 relation_list = gtk_list_new();
1185 gtk_list_set_selection_mode(GTK_LIST(relation_list),
1186 GTK_SELECTION_BROWSE);
1188 l_store = gtk_list_store_new(1, G_TYPE_STRING);
1189 relation_list = tree_view_new(GTK_TREE_MODEL(l_store));
1190 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(relation_list), FALSE);
1191 g_object_unref(G_OBJECT(l_store));
1192 renderer = gtk_cell_renderer_text_new();
1193 column = gtk_tree_view_column_new_with_attributes("relation", renderer,
1195 gtk_tree_view_append_column(GTK_TREE_VIEW(relation_list), column);
1196 l_sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list));
1197 gtk_tree_selection_set_mode(l_sel, GTK_SELECTION_BROWSE);
1199 gtk_box_pack_start(GTK_BOX(col2_vb), relation_list, TRUE, TRUE, 0);
1201 range_label = gtk_label_new("Range (offset:length)");
1202 gtk_misc_set_alignment(GTK_MISC(range_label), 0.0, 0.0);
1203 gtk_box_pack_start(GTK_BOX(col2_vb), range_label, FALSE, FALSE, 0);
1205 range_entry = gtk_entry_new();
1206 gtk_box_pack_start(GTK_BOX(col2_vb), range_entry, FALSE, FALSE, 0);
1209 * OK, show the relation label and range stuff as it would be
1210 * with everything turned on, so it'll request as much space
1211 * as it'll ever need, so the dialog box and widgets start out
1212 * with the right sizes.
1214 * XXX - this doesn't work. It *doesn't* request as much space
1215 * as it'll ever need.
1217 * XXX - FT_UINT8 doesn't support ranges, so even if it did work,
1218 * it wouldn't work right.
1220 * XXX - this no longer affects the range stuff, as that's
1221 * controlled both by the type and by the relational operator
1224 show_relations(relation_list, FT_UINT8);
1225 gtk_widget_show(relation_label);
1226 gtk_widget_show(relation_list);
1228 value_vb = gtk_vbox_new(FALSE, 5);
1229 gtk_container_border_width(GTK_CONTAINER(value_vb), 5);
1230 gtk_container_add(GTK_CONTAINER(hb), value_vb);
1231 gtk_widget_show(value_vb);
1233 value_label = gtk_label_new("Value");
1234 gtk_misc_set_alignment(GTK_MISC(value_label), 0.0, 0.0);
1235 gtk_box_pack_start(GTK_BOX(value_vb), value_label, FALSE, FALSE, 0);
1236 gtk_widget_show(value_label);
1238 value_entry = gtk_entry_new();
1239 gtk_box_pack_start(GTK_BOX(value_vb), value_entry, FALSE, FALSE, 0);
1240 gtk_widget_show(value_entry);
1242 value_list_scrolled_win = gtk_scrolled_window_new(NULL, NULL);
1243 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(value_list_scrolled_win),
1244 GTK_POLICY_AUTOMATIC,
1245 GTK_POLICY_AUTOMATIC);
1246 gtk_box_pack_start(GTK_BOX(value_vb), value_list_scrolled_win, TRUE,
1248 gtk_widget_show(value_list_scrolled_win);
1250 #if GTK_MAJOR_VERSION < 2
1251 value_list = gtk_list_new();
1252 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(value_list_scrolled_win),
1254 SIGNAL_CONNECT(value_list, "select-child", value_list_sel_cb, value_entry);
1255 gtk_list_set_selection_mode(GTK_LIST(value_list), GTK_SELECTION_SINGLE);
1256 /* This remains hidden until an enumerated field is selected */
1259 * The value stuff may be hidden or shown depending on what
1260 * relation was selected; connect to the "select-child" signal
1261 * for the relation list, so we can make that happen.
1263 SIGNAL_CONNECT(relation_list, "select-child", relation_list_sel_cb, NULL);
1265 l_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
1266 value_list = tree_view_new(GTK_TREE_MODEL(l_store));
1267 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(value_list), FALSE);
1268 g_object_unref(G_OBJECT(l_store));
1269 renderer = gtk_cell_renderer_text_new();
1270 column = gtk_tree_view_column_new_with_attributes("value", renderer,
1272 gtk_tree_view_append_column(GTK_TREE_VIEW(value_list), column);
1273 SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list)),
1274 "changed", value_list_sel_cb, value_entry);
1277 * The value stuff may be hidden or shown depending on what
1278 * relation was selected; connect to the "changed" signal
1279 * for the relation list, so we can make that happen.
1281 SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list)),
1282 "changed", relation_list_sel_cb, NULL);
1283 l_sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list));
1284 gtk_tree_selection_set_mode(l_sel, GTK_SELECTION_SINGLE);
1285 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(value_list_scrolled_win),
1287 /* This remains hidden until an enumerated field is selected */
1291 * Put the items in the Tree; we don't want to do that until
1292 * we've constructed the value list and set the tree's
1293 * E_DFILTER_EXPR_VALUE_LIST_KEY data to point to it, and
1294 * constructed the "Accept" button and set the tree's
1295 * E_DFILTER_EXPR_ACCEPT_BT_KEY data to point to it, so that
1296 * when the list item is "helpfully" automatically selected for us
1297 * we're ready to cope with the selection signal.
1300 #if GTK_MAJOR_VERSION < 2
1301 /* a hash table seems excessive, but I don't see support for a
1302 sparse array in glib */
1303 proto_array = g_hash_table_new(g_direct_hash, g_direct_equal);
1304 for (i = proto_get_first_protocol(&cookie); i != -1;
1305 i = proto_get_next_protocol(&cookie)) {
1306 hfinfo = proto_registrar_get_nth(i);
1307 /* Create a node for the protocol, and remember it for
1309 name = proto_get_protocol_short_name(i); /* name, short_name or filter name ? */
1310 protocol_node = gtk_ctree_insert_node(GTK_CTREE(tree),
1313 NULL, NULL, NULL, NULL,
1315 gtk_ctree_node_set_row_data(GTK_CTREE(tree), protocol_node,
1317 g_hash_table_insert(proto_array, (gpointer)i, protocol_node);
1320 len = proto_registrar_n();
1321 for (i = 0; i < len; i++) {
1322 char *strp, str[TAG_STRING_LEN+1];
1325 * If this field is a protocol, skip it - we already put
1328 if (proto_registrar_is_protocol(i))
1331 hfinfo = proto_registrar_get_nth(i);
1334 * If this field isn't at the head of the list of
1335 * fields with this name, skip this field - all
1336 * fields with the same name are really just versions
1337 * of the same field stored in different bits, and
1338 * should have the same type/radix/value list, and
1339 * just differ in their bit masks. (If a field isn't
1340 * a bitfield, but can be, say, 1 or 2 bytes long,
1341 * it can just be made FT_UINT16, meaning the
1342 * *maximum* length is 2 bytes, and be used
1345 if (hfinfo->same_name_prev != NULL)
1348 /* Create a node for the item, and put it
1349 under its parent protocol. */
1350 protocol_node = g_hash_table_lookup(proto_array,
1351 GINT_TO_POINTER(proto_registrar_get_parent(i)));
1352 if (hfinfo->blurb != NULL && hfinfo->blurb[0] != '\0') {
1353 snprintf(str, TAG_STRING_LEN, "%s - %s (%s)", hfinfo->abbrev,
1354 hfinfo->name, hfinfo->blurb);
1356 snprintf(str, TAG_STRING_LEN, "%s - %s", hfinfo->abbrev,
1359 str[TAG_STRING_LEN]=0;
1361 item_node = gtk_ctree_insert_node(GTK_CTREE(tree),
1362 protocol_node, NULL,
1364 NULL, NULL, NULL, NULL,
1366 gtk_ctree_node_set_row_data(GTK_CTREE(tree),
1369 g_hash_table_destroy(proto_array);
1371 #else /* GTK_MAJOR_VERSION < 2 */
1373 /* GTK2 code using two levels iterator to enumerate all protocol fields */
1375 GtkTreeIter iter, child_iter;
1376 void *cookie, *cookie2;
1379 for (i = proto_get_first_protocol(&cookie); i != -1;
1380 i = proto_get_next_protocol(&cookie)) {
1381 char *strp, str[TAG_STRING_LEN+1];
1383 hfinfo = proto_registrar_get_nth(i);
1384 name = proto_get_protocol_short_name(i); /* name, short_name or filter name ? */
1386 gtk_tree_store_append(store, &iter, NULL);
1387 gtk_tree_store_set(store, &iter, 0, name, 1, hfinfo, -1);
1389 for (hfinfo = proto_get_first_protocol_field(i, &cookie2); hfinfo != NULL;
1390 hfinfo = proto_get_next_protocol_field(&cookie2)) {
1392 if (hfinfo->same_name_prev != NULL) /* ignore duplicate names */
1395 if (hfinfo->blurb != NULL && hfinfo->blurb[0] != '\0') {
1396 snprintf(str, TAG_STRING_LEN, "%s - %s (%s)",
1397 hfinfo->abbrev, hfinfo->name, hfinfo->blurb);
1399 snprintf(str, TAG_STRING_LEN, "%s - %s", hfinfo->abbrev,
1402 str[TAG_STRING_LEN]=0;
1404 gtk_tree_store_append(store, &child_iter, &iter);
1405 gtk_tree_store_set(store, &child_iter, 0, strp, 1, hfinfo, -1);
1408 g_object_unref(G_OBJECT(store));
1410 #endif /* GTK_MAJOR_VERSION < 2 */
1412 gtk_widget_show_all(tree);
1414 list_bb = gtk_hbutton_box_new();
1415 gtk_button_box_set_layout(GTK_BUTTON_BOX(list_bb), GTK_BUTTONBOX_START);
1416 gtk_button_box_set_spacing(GTK_BUTTON_BOX(list_bb), 5);
1417 gtk_container_add(GTK_CONTAINER(main_vb), list_bb);
1418 gtk_widget_show(list_bb);
1420 #if GTK_MAJOR_VERSION < 2
1421 accept_bt = gtk_button_new_with_label("Accept");
1423 accept_bt = gtk_button_new_from_stock(GTK_STOCK_OK);
1425 gtk_widget_set_sensitive(accept_bt, FALSE);
1426 SIGNAL_CONNECT(accept_bt, "clicked", dfilter_expr_dlg_accept_cb, filter_te);
1427 GTK_WIDGET_SET_FLAGS(accept_bt, GTK_CAN_DEFAULT);
1428 alignment = gtk_alignment_new(0.0, 0.5, 1.0, 0.0);
1429 gtk_container_add(GTK_CONTAINER(alignment), accept_bt);
1430 gtk_box_pack_start(GTK_BOX(list_bb), alignment, TRUE, TRUE, 0);
1431 gtk_widget_grab_default(accept_bt);
1432 gtk_widget_show(accept_bt);
1433 gtk_widget_show(alignment);
1435 #if GTK_MAJOR_VERSION < 2
1436 close_bt = gtk_button_new_with_label("Close");
1438 close_bt = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1440 SIGNAL_CONNECT(close_bt, "clicked", dfilter_expr_dlg_cancel_cb, window);
1441 alignment = gtk_alignment_new(0.0, 0.5, 1.0, 0.0);
1442 gtk_container_add(GTK_CONTAINER(alignment), close_bt);
1443 gtk_box_pack_start(GTK_BOX(list_bb), alignment, TRUE, TRUE, 0);
1444 gtk_widget_show(close_bt);
1445 gtk_widget_show(alignment);
1447 /* Catch the "activate" signal on the range and value text entries,
1448 so that if the user types Return there, we act as if the "Accept"
1449 button had been selected, as happens if Return is typed if some
1450 widget that *doesn't* handle the Return key has the input focus. */
1451 dlg_set_activate(range_entry, accept_bt);
1452 dlg_set_activate(value_entry, accept_bt);
1455 * Catch the "key_press_event" signal in the window, so that we can
1456 * catch the ESC key being pressed and act as if the "Close" button
1457 * had been selected.
1459 dlg_set_cancel(window, close_bt);
1461 OBJECT_SET_DATA(window, E_DFILTER_EXPR_RELATION_LIST_KEY, relation_list);
1462 OBJECT_SET_DATA(window, E_DFILTER_EXPR_RANGE_LABEL_KEY, range_label);
1463 OBJECT_SET_DATA(window, E_DFILTER_EXPR_RANGE_ENTRY_KEY, range_entry);
1464 OBJECT_SET_DATA(window, E_DFILTER_EXPR_VALUE_LABEL_KEY, value_label);
1465 OBJECT_SET_DATA(window, E_DFILTER_EXPR_VALUE_ENTRY_KEY, value_entry);
1466 OBJECT_SET_DATA(window, E_DFILTER_EXPR_VALUE_LIST_KEY, value_list);
1467 OBJECT_SET_DATA(window, E_DFILTER_EXPR_VALUE_LIST_SW_KEY,
1468 value_list_scrolled_win);
1469 OBJECT_SET_DATA(window, E_DFILTER_EXPR_ACCEPT_BT_KEY, accept_bt);
1471 #if GTK_MAJOR_VERSION < 2
1473 * OK, we've finally built the entire list, complete with the row data,
1474 * and attached to the top-level widget pointers to the relevant
1475 * subwidgets, so it's safe to put the list in browse mode.
1477 gtk_clist_set_selection_mode (GTK_CLIST(tree),
1478 GTK_SELECTION_BROWSE);
1482 * Catch the "destroy" signal on our top-level window, and,
1483 * when it's destroyed, disconnect the signal we'll be
1486 SIGNAL_CONNECT(window, "destroy", dfilter_expr_dlg_destroy_cb, filter_te);
1489 * Catch the "destroy" signal on the text entry widget to which
1490 * we're attached; if it's destroyed, we should destroy ourselves
1493 SIGNAL_CONNECT(filter_te, "destroy", dfilter_expr_dlg_cancel_cb, window);
1495 gtk_widget_show(window);