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>
12 * Wireshark - Network traffic analyzer
13 * By Gerald Combs <gerald@wireshark.org>
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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
52 #include "gui_utils.h"
53 #include "simple_dialog.h"
54 #include "dlg_utils.h"
55 #include "proto_dlg.h"
56 #include "filter_dlg.h"
57 #include "dfilter_expr_dlg.h"
58 #include "compat_macros.h"
60 #define E_DFILTER_EXPR_TREE_KEY "dfilter_expr_tree"
61 #define E_DFILTER_EXPR_CURRENT_VAR_KEY "dfilter_expr_current_var"
62 #define E_DFILTER_EXPR_RELATION_LIST_KEY "dfilter_expr_relation_list"
63 #define E_DFILTER_EXPR_RANGE_LABEL_KEY "dfilter_expr_range_label"
64 #define E_DFILTER_EXPR_RANGE_ENTRY_KEY "dfilter_expr_range_entry"
65 #define E_DFILTER_EXPR_VALUE_LABEL_KEY "dfilter_expr_value_label"
66 #define E_DFILTER_EXPR_VALUE_ENTRY_KEY "dfilter_expr_value_entry"
67 #define E_DFILTER_EXPR_VALUE_LIST_LABEL_KEY "dfilter_expr_value_list_label"
68 #define E_DFILTER_EXPR_VALUE_LIST_KEY "dfilter_expr_value_list"
69 #define E_DFILTER_EXPR_VALUE_LIST_SW_KEY "dfilter_expr_value_list_sw"
70 #define E_DFILTER_EXPR_OK_BT_KEY "dfilter_expr_accept_bt"
71 #define E_DFILTER_EXPR_VALUE_KEY "dfilter_expr_value"
73 typedef struct protocol_data {
78 static void show_relations(GtkWidget *relation_list, ftenum_t ftype);
79 static gboolean relation_is_presence_test(const char *string);
80 static void add_relation_list(GtkWidget *relation_list, const char *relation, gboolean sensitive);
81 static void build_boolean_values(GtkWidget *value_list_scrolled_win,
82 GtkWidget *value_list,
83 const true_false_string *values);
84 static void build_enum_values(GtkWidget *value_list_scrolled_win,
85 GtkWidget *value_list,
86 const value_string *values);
87 static void add_value_list_item(GtkWidget *value_list, const gchar *string,
89 static void display_value_fields(header_field_info *hfinfo,
90 gboolean is_comparison, GtkWidget *value_label,
91 GtkWidget *value_entry,
92 GtkWidget *value_list_label, GtkWidget *value_list,
93 GtkWidget *value_list_scrolled_win,
94 GtkWidget *range_label,
95 GtkWidget *range_entry);
98 * Note that this is called every time the user clicks on an item,
99 * whether it is already selected or not.
101 #if GTK_MAJOR_VERSION < 2
103 field_select_row_cb(GtkWidget *tree, GList *node, gint column _U_,
104 gpointer user_data _U_)
107 field_select_row_cb(GtkTreeSelection *sel, gpointer tree)
110 GtkWidget *window = gtk_widget_get_toplevel(tree);
111 GtkWidget *relation_list = OBJECT_GET_DATA(window,
112 E_DFILTER_EXPR_RELATION_LIST_KEY);
113 GtkWidget *range_label = OBJECT_GET_DATA(window,
114 E_DFILTER_EXPR_RANGE_LABEL_KEY);
115 GtkWidget *range_entry = OBJECT_GET_DATA(window,
116 E_DFILTER_EXPR_RANGE_ENTRY_KEY);
117 GtkWidget *value_label = OBJECT_GET_DATA(window,
118 E_DFILTER_EXPR_VALUE_LABEL_KEY);
119 GtkWidget *value_entry = OBJECT_GET_DATA(window,
120 E_DFILTER_EXPR_VALUE_ENTRY_KEY);
121 GtkWidget *value_list_label = OBJECT_GET_DATA(window,
122 E_DFILTER_EXPR_VALUE_LIST_LABEL_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 *ok_bt = OBJECT_GET_DATA(window,
128 E_DFILTER_EXPR_OK_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 g_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_label, 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(ok_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", TRUE);
263 add_relation_list(relation_list, "==",
264 ftype_can_eq(ftype) || (ftype_can_slice(ftype) && ftype_can_eq(FT_BYTES)));
265 add_relation_list(relation_list, "!=",
266 ftype_can_ne(ftype) || (ftype_can_slice(ftype) && ftype_can_ne(FT_BYTES)));
267 add_relation_list(relation_list, ">",
268 ftype_can_gt(ftype) || (ftype_can_slice(ftype) && ftype_can_gt(FT_BYTES)));
270 add_relation_list(relation_list, "<",
271 ftype_can_lt(ftype) || (ftype_can_slice(ftype) && ftype_can_lt(FT_BYTES)));
272 add_relation_list(relation_list, ">=",
273 ftype_can_ge(ftype) || (ftype_can_slice(ftype) && ftype_can_ge(FT_BYTES)));
274 add_relation_list(relation_list, "<=",
275 ftype_can_le(ftype) || (ftype_can_slice(ftype) && ftype_can_le(FT_BYTES)));
276 add_relation_list(relation_list, "contains",
277 ftype_can_contains(ftype) || (ftype_can_slice(ftype) && ftype_can_contains(FT_BYTES)));
279 add_relation_list(relation_list, "matches",
280 ftype_can_matches(ftype) || (ftype_can_slice(ftype) && ftype_can_matches(FT_BYTES)));
283 #if GTK_MAJOR_VERSION >= 2
284 gtk_tree_model_get_iter_first(gtk_tree_view_get_model(GTK_TREE_VIEW(relation_list)), &iter);
285 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list)), &iter);
290 * Given a string that represents a test to be made on a field, returns
291 * TRUE if it tests for the field's presence, FALSE otherwise.
294 relation_is_presence_test(const char *string)
296 return (strcmp(string, "is present") == 0);
300 add_relation_list(GtkWidget *relation_list, const char *relation, gboolean sensitive)
302 #if GTK_MAJOR_VERSION < 2
303 GtkWidget *label, *item;
305 label = gtk_label_new(relation);
306 item = gtk_list_item_new();
308 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
309 gtk_container_add(GTK_CONTAINER(item), label);
310 gtk_widget_show(label);
311 gtk_container_add(GTK_CONTAINER(relation_list), item);
312 gtk_widget_show(item);
313 gtk_widget_set_sensitive(item, sensitive);
315 GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(relation_list)));
318 /* XXX: I currently see no way to insensitive the item,
319 * so for a first step, just don't show it (as before these changes :-) */
324 gtk_list_store_append(store, &iter);
325 gtk_list_store_set(store, &iter, 0, relation, -1);
329 #if GTK_MAJOR_VERSION < 2
331 relation_list_sel_cb(GtkList *relation_list, GtkWidget *child _U_,
332 gpointer user_data _U_)
335 relation_list_sel_cb(GtkTreeSelection *sel, gpointer user_data _U_)
338 #if GTK_MAJOR_VERSION < 2
339 GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(relation_list));
341 GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(gtk_tree_selection_get_tree_view(sel)));
343 GtkWidget *range_label =
344 OBJECT_GET_DATA(window, E_DFILTER_EXPR_RANGE_LABEL_KEY);
345 GtkWidget *range_entry =
346 OBJECT_GET_DATA(window, E_DFILTER_EXPR_RANGE_ENTRY_KEY);
347 GtkWidget *value_label =
348 OBJECT_GET_DATA(window, E_DFILTER_EXPR_VALUE_LABEL_KEY);
349 GtkWidget *value_entry =
350 OBJECT_GET_DATA(window, E_DFILTER_EXPR_VALUE_ENTRY_KEY);
351 GtkWidget *value_list_label =
352 OBJECT_GET_DATA(window, E_DFILTER_EXPR_VALUE_LIST_LABEL_KEY);
353 GtkWidget *value_list =
354 OBJECT_GET_DATA(window, E_DFILTER_EXPR_VALUE_LIST_KEY);
355 GtkWidget *value_list_scrolled_win =
356 OBJECT_GET_DATA(window, E_DFILTER_EXPR_VALUE_LIST_SW_KEY);
357 header_field_info *hfinfo =
358 OBJECT_GET_DATA(window, E_DFILTER_EXPR_CURRENT_VAR_KEY);
360 #if GTK_MAJOR_VERSION < 2
362 GtkWidget *item, *item_label;
365 * What's the relation?
367 sl = GTK_LIST(relation_list)->selection;
368 item = GTK_WIDGET(sl->data);
369 item_label = GTK_BIN(item)->child;
370 gtk_label_get(GTK_LABEL(item_label), &item_str);
376 * What's the relation?
378 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
380 gtk_tree_model_get(model, &iter, 0, &item_str, -1);
384 * Update the display of various items for the value, as appropriate.
386 display_value_fields(hfinfo,
387 !relation_is_presence_test(item_str),
388 value_label, value_entry, value_list_label, value_list,
389 value_list_scrolled_win, range_label, range_entry);
390 #if GTK_MAJOR_VERSION >= 2
396 build_boolean_values(GtkWidget *value_list_scrolled_win, GtkWidget *value_list,
397 const true_false_string *values)
399 static const true_false_string true_false = { "True", "False" };
400 #if GTK_MAJOR_VERSION >= 2
401 GtkTreeSelection *sel;
404 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list));
408 * Clear out the items for the list, and put in the names
409 * from the value_string list.
411 #if GTK_MAJOR_VERSION < 2
412 gtk_list_clear_items(GTK_LIST(value_list), 0, -1);
414 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
418 * Put the list in single mode, so we don't get any selection
419 * events while we're building it (i.e., so we don't get any
420 * on a list item BEFORE WE GET TO SET THE DATA FOR THE LIST
421 * ITEM SO THAT THE HANDLER CAN HANDLE IT).
423 #if GTK_MAJOR_VERSION < 2
424 gtk_list_set_selection_mode(GTK_LIST(value_list), GTK_SELECTION_SINGLE);
426 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
433 values = &true_false;
434 add_value_list_item(value_list, values->true_string, (const gpointer) values);
435 add_value_list_item(value_list, values->false_string, NULL);
438 * OK, we're done, so we can finally put it in browse mode.
439 * Select the first item, so that the user doesn't have to, under
440 * the assumption that they're most likely to test if something
441 * is true, not false.
443 #if GTK_MAJOR_VERSION < 2
444 gtk_list_set_selection_mode(GTK_LIST(value_list), GTK_SELECTION_BROWSE);
445 gtk_list_select_item(GTK_LIST(value_list), 0);
447 gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
448 gtk_tree_model_get_iter_first(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list)), &iter);
449 gtk_tree_selection_select_iter(sel, &iter);
452 gtk_widget_show_all(value_list_scrolled_win);
456 build_enum_values(GtkWidget *value_list_scrolled_win _U_, GtkWidget *value_list,
457 const value_string *values)
459 #if GTK_MAJOR_VERSION >= 2
460 GtkTreeSelection *sel;
462 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list));
465 * Clear out the items for the list, and put in the names
466 * from the value_string list.
468 #if GTK_MAJOR_VERSION < 2
469 gtk_list_clear_items(GTK_LIST(value_list), 0, -1);
471 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
475 * Put the list in single mode, so we don't get any selection
476 * events while we're building it (i.e., so we don't get any
477 * on a list item BEFORE WE GET TO SET THE DATA FOR THE LIST
478 * ITEM SO THAT THE HANDLER CAN HANDLE IT).
480 #if GTK_MAJOR_VERSION < 2
481 gtk_list_set_selection_mode(GTK_LIST(value_list), GTK_SELECTION_SINGLE);
483 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
489 while (values->strptr != NULL) {
490 add_value_list_item(value_list, values->strptr,
491 (const gpointer) values);
496 * OK, we're done, so we can finally put it in browse mode.
498 #if GTK_MAJOR_VERSION < 2
499 gtk_list_set_selection_mode(GTK_LIST(value_list), GTK_SELECTION_BROWSE);
501 gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
506 add_value_list_item(GtkWidget *value_list, const gchar *string, const gpointer data)
508 #if GTK_MAJOR_VERSION < 2
509 GtkWidget *label, *item;
511 label = gtk_label_new(string);
512 item = gtk_list_item_new();
514 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
515 gtk_container_add(GTK_CONTAINER(item), label);
516 gtk_widget_show(label);
517 gtk_container_add(GTK_CONTAINER(value_list), item);
518 OBJECT_SET_DATA(item, E_DFILTER_EXPR_VALUE_KEY, data);
519 gtk_widget_show(item);
521 GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list)));
524 gtk_list_store_append(store, &iter);
525 gtk_list_store_set(store, &iter, 0, string, 1, data, -1);
530 * Show or hide the various values fields as appropriate for the field
531 * and currently-selected relation.
534 display_value_fields(header_field_info *hfinfo, gboolean is_comparison,
535 GtkWidget *value_label, GtkWidget *value_entry,
536 GtkWidget *value_list_label,
537 GtkWidget *value_list _U_,
538 GtkWidget *value_list_scrolled_win, GtkWidget *range_label,
539 GtkWidget *range_entry)
541 gboolean show_value_label = FALSE;
542 gboolean show_value_list = FALSE;
543 gboolean show_range = FALSE;
548 * this is an FT_NONE variable, in which case you can
549 * only check whether it's present or absent in the
554 * this is a Boolean variable, in which case you
555 * can't specify a value to compare with, you can
556 * only specify whether to test for the Boolean
557 * being true or to test for it being false
561 * this isn't a Boolean variable, in which case you
562 * can test for its presence in the protocol tree,
563 * and the default relation is such a test, in
564 * which case you don't compare with a value
566 * so we hide the value entry.
568 show_value_list = is_comparison;
571 * If we're showing the entry; show the label as well.
573 show_value_label = TRUE;
576 switch (hfinfo->type) {
579 show_value_list = is_comparison;
582 * If we're showing the value list; show the label as well.
584 show_value_label = TRUE;
596 if (hfinfo->strings != NULL) {
598 * We have a list of values to show.
601 show_value_list = is_comparison;
604 * We're showing the entry; show the label
607 show_value_label = TRUE;
611 * There is no list of names for values, so don't
614 show_value_list = FALSE;
620 * There is no list of names for values; hide the list.
622 show_value_list = FALSE;
626 gtk_widget_set_sensitive(value_label, show_value_label);
627 gtk_widget_set_sensitive(value_entry, show_value_label);
629 gtk_widget_set_sensitive(value_list_label, show_value_list);
630 gtk_widget_set_sensitive(value_list_scrolled_win, show_value_list);
633 * Is this a comparison, and are ranges supported by this type?
634 * If both are true, show the range stuff, otherwise hide it.
636 show_range = (is_comparison && ftype_can_slice(hfinfo->type));
637 gtk_widget_set_sensitive(range_label, show_range);
638 gtk_widget_set_sensitive(range_entry, show_range);
641 #if GTK_MAJOR_VERSION < 2
643 value_list_sel_cb(GtkList *value_list, GtkWidget *child,
644 gpointer value_entry_arg)
647 value_list_sel_cb(GtkTreeSelection *sel, gpointer value_entry_arg)
650 GtkWidget *value_entry = value_entry_arg;
651 #if GTK_MAJOR_VERSION < 2
652 GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(value_list));
654 GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(gtk_tree_selection_get_tree_view(sel)));
658 header_field_info *hfinfo = OBJECT_GET_DATA(window,
659 E_DFILTER_EXPR_CURRENT_VAR_KEY);
660 const value_string *value = NULL;
661 char value_string[11+1]; /* long enough for 32-bit octal value */
663 #if GTK_MAJOR_VERSION < 2
664 value = OBJECT_GET_DATA(child, E_DFILTER_EXPR_VALUE_KEY);
666 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
668 gtk_tree_model_get(model, &iter, 1, &value, -1);
672 * This should either be a numeric type or a Boolean type.
674 if (hfinfo->type == FT_BOOLEAN) {
676 * Boolean type; if the value key for the selected item
677 * is non-null, it's the item for "true", otherwise it's
678 * the item for "false". Compare with 1 if we're
679 * testing for "true", and compare with 0 if we're
680 * testing for "false".
683 strcpy(value_string, "1");
685 strcpy(value_string, "0");
688 * Numeric type; get the value corresponding to the
689 * selected item, and display it in the base for this
692 switch (hfinfo->display) {
695 switch (hfinfo->type) {
701 g_snprintf(value_string, sizeof value_string,
709 g_snprintf(value_string, sizeof value_string,
714 g_assert_not_reached();
719 g_snprintf(value_string, sizeof value_string, "0x%x",
724 g_snprintf(value_string, sizeof value_string, "%#o",
729 g_assert_not_reached();
732 gtk_entry_set_text(GTK_ENTRY(value_entry), value_string);
736 dfilter_report_bad_value(const char *format, ...)
738 char error_msg_buf[1024];
741 va_start(args, format);
742 g_vsnprintf(error_msg_buf, sizeof error_msg_buf, format, args);
745 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_msg_buf);
749 dfilter_expr_dlg_accept_cb(GtkWidget *w, gpointer filter_te_arg)
751 GtkWidget *filter_te = filter_te_arg;
752 GtkWidget *window = gtk_widget_get_toplevel(w);
753 GtkWidget *relation_list =
754 OBJECT_GET_DATA(window, E_DFILTER_EXPR_RELATION_LIST_KEY);
755 GtkWidget *range_entry =
756 OBJECT_GET_DATA(window, E_DFILTER_EXPR_RANGE_ENTRY_KEY);
757 GtkWidget *value_entry =
758 OBJECT_GET_DATA(window, E_DFILTER_EXPR_VALUE_ENTRY_KEY);
759 header_field_info *hfinfo;
761 gchar *range_str, *stripped_range_str;
762 gchar *value_str, *stripped_value_str;
766 gboolean can_compare;
768 #if GTK_MAJOR_VERSION < 2
770 GtkWidget *item, *item_label;
778 * Get the variable to be tested.
780 hfinfo = OBJECT_GET_DATA(window, E_DFILTER_EXPR_CURRENT_VAR_KEY);
783 * Get the relation operator to use.
785 #if GTK_MAJOR_VERSION < 2
786 sl = GTK_LIST(relation_list)->selection;
787 item = GTK_WIDGET(sl->data);
788 item_label = GTK_BIN(item)->child;
789 gtk_label_get(GTK_LABEL(item_label), &item_str);
791 if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list)),
793 gtk_tree_model_get(model, &iter, 0, &item_str, -1);
798 * Get the range to use, if any.
800 if (GTK_WIDGET_SENSITIVE(range_entry)) {
801 range_str = g_strdup(gtk_entry_get_text(GTK_ENTRY(range_entry)));
803 * XXX - strip this even for strings?
804 * Doing so for strings mean you can't match a string that has
805 * leading or trailing whitespace, but you can't see trailing
806 * whitespace in a text field, so it's not clear that it's
807 * a good idea to allow that.
809 stripped_range_str = g_strstrip(range_str);
810 if (strcmp(stripped_range_str, "") == 0) {
812 * No range was specified.
816 stripped_range_str = NULL;
820 * XXX - check it for validity?
824 stripped_range_str = NULL;
828 * If a range was specified, the type of the LHS of the
829 * comparison is FT_BYTES; otherwise, it's the type of the field.
831 if (range_str == NULL)
832 ftype = hfinfo->type;
837 * Make sure the relation is valid for the type in question.
838 * We may be offering relations that the type of the field
839 * can't support, because the field's type supports slicing,
840 * and the relation *is* supported on byte strings.
842 if (strcmp(item_str, "==") == 0)
843 can_compare = ftype_can_eq(ftype);
844 else if (strcmp(item_str, "!=") == 0)
845 can_compare = ftype_can_ne(ftype);
846 else if (strcmp(item_str, ">") == 0)
847 can_compare = ftype_can_gt(ftype);
848 else if (strcmp(item_str, "<") == 0)
849 can_compare = ftype_can_lt(ftype);
850 else if (strcmp(item_str, ">=") == 0)
851 can_compare = ftype_can_ge(ftype);
852 else if (strcmp(item_str, "<=") == 0)
853 can_compare = ftype_can_le(ftype);
854 else if (strcmp(item_str, "contains") == 0)
855 can_compare = ftype_can_contains(ftype);
856 else if (strcmp(item_str, "matches") == 0)
857 can_compare = ftype_can_matches(ftype);
859 can_compare = TRUE; /* not a comparison */
861 if (range_str == NULL) {
862 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
863 "That field can't be tested with \"%s\".",
866 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
867 "Ranges of that field can't be tested with \"%s\".",
870 if (range_str != NULL)
876 * Get the value to use, if any.
878 if (GTK_WIDGET_SENSITIVE(value_entry)) {
879 value_str = g_strdup(gtk_entry_get_text(GTK_ENTRY(value_entry)));
880 stripped_value_str = g_strstrip(value_str);
881 if (strcmp(stripped_value_str, "") == 0) {
883 * This field takes a value, but they didn't supply
886 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
887 "That field must be compared with a value, "
888 "but you didn't specify a value with which to "
890 if (range_str != NULL)
897 * Make sure the value is valid.
899 * If no range string was specified, it must be valid
900 * for the type of the field; if a range string was
901 * specified, must be valid for FT_BYTES.
903 if (strcmp(item_str, "contains") == 0) {
904 fvalue = fvalue_from_unparsed(ftype, stripped_value_str, TRUE,
905 dfilter_report_bad_value);
908 fvalue = fvalue_from_unparsed(ftype, stripped_value_str, FALSE,
909 dfilter_report_bad_value);
911 if (fvalue == NULL) {
915 * The dialog box was already popped up by
916 * "dfilter_report_bad_value()".
918 if (range_str != NULL)
926 stripped_value_str = NULL;
930 * Insert the expression at the current cursor position.
931 * If there's a non-whitespace character to the left of it,
932 * insert a blank first; if there's a non-whitespace character
933 * to the right of it, insert a blank after it.
935 pos = gtk_editable_get_position(GTK_EDITABLE(filter_te));
936 chars = gtk_editable_get_chars(GTK_EDITABLE(filter_te), pos, pos + 1);
937 if (strcmp(chars, "") != 0 && !isspace((unsigned char)chars[0]))
938 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
941 gtk_editable_insert_text(GTK_EDITABLE(filter_te), hfinfo->abbrev,
942 strlen(hfinfo->abbrev), &pos);
943 if (range_str != NULL) {
944 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "[", 1, &pos);
945 gtk_editable_insert_text(GTK_EDITABLE(filter_te),
946 stripped_range_str, strlen(stripped_range_str), &pos);
947 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "]", 1, &pos);
950 if (item_str != NULL && !relation_is_presence_test(item_str)) {
951 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
952 gtk_editable_insert_text(GTK_EDITABLE(filter_te), item_str,
953 strlen(item_str), &pos);
955 if (value_str != NULL) {
956 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
958 * XXX - we should do this by generating an appropriate display
959 * filter value string for this field; that requires us to have
960 * a "generate display filter string" method for every FT_ type.
962 switch (hfinfo->type) {
967 case FT_ABSOLUTE_TIME:
969 * Always put quotes around the string.
976 * If the string contains white space, put quotes around it.
978 quote_it = (strpbrk(stripped_value_str, " \t") != NULL);
983 * Put quotes around the string.
985 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "\"",
988 gtk_editable_insert_text(GTK_EDITABLE(filter_te),
989 stripped_value_str, strlen(stripped_value_str), &pos);
992 * Put quotes around the string.
994 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "\"",
999 chars = gtk_editable_get_chars(GTK_EDITABLE(filter_te), pos + 1, pos + 2);
1000 if (strcmp(chars, "") != 0 && !isspace((unsigned char)chars[0]))
1001 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
1005 * Put the cursor after the expression we just entered into
1006 * the text entry widget.
1008 gtk_editable_set_position(GTK_EDITABLE(filter_te), pos);
1011 * We're done; destroy the dialog box (which is the top-level
1012 * widget for the "Accept" button).
1014 window_destroy(window);
1015 #if GTK_MAJOR_VERSION >= 2
1021 dfilter_expr_dlg_cancel_cb(GtkWidget *w _U_, gpointer parent_w)
1024 * User pressed the cancel button; close the dialog box.
1026 window_destroy(GTK_WIDGET(parent_w));
1029 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()" */
1031 dfilter_expr_dlg_delete_event_cb(GtkWidget *w _U_, GdkEvent *event _U_,
1034 dfilter_expr_dlg_cancel_cb(NULL, parent_w);
1039 dfilter_expr_dlg_destroy_cb(GtkWidget *w, gpointer filter_te)
1042 * The dialog box is being destroyed; disconnect from the
1043 * "destroy" signal on the text entry box to which we're
1044 * attached, as the handler for that signal is supposed
1045 * to destroy us, but we're already gone.
1047 SIGNAL_DISCONNECT_BY_FUNC(filter_te, dfilter_expr_dlg_cancel_cb, w);
1051 * Length of string used for protocol fields.
1053 #define TAG_STRING_LEN 256
1056 dfilter_expr_dlg_new(GtkWidget *filter_te)
1058 GtkWidget *window, *main_vb, *main_hb;
1060 GtkWidget *field_vb, *field_tree_lb, *field_tree, *tree_scrolled_win;
1062 GtkWidget *relation_vb, *relation_label, *relation_list, *relation_list_scrolled_win;
1063 /* GtkWidget *relation_present_rb, *relation_equals_rb, *relation_unequals_rb,
1064 *relation_greater_rb, *relation_less_rb,
1065 *relation_greaterequal_rb, *relation_lessequal_rb,
1066 *relation_contains_rb, *relation_matches_rb;*/
1068 GtkWidget *value_vb, *value_label, *value_entry;
1069 GtkWidget *value_list_label, *value_list_scrolled_win, *value_list;
1070 GtkWidget *range_label, *range_entry;
1072 GtkWidget *list_bb, *ok_bt, *cancel_bt;
1073 header_field_info *hfinfo;
1075 protocol_t *protocol;
1076 #if GTK_MAJOR_VERSION < 2
1080 GHashTable *proto_array;
1081 GtkCTreeNode *protocol_node, *item_node;
1083 GtkTreeStore *store;
1084 GtkTreeSelection *selection;
1085 GtkCellRenderer *renderer;
1086 GtkTreeViewColumn *column;
1087 GtkListStore *l_store;
1088 GtkTreeSelection *l_sel;
1091 window = dlg_window_new("Wireshark: Filter Expression");
1092 gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
1093 gtk_container_set_border_width(GTK_CONTAINER(window), 5);
1095 main_vb = gtk_vbox_new(FALSE, 5);
1096 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1097 gtk_container_add(GTK_CONTAINER(window), main_vb);
1099 main_hb = gtk_hbox_new(FALSE, 5);
1100 gtk_container_border_width(GTK_CONTAINER(main_hb), 5);
1101 gtk_container_add(GTK_CONTAINER(main_vb), main_hb);
1103 field_vb = gtk_vbox_new(FALSE, 5);
1104 gtk_container_border_width(GTK_CONTAINER(field_vb), 5);
1105 gtk_container_add(GTK_CONTAINER(main_hb), field_vb);
1107 field_tree_lb = gtk_label_new("Field name");
1108 gtk_misc_set_alignment(GTK_MISC(field_tree_lb), 0.0, 0.0);
1109 gtk_box_pack_start(GTK_BOX(field_vb), field_tree_lb, FALSE, FALSE, 0);
1111 tree_scrolled_win = scrolled_window_new(NULL, NULL);
1112 #if GTK_MAJOR_VERSION >= 2
1113 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(tree_scrolled_win),
1116 gtk_box_pack_start(GTK_BOX(field_vb), tree_scrolled_win, TRUE, TRUE, 0);
1117 WIDGET_SET_SIZE(tree_scrolled_win, 300, -1);
1120 #if GTK_MAJOR_VERSION < 2
1121 field_tree = ctree_new(1, 0);
1122 SIGNAL_CONNECT(field_tree, "tree-select-row", field_select_row_cb, field_tree);
1124 store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
1125 field_tree = tree_view_new(GTK_TREE_MODEL(store));
1126 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(field_tree), FALSE);
1127 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(field_tree));
1128 gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
1129 renderer = gtk_cell_renderer_text_new();
1130 column = gtk_tree_view_column_new_with_attributes("Field name", renderer,
1132 gtk_tree_view_append_column(GTK_TREE_VIEW(field_tree), column);
1133 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1134 gtk_tree_view_column_set_sort_column_id(column, 0);
1135 SIGNAL_CONNECT(selection, "changed", field_select_row_cb, field_tree);
1137 gtk_container_add(GTK_CONTAINER(tree_scrolled_win), field_tree);
1139 #if GTK_MAJOR_VERSION < 2
1141 * GTK's annoying CTree widget will deliver a selection event
1142 * the instant you add an item to the field_tree, *the fact that you
1143 * haven't even had time to set the item's row data nonwithstanding*.
1145 * We'll put the widget into GTK_SELECTION_SINGLE mode in the
1146 * hopes that it's *STOP DOING THAT*.
1148 gtk_clist_set_selection_mode(GTK_CLIST(field_tree),
1149 GTK_SELECTION_SINGLE);
1152 relation_vb = gtk_vbox_new(FALSE, 5);
1153 gtk_container_border_width(GTK_CONTAINER(relation_vb), 5);
1154 gtk_container_add(GTK_CONTAINER(main_hb), relation_vb);
1156 relation_label = gtk_label_new("Relation");
1157 gtk_misc_set_alignment(GTK_MISC(relation_label), 0.0, 0.0);
1158 gtk_box_pack_start(GTK_BOX(relation_vb), relation_label, FALSE, FALSE, 0);
1160 relation_list_scrolled_win = scrolled_window_new(NULL, NULL);
1161 /* never use a scrollbar in x direction, show the complete relation string */
1162 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(relation_list_scrolled_win),
1163 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1164 #if GTK_MAJOR_VERSION >= 2
1165 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(relation_list_scrolled_win),
1169 #if GTK_MAJOR_VERSION < 2
1170 relation_list = gtk_list_new();
1171 gtk_list_set_selection_mode(GTK_LIST(relation_list),
1172 GTK_SELECTION_BROWSE);
1174 l_store = gtk_list_store_new(1, G_TYPE_STRING);
1175 relation_list = tree_view_new(GTK_TREE_MODEL(l_store));
1176 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(relation_list), FALSE);
1177 g_object_unref(G_OBJECT(l_store));
1178 renderer = gtk_cell_renderer_text_new();
1179 column = gtk_tree_view_column_new_with_attributes("relation", renderer,
1181 gtk_tree_view_append_column(GTK_TREE_VIEW(relation_list), column);
1182 l_sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list));
1183 gtk_tree_selection_set_mode(l_sel, GTK_SELECTION_BROWSE);
1185 #if GTK_MAJOR_VERSION < 2
1186 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(relation_list_scrolled_win),
1189 gtk_container_add(GTK_CONTAINER(relation_list_scrolled_win), relation_list);
1191 gtk_box_pack_start(GTK_BOX(relation_vb), relation_list_scrolled_win, TRUE, TRUE, 0);
1194 * OK, show the relation label and range stuff as it would be
1195 * with everything turned on, so it'll request as much space
1196 * as it'll ever need, so the dialog box and widgets start out
1197 * with the right sizes.
1199 * XXX - this doesn't work. It *doesn't* request as much space
1200 * as it'll ever need.
1202 * XXX - FT_UINT8 doesn't support ranges, so even if it did work,
1203 * it wouldn't work right.
1205 * XXX - this no longer affects the range stuff, as that's
1206 * controlled both by the type and by the relational operator
1209 show_relations(relation_list, FT_UINT8);
1212 relation_present_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL, "is present", NULL);
1213 gtk_box_pack_start(GTK_BOX(relation_vb), relation_present_rb, FALSE, FALSE, 0);
1215 relation_equals_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(relation_present_rb, "==", NULL);
1216 gtk_box_pack_start(GTK_BOX(relation_vb), relation_equals_rb, FALSE, FALSE, 0);
1218 relation_unequals_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(relation_present_rb, "!=", NULL);
1219 gtk_box_pack_start(GTK_BOX(relation_vb), relation_unequals_rb, FALSE, FALSE, 0);
1221 relation_greater_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(relation_present_rb, ">", NULL);
1222 gtk_box_pack_start(GTK_BOX(relation_vb), relation_greater_rb, FALSE, FALSE, 0);
1224 relation_less_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(relation_present_rb, "<", NULL);
1225 gtk_box_pack_start(GTK_BOX(relation_vb), relation_less_rb, FALSE, FALSE, 0);
1227 relation_greaterequal_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(relation_present_rb, ">=", NULL);
1228 gtk_box_pack_start(GTK_BOX(relation_vb), relation_greaterequal_rb, FALSE, FALSE, 0);
1230 relation_lessequal_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(relation_present_rb, "<=", NULL);
1231 gtk_box_pack_start(GTK_BOX(relation_vb), relation_lessequal_rb, FALSE, FALSE, 0);
1233 relation_contains_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(relation_present_rb, "contains", NULL);
1234 gtk_box_pack_start(GTK_BOX(relation_vb), relation_contains_rb, FALSE, FALSE, 0);
1236 relation_matches_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(relation_present_rb, "matches", NULL);
1237 gtk_box_pack_start(GTK_BOX(relation_vb), relation_matches_rb, FALSE, FALSE, 0);
1240 value_vb = gtk_vbox_new(FALSE, 5);
1241 gtk_container_border_width(GTK_CONTAINER(value_vb), 5);
1242 gtk_container_add(GTK_CONTAINER(main_hb), value_vb);
1244 value_label = gtk_label_new("Value");
1245 gtk_misc_set_alignment(GTK_MISC(value_label), 0.0, 0.0);
1246 gtk_box_pack_start(GTK_BOX(value_vb), value_label, FALSE, FALSE, 0);
1248 value_entry = gtk_entry_new();
1249 gtk_box_pack_start(GTK_BOX(value_vb), value_entry, FALSE, FALSE, 0);
1251 value_list_label = gtk_label_new("Predefined values:");
1252 gtk_misc_set_alignment(GTK_MISC(value_list_label), 0.0, 0.0);
1253 gtk_box_pack_start(GTK_BOX(value_vb), value_list_label, FALSE, FALSE, 0);
1255 value_list_scrolled_win = scrolled_window_new(NULL, NULL);
1256 gtk_box_pack_start(GTK_BOX(value_vb), value_list_scrolled_win, TRUE,
1259 #if GTK_MAJOR_VERSION < 2
1260 value_list = gtk_list_new();
1261 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(value_list_scrolled_win),
1263 SIGNAL_CONNECT(value_list, "select-child", value_list_sel_cb, value_entry);
1264 gtk_list_set_selection_mode(GTK_LIST(value_list), GTK_SELECTION_SINGLE);
1265 /* This remains hidden until an enumerated field is selected */
1268 * The value stuff may be hidden or shown depending on what
1269 * relation was selected; connect to the "select-child" signal
1270 * for the relation list, so we can make that happen.
1272 SIGNAL_CONNECT(relation_list, "select-child", relation_list_sel_cb, NULL);
1274 l_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
1275 value_list = tree_view_new(GTK_TREE_MODEL(l_store));
1276 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(value_list), FALSE);
1277 g_object_unref(G_OBJECT(l_store));
1278 renderer = gtk_cell_renderer_text_new();
1279 column = gtk_tree_view_column_new_with_attributes("value", renderer,
1281 gtk_tree_view_append_column(GTK_TREE_VIEW(value_list), column);
1282 SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list)),
1283 "changed", value_list_sel_cb, value_entry);
1286 * The value stuff may be hidden or shown depending on what
1287 * relation was selected; connect to the "changed" signal
1288 * for the relation list, so we can make that happen.
1290 SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list)),
1291 "changed", relation_list_sel_cb, NULL);
1292 l_sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list));
1293 gtk_tree_selection_set_mode(l_sel, GTK_SELECTION_SINGLE);
1294 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(value_list_scrolled_win),
1296 /* This remains hidden until an enumerated field is selected */
1300 * Put the items in the Tree; we don't want to do that until
1301 * we've constructed the value list and set the tree's
1302 * E_DFILTER_EXPR_VALUE_LIST_KEY data to point to it, and
1303 * constructed the "Accept" button and set the tree's
1304 * E_DFILTER_EXPR_OK_BT_KEY data to point to it, so that
1305 * when the list item is "helpfully" automatically selected for us
1306 * we're ready to cope with the selection signal.
1309 #if GTK_MAJOR_VERSION < 2
1310 /* a hash table seems excessive, but I don't see support for a
1311 sparse array in glib */
1312 proto_array = g_hash_table_new(g_direct_hash, g_direct_equal);
1313 for (i = proto_get_first_protocol(&cookie); i != -1;
1314 i = proto_get_next_protocol(&cookie)) {
1315 hfinfo = proto_registrar_get_nth(i);
1317 /* Create a node for the protocol, and remember it for
1319 protocol = find_protocol_by_id(i);
1321 if (!proto_is_protocol_enabled(protocol))
1324 name = proto_get_protocol_short_name(protocol); /* name, short_name or filter name ? */
1325 protocol_node = gtk_ctree_insert_node(GTK_CTREE(field_tree),
1327 (gchar **) &name, 5,
1328 NULL, NULL, NULL, NULL,
1330 gtk_ctree_node_set_row_data(GTK_CTREE(field_tree), protocol_node,
1332 g_hash_table_insert(proto_array, GINT_TO_POINTER(i), protocol_node);
1335 len = proto_registrar_n();
1336 for (i = 0; i < len; i++) {
1337 char *strp, str[TAG_STRING_LEN+1];
1340 * If this field is a protocol, skip it - we already put
1343 if (proto_registrar_is_protocol(i))
1346 hfinfo = proto_registrar_get_nth(i);
1349 * If this field isn't at the head of the list of
1350 * fields with this name, skip this field - all
1351 * fields with the same name are really just versions
1352 * of the same field stored in different bits, and
1353 * should have the same type/radix/value list, and
1354 * just differ in their bit masks. (If a field isn't
1355 * a bitfield, but can be, say, 1 or 2 bytes long,
1356 * it can just be made FT_UINT16, meaning the
1357 * *maximum* length is 2 bytes, and be used
1360 if (hfinfo->same_name_prev != NULL)
1363 if (!proto_is_protocol_enabled(find_protocol_by_id(
1364 proto_registrar_get_parent(i)))) {
1368 /* Create a node for the item, and put it
1369 under its parent protocol. */
1370 protocol_node = g_hash_table_lookup(proto_array,
1371 GINT_TO_POINTER(proto_registrar_get_parent(i)));
1372 if (hfinfo->blurb != NULL && hfinfo->blurb[0] != '\0') {
1373 g_snprintf(str, TAG_STRING_LEN, "%s - %s (%s)", hfinfo->abbrev,
1374 hfinfo->name, hfinfo->blurb);
1376 g_snprintf(str, TAG_STRING_LEN, "%s - %s", hfinfo->abbrev,
1379 str[TAG_STRING_LEN]=0;
1381 item_node = gtk_ctree_insert_node(GTK_CTREE(field_tree),
1382 protocol_node, NULL,
1384 NULL, NULL, NULL, NULL,
1386 gtk_ctree_node_set_row_data(GTK_CTREE(field_tree),
1389 g_hash_table_destroy(proto_array);
1391 #else /* GTK_MAJOR_VERSION < 2 */
1393 /* GTK2 code using two levels iterator to enumerate all protocol fields */
1395 GtkTreeIter iter, child_iter;
1396 void *cookie, *cookie2;
1399 for (i = proto_get_first_protocol(&cookie); i != -1;
1400 i = proto_get_next_protocol(&cookie)) {
1401 char *strp, str[TAG_STRING_LEN+1];
1403 protocol = find_protocol_by_id(i);
1405 if (!proto_is_protocol_enabled(protocol)) {
1409 name = proto_get_protocol_short_name(protocol); /* name, short_name or filter name ? */
1410 hfinfo = proto_registrar_get_nth(i);
1412 gtk_tree_store_append(store, &iter, NULL);
1413 gtk_tree_store_set(store, &iter, 0, name, 1, hfinfo, -1);
1415 for (hfinfo = proto_get_first_protocol_field(i, &cookie2); hfinfo != NULL;
1416 hfinfo = proto_get_next_protocol_field(&cookie2)) {
1418 if (hfinfo->same_name_prev != NULL) /* ignore duplicate names */
1421 if (hfinfo->blurb != NULL && hfinfo->blurb[0] != '\0') {
1422 g_snprintf(str, TAG_STRING_LEN, "%s - %s (%s)",
1423 hfinfo->abbrev, hfinfo->name, hfinfo->blurb);
1425 g_snprintf(str, TAG_STRING_LEN, "%s - %s", hfinfo->abbrev,
1428 str[TAG_STRING_LEN]=0;
1430 gtk_tree_store_append(store, &child_iter, &iter);
1431 gtk_tree_store_set(store, &child_iter, 0, strp, 1, hfinfo, -1);
1434 g_object_unref(G_OBJECT(store));
1436 #endif /* GTK_MAJOR_VERSION < 2 */
1438 range_label = gtk_label_new("Range (offset:length)");
1439 gtk_misc_set_alignment(GTK_MISC(range_label), 0.0, 0.0);
1440 gtk_box_pack_start(GTK_BOX(value_vb), range_label, FALSE, FALSE, 0);
1442 range_entry = gtk_entry_new();
1443 gtk_box_pack_start(GTK_BOX(value_vb), range_entry, FALSE, FALSE, 0);
1447 list_bb = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_CANCEL, NULL);
1448 gtk_box_pack_start(GTK_BOX(main_vb), list_bb, FALSE, FALSE, 0);
1449 gtk_container_set_border_width (GTK_CONTAINER (list_bb), 0);
1451 ok_bt = OBJECT_GET_DATA(list_bb, GTK_STOCK_OK);
1452 gtk_widget_set_sensitive(ok_bt, FALSE);
1453 SIGNAL_CONNECT(ok_bt, "clicked", dfilter_expr_dlg_accept_cb, filter_te);
1455 cancel_bt = OBJECT_GET_DATA(list_bb, GTK_STOCK_CANCEL);
1456 window_set_cancel_button(window, cancel_bt, NULL);
1457 SIGNAL_CONNECT(cancel_bt, "clicked", dfilter_expr_dlg_cancel_cb, window);
1459 gtk_widget_grab_default(ok_bt);
1461 /* Catch the "activate" signal on the range and value text entries,
1462 so that if the user types Return there, we act as if the "Accept"
1463 button had been selected, as happens if Return is typed if some
1464 widget that *doesn't* handle the Return key has the input focus. */
1465 dlg_set_activate(range_entry, ok_bt);
1466 dlg_set_activate(value_entry, ok_bt);
1468 OBJECT_SET_DATA(window, E_DFILTER_EXPR_RELATION_LIST_KEY, relation_list);
1469 OBJECT_SET_DATA(window, E_DFILTER_EXPR_RANGE_LABEL_KEY, range_label);
1470 OBJECT_SET_DATA(window, E_DFILTER_EXPR_RANGE_ENTRY_KEY, range_entry);
1471 OBJECT_SET_DATA(window, E_DFILTER_EXPR_VALUE_LABEL_KEY, value_label);
1472 OBJECT_SET_DATA(window, E_DFILTER_EXPR_VALUE_ENTRY_KEY, value_entry);
1473 OBJECT_SET_DATA(window, E_DFILTER_EXPR_VALUE_LIST_KEY, value_list);
1474 OBJECT_SET_DATA(window, E_DFILTER_EXPR_VALUE_LIST_LABEL_KEY, value_list_label);
1475 OBJECT_SET_DATA(window, E_DFILTER_EXPR_VALUE_LIST_SW_KEY,
1476 value_list_scrolled_win);
1477 OBJECT_SET_DATA(window, E_DFILTER_EXPR_OK_BT_KEY, ok_bt);
1479 #if GTK_MAJOR_VERSION < 2
1481 * OK, we've finally built the entire list, complete with the row data,
1482 * and attached to the top-level widget pointers to the relevant
1483 * subwidgets, so it's safe to put the list in browse mode.
1485 gtk_clist_set_selection_mode (GTK_CLIST(field_tree),
1486 GTK_SELECTION_BROWSE);
1489 SIGNAL_CONNECT(window, "delete_event", dfilter_expr_dlg_delete_event_cb,
1493 * Catch the "destroy" signal on our top-level window, and,
1494 * when it's destroyed, disconnect the signal we'll be
1497 SIGNAL_CONNECT(window, "destroy", dfilter_expr_dlg_destroy_cb, filter_te);
1500 * Catch the "destroy" signal on the text entry widget to which
1501 * we're attached; if it's destroyed, we should destroy ourselves
1504 SIGNAL_CONNECT(filter_te, "destroy", dfilter_expr_dlg_cancel_cb, window);
1506 gtk_widget_show_all(window);
1507 window_present(window);