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 * 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
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, 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, 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, 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, (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,
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, gchar *string, 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) {
700 g_snprintf(value_string, sizeof value_string,
707 g_snprintf(value_string, sizeof value_string,
712 g_assert_not_reached();
717 g_snprintf(value_string, sizeof value_string, "0x%x",
722 g_snprintf(value_string, sizeof value_string, "%#o",
727 g_assert_not_reached();
730 gtk_entry_set_text(GTK_ENTRY(value_entry), value_string);
734 dfilter_report_bad_value(char *format, ...)
736 char error_msg_buf[1024];
739 va_start(args, format);
740 g_vsnprintf(error_msg_buf, sizeof error_msg_buf, format, args);
743 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_msg_buf);
747 dfilter_expr_dlg_accept_cb(GtkWidget *w, gpointer filter_te_arg)
749 GtkWidget *filter_te = filter_te_arg;
750 GtkWidget *window = gtk_widget_get_toplevel(w);
751 GtkWidget *relation_list =
752 OBJECT_GET_DATA(window, E_DFILTER_EXPR_RELATION_LIST_KEY);
753 GtkWidget *range_entry =
754 OBJECT_GET_DATA(window, E_DFILTER_EXPR_RANGE_ENTRY_KEY);
755 GtkWidget *value_entry =
756 OBJECT_GET_DATA(window, E_DFILTER_EXPR_VALUE_ENTRY_KEY);
757 header_field_info *hfinfo;
759 gchar *range_str, *stripped_range_str;
760 gchar *value_str, *stripped_value_str;
764 gboolean can_compare;
766 #if GTK_MAJOR_VERSION < 2
768 GtkWidget *item, *item_label;
776 * Get the variable to be tested.
778 hfinfo = OBJECT_GET_DATA(window, E_DFILTER_EXPR_CURRENT_VAR_KEY);
781 * Get the relation operator to use.
783 #if GTK_MAJOR_VERSION < 2
784 sl = GTK_LIST(relation_list)->selection;
785 item = GTK_WIDGET(sl->data);
786 item_label = GTK_BIN(item)->child;
787 gtk_label_get(GTK_LABEL(item_label), &item_str);
789 if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list)),
791 gtk_tree_model_get(model, &iter, 0, &item_str, -1);
793 /* XXX - the relation list is in GTK_SELECTION_BROWSE mode; how
794 can this ever be null? */
800 * Get the range to use, if any.
802 if (GTK_WIDGET_SENSITIVE(range_entry)) {
803 range_str = g_strdup(gtk_entry_get_text(GTK_ENTRY(range_entry)));
805 * XXX - strip this even for strings?
806 * Doing so for strings mean you can't match a string that has
807 * leading or trailing whitespace, but you can't see trailing
808 * whitespace in a text field, so it's not clear that it's
809 * a good idea to allow that.
811 stripped_range_str = g_strstrip(range_str);
812 if (strcmp(stripped_range_str, "") == 0) {
814 * No range was specified.
818 stripped_range_str = NULL;
822 * XXX - check it for validity?
826 stripped_range_str = NULL;
830 * If a range was specified, the type of the LHS of the
831 * comparison is FT_BYTES; otherwise, it's the type of the field.
833 if (range_str == NULL)
834 ftype = hfinfo->type;
839 * Make sure the relation is valid for the type in question.
840 * We may be offering relations that the type of the field
841 * can't support, because the field's type supports slicing,
842 * and the relation *is* supported on byte strings.
844 if (strcmp(item_str, "==") == 0)
845 can_compare = ftype_can_eq(ftype);
846 else if (strcmp(item_str, "!=") == 0)
847 can_compare = ftype_can_ne(ftype);
848 else if (strcmp(item_str, ">") == 0)
849 can_compare = ftype_can_gt(ftype);
850 else if (strcmp(item_str, "<") == 0)
851 can_compare = ftype_can_lt(ftype);
852 else if (strcmp(item_str, ">=") == 0)
853 can_compare = ftype_can_ge(ftype);
854 else if (strcmp(item_str, "<=") == 0)
855 can_compare = ftype_can_le(ftype);
856 else if (strcmp(item_str, "contains") == 0)
857 can_compare = ftype_can_contains(ftype);
858 else if (strcmp(item_str, "matches") == 0)
859 can_compare = ftype_can_matches(ftype);
861 can_compare = TRUE; /* not a comparison */
863 if (range_str == NULL) {
864 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
865 "That field cannot be tested with \"%s\".",
868 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
869 "Ranges of that field cannot be tested with \"%s\".",
872 if (range_str != NULL)
878 * Get the value to use, if any.
880 if (GTK_WIDGET_SENSITIVE(value_entry)) {
881 value_str = g_strdup(gtk_entry_get_text(GTK_ENTRY(value_entry)));
882 stripped_value_str = g_strstrip(value_str);
883 if (strcmp(stripped_value_str, "") == 0) {
885 * This field takes a value, but they didn't supply
888 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
889 "That field must be compared with a value, "
890 "but you didn't specify a value with which to "
892 if (range_str != NULL)
899 * Make sure the value is valid.
901 * If no range string was specified, it must be valid
902 * for the type of the field; if a range string was
903 * specified, must be valid for FT_BYTES.
905 if (strcmp(item_str, "contains") == 0) {
906 fvalue = fvalue_from_unparsed(ftype, stripped_value_str, TRUE,
907 dfilter_report_bad_value);
910 fvalue = fvalue_from_unparsed(ftype, stripped_value_str, FALSE,
911 dfilter_report_bad_value);
913 if (fvalue == NULL) {
917 * The dialog box was already popped up by
918 * "dfilter_report_bad_value()".
920 if (range_str != NULL)
928 stripped_value_str = NULL;
932 * Insert the expression at the current cursor position.
933 * If there's a non-whitespace character to the left of it,
934 * insert a blank first; if there's a non-whitespace character
935 * to the right of it, insert a blank after it.
937 pos = gtk_editable_get_position(GTK_EDITABLE(filter_te));
938 chars = gtk_editable_get_chars(GTK_EDITABLE(filter_te), pos, pos + 1);
939 if (strcmp(chars, "") != 0 && !isspace((unsigned char)chars[0]))
940 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
943 gtk_editable_insert_text(GTK_EDITABLE(filter_te), hfinfo->abbrev,
944 strlen(hfinfo->abbrev), &pos);
945 if (range_str != NULL) {
946 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "[", 1, &pos);
947 gtk_editable_insert_text(GTK_EDITABLE(filter_te),
948 stripped_range_str, strlen(stripped_range_str), &pos);
949 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "]", 1, &pos);
952 if (item_str != NULL && !relation_is_presence_test(item_str)) {
953 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
954 gtk_editable_insert_text(GTK_EDITABLE(filter_te), item_str,
955 strlen(item_str), &pos);
957 if (value_str != NULL) {
958 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
960 * XXX - we should do this by generating an appropriate display
961 * filter value string for this field; that requires us to have
962 * a "generate display filter string" method for every FT_ type.
964 switch (hfinfo->type) {
969 case FT_ABSOLUTE_TIME:
971 * Always put quotes around the string.
978 * If the string contains white space, put quotes around it.
980 quote_it = (strpbrk(stripped_value_str, " \t") != NULL);
985 * Put quotes around the string.
987 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "\"",
990 gtk_editable_insert_text(GTK_EDITABLE(filter_te),
991 stripped_value_str, strlen(stripped_value_str), &pos);
994 * Put quotes around the string.
996 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "\"",
1001 chars = gtk_editable_get_chars(GTK_EDITABLE(filter_te), pos + 1, pos + 2);
1002 if (strcmp(chars, "") != 0 && !isspace((unsigned char)chars[0]))
1003 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
1007 * Put the cursor after the expression we just entered into
1008 * the text entry widget.
1010 gtk_editable_set_position(GTK_EDITABLE(filter_te), pos);
1013 * We're done; destroy the dialog box (which is the top-level
1014 * widget for the "Accept" button).
1016 window_destroy(window);
1017 #if GTK_MAJOR_VERSION >= 2
1023 dfilter_expr_dlg_cancel_cb(GtkWidget *w _U_, gpointer parent_w)
1026 * User pressed the cancel button; close the dialog box.
1028 window_destroy(GTK_WIDGET(parent_w));
1031 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()" */
1033 dfilter_expr_dlg_delete_event_cb(GtkWidget *w _U_, GdkEvent *event _U_,
1036 dfilter_expr_dlg_cancel_cb(NULL, parent_w);
1041 dfilter_expr_dlg_destroy_cb(GtkWidget *w, gpointer filter_te)
1044 * The dialog box is being destroyed; disconnect from the
1045 * "destroy" signal on the text entry box to which we're
1046 * attached, as the handler for that signal is supposed
1047 * to destroy us, but we're already gone.
1049 SIGNAL_DISCONNECT_BY_FUNC(filter_te, dfilter_expr_dlg_cancel_cb, w);
1053 * Length of string used for protocol fields.
1055 #define TAG_STRING_LEN 256
1058 dfilter_expr_dlg_new(GtkWidget *filter_te)
1060 GtkWidget *window, *main_vb, *main_hb;
1062 GtkWidget *field_vb, *field_tree_lb, *field_tree, *tree_scrolled_win;
1064 GtkWidget *relation_vb, *relation_label, *relation_list, *relation_list_scrolled_win;
1065 /* GtkWidget *relation_present_rb, *relation_equals_rb, *relation_unequals_rb,
1066 *relation_greater_rb, *relation_less_rb,
1067 *relation_greaterequal_rb, *relation_lessequal_rb,
1068 *relation_contains_rb, *relation_matches_rb;*/
1070 GtkWidget *value_vb, *value_label, *value_entry;
1071 GtkWidget *value_list_label, *value_list_scrolled_win, *value_list;
1072 GtkWidget *range_label, *range_entry;
1074 GtkWidget *list_bb, *ok_bt, *cancel_bt;
1075 header_field_info *hfinfo;
1077 protocol_t *protocol;
1078 #if GTK_MAJOR_VERSION < 2
1082 GHashTable *proto_array;
1083 GtkCTreeNode *protocol_node, *item_node;
1085 GtkTreeStore *store;
1086 GtkTreeSelection *selection;
1087 GtkCellRenderer *renderer;
1088 GtkTreeViewColumn *column;
1089 GtkListStore *l_store;
1090 GtkTreeSelection *l_sel;
1093 window = dlg_window_new("Ethereal: Filter Expression");
1094 gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
1095 gtk_container_set_border_width(GTK_CONTAINER(window), 5);
1097 main_vb = gtk_vbox_new(FALSE, 5);
1098 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1099 gtk_container_add(GTK_CONTAINER(window), main_vb);
1101 main_hb = gtk_hbox_new(FALSE, 5);
1102 gtk_container_border_width(GTK_CONTAINER(main_hb), 5);
1103 gtk_container_add(GTK_CONTAINER(main_vb), main_hb);
1105 field_vb = gtk_vbox_new(FALSE, 5);
1106 gtk_container_border_width(GTK_CONTAINER(field_vb), 5);
1107 gtk_container_add(GTK_CONTAINER(main_hb), field_vb);
1109 field_tree_lb = gtk_label_new("Field name");
1110 gtk_misc_set_alignment(GTK_MISC(field_tree_lb), 0.0, 0.0);
1111 gtk_box_pack_start(GTK_BOX(field_vb), field_tree_lb, FALSE, FALSE, 0);
1113 tree_scrolled_win = scrolled_window_new(NULL, NULL);
1114 #if GTK_MAJOR_VERSION >= 2
1115 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(tree_scrolled_win),
1118 gtk_box_pack_start(GTK_BOX(field_vb), tree_scrolled_win, TRUE, TRUE, 0);
1119 WIDGET_SET_SIZE(tree_scrolled_win, 300, -1);
1122 #if GTK_MAJOR_VERSION < 2
1123 field_tree = ctree_new(1, 0);
1124 SIGNAL_CONNECT(field_tree, "tree-select-row", field_select_row_cb, field_tree);
1126 store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
1127 field_tree = tree_view_new(GTK_TREE_MODEL(store));
1128 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(field_tree), FALSE);
1129 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(field_tree));
1130 gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
1131 renderer = gtk_cell_renderer_text_new();
1132 column = gtk_tree_view_column_new_with_attributes("Field name", renderer,
1134 gtk_tree_view_append_column(GTK_TREE_VIEW(field_tree), column);
1135 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1136 gtk_tree_view_column_set_sort_column_id(column, 0);
1137 SIGNAL_CONNECT(selection, "changed", field_select_row_cb, field_tree);
1139 gtk_container_add(GTK_CONTAINER(tree_scrolled_win), field_tree);
1141 #if GTK_MAJOR_VERSION < 2
1143 * GTK's annoying CTree widget will deliver a selection event
1144 * the instant you add an item to the field_tree, *the fact that you
1145 * haven't even had time to set the item's row data nonwithstanding*.
1147 * We'll put the widget into GTK_SELECTION_SINGLE mode in the
1148 * hopes that it's *STOP DOING THAT*.
1150 gtk_clist_set_selection_mode(GTK_CLIST(field_tree),
1151 GTK_SELECTION_SINGLE);
1154 relation_vb = gtk_vbox_new(FALSE, 5);
1155 gtk_container_border_width(GTK_CONTAINER(relation_vb), 5);
1156 gtk_container_add(GTK_CONTAINER(main_hb), relation_vb);
1158 relation_label = gtk_label_new("Relation");
1159 gtk_misc_set_alignment(GTK_MISC(relation_label), 0.0, 0.0);
1160 gtk_box_pack_start(GTK_BOX(relation_vb), relation_label, FALSE, FALSE, 0);
1162 relation_list_scrolled_win = scrolled_window_new(NULL, NULL);
1163 /* never use a scrollbar in x direction, show the complete relation string */
1164 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(relation_list_scrolled_win),
1165 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1166 #if GTK_MAJOR_VERSION >= 2
1167 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(relation_list_scrolled_win),
1171 #if GTK_MAJOR_VERSION < 2
1172 relation_list = gtk_list_new();
1173 gtk_list_set_selection_mode(GTK_LIST(relation_list),
1174 GTK_SELECTION_BROWSE);
1176 l_store = gtk_list_store_new(1, G_TYPE_STRING);
1177 relation_list = tree_view_new(GTK_TREE_MODEL(l_store));
1178 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(relation_list), FALSE);
1179 g_object_unref(G_OBJECT(l_store));
1180 renderer = gtk_cell_renderer_text_new();
1181 column = gtk_tree_view_column_new_with_attributes("relation", renderer,
1183 gtk_tree_view_append_column(GTK_TREE_VIEW(relation_list), column);
1184 l_sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list));
1185 gtk_tree_selection_set_mode(l_sel, GTK_SELECTION_BROWSE);
1187 #if GTK_MAJOR_VERSION < 2
1188 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(relation_list_scrolled_win),
1191 gtk_container_add(GTK_CONTAINER(relation_list_scrolled_win), relation_list);
1193 gtk_box_pack_start(GTK_BOX(relation_vb), relation_list_scrolled_win, TRUE, TRUE, 0);
1196 * OK, show the relation label and range stuff as it would be
1197 * with everything turned on, so it'll request as much space
1198 * as it'll ever need, so the dialog box and widgets start out
1199 * with the right sizes.
1201 * XXX - this doesn't work. It *doesn't* request as much space
1202 * as it'll ever need.
1204 * XXX - FT_UINT8 doesn't support ranges, so even if it did work,
1205 * it wouldn't work right.
1207 * XXX - this no longer affects the range stuff, as that's
1208 * controlled both by the type and by the relational operator
1211 show_relations(relation_list, FT_UINT8);
1214 relation_present_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL, "is present", NULL);
1215 gtk_box_pack_start(GTK_BOX(relation_vb), relation_present_rb, FALSE, FALSE, 0);
1217 relation_equals_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(relation_present_rb, "==", NULL);
1218 gtk_box_pack_start(GTK_BOX(relation_vb), relation_equals_rb, FALSE, FALSE, 0);
1220 relation_unequals_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(relation_present_rb, "!=", NULL);
1221 gtk_box_pack_start(GTK_BOX(relation_vb), relation_unequals_rb, FALSE, FALSE, 0);
1223 relation_greater_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(relation_present_rb, ">", NULL);
1224 gtk_box_pack_start(GTK_BOX(relation_vb), relation_greater_rb, FALSE, FALSE, 0);
1226 relation_less_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(relation_present_rb, "<", NULL);
1227 gtk_box_pack_start(GTK_BOX(relation_vb), relation_less_rb, FALSE, FALSE, 0);
1229 relation_greaterequal_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(relation_present_rb, ">=", NULL);
1230 gtk_box_pack_start(GTK_BOX(relation_vb), relation_greaterequal_rb, FALSE, FALSE, 0);
1232 relation_lessequal_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(relation_present_rb, "<=", NULL);
1233 gtk_box_pack_start(GTK_BOX(relation_vb), relation_lessequal_rb, FALSE, FALSE, 0);
1235 relation_contains_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(relation_present_rb, "contains", NULL);
1236 gtk_box_pack_start(GTK_BOX(relation_vb), relation_contains_rb, FALSE, FALSE, 0);
1238 relation_matches_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(relation_present_rb, "matches", NULL);
1239 gtk_box_pack_start(GTK_BOX(relation_vb), relation_matches_rb, FALSE, FALSE, 0);
1242 value_vb = gtk_vbox_new(FALSE, 5);
1243 gtk_container_border_width(GTK_CONTAINER(value_vb), 5);
1244 gtk_container_add(GTK_CONTAINER(main_hb), value_vb);
1246 value_label = gtk_label_new("Value");
1247 gtk_misc_set_alignment(GTK_MISC(value_label), 0.0, 0.0);
1248 gtk_box_pack_start(GTK_BOX(value_vb), value_label, FALSE, FALSE, 0);
1250 value_entry = gtk_entry_new();
1251 gtk_box_pack_start(GTK_BOX(value_vb), value_entry, FALSE, FALSE, 0);
1253 value_list_label = gtk_label_new("Predefined values:");
1254 gtk_misc_set_alignment(GTK_MISC(value_list_label), 0.0, 0.0);
1255 gtk_box_pack_start(GTK_BOX(value_vb), value_list_label, FALSE, FALSE, 0);
1257 value_list_scrolled_win = scrolled_window_new(NULL, NULL);
1258 gtk_box_pack_start(GTK_BOX(value_vb), value_list_scrolled_win, TRUE,
1261 #if GTK_MAJOR_VERSION < 2
1262 value_list = gtk_list_new();
1263 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(value_list_scrolled_win),
1265 SIGNAL_CONNECT(value_list, "select-child", value_list_sel_cb, value_entry);
1266 gtk_list_set_selection_mode(GTK_LIST(value_list), GTK_SELECTION_SINGLE);
1267 /* This remains hidden until an enumerated field is selected */
1270 * The value stuff may be hidden or shown depending on what
1271 * relation was selected; connect to the "select-child" signal
1272 * for the relation list, so we can make that happen.
1274 SIGNAL_CONNECT(relation_list, "select-child", relation_list_sel_cb, NULL);
1276 l_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
1277 value_list = tree_view_new(GTK_TREE_MODEL(l_store));
1278 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(value_list), FALSE);
1279 g_object_unref(G_OBJECT(l_store));
1280 renderer = gtk_cell_renderer_text_new();
1281 column = gtk_tree_view_column_new_with_attributes("value", renderer,
1283 gtk_tree_view_append_column(GTK_TREE_VIEW(value_list), column);
1284 SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list)),
1285 "changed", value_list_sel_cb, value_entry);
1288 * The value stuff may be hidden or shown depending on what
1289 * relation was selected; connect to the "changed" signal
1290 * for the relation list, so we can make that happen.
1292 SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list)),
1293 "changed", relation_list_sel_cb, NULL);
1294 l_sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list));
1295 gtk_tree_selection_set_mode(l_sel, GTK_SELECTION_SINGLE);
1296 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(value_list_scrolled_win),
1298 /* This remains hidden until an enumerated field is selected */
1302 * Put the items in the Tree; we don't want to do that until
1303 * we've constructed the value list and set the tree's
1304 * E_DFILTER_EXPR_VALUE_LIST_KEY data to point to it, and
1305 * constructed the "Accept" button and set the tree's
1306 * E_DFILTER_EXPR_OK_BT_KEY data to point to it, so that
1307 * when the list item is "helpfully" automatically selected for us
1308 * we're ready to cope with the selection signal.
1311 #if GTK_MAJOR_VERSION < 2
1312 /* a hash table seems excessive, but I don't see support for a
1313 sparse array in glib */
1314 proto_array = g_hash_table_new(g_direct_hash, g_direct_equal);
1315 for (i = proto_get_first_protocol(&cookie); i != -1;
1316 i = proto_get_next_protocol(&cookie)) {
1317 hfinfo = proto_registrar_get_nth(i);
1319 /* Create a node for the protocol, and remember it for
1321 protocol = find_protocol_by_id(i);
1323 if (!proto_is_protocol_enabled(protocol))
1326 name = proto_get_protocol_short_name(protocol); /* name, short_name or filter name ? */
1327 protocol_node = gtk_ctree_insert_node(GTK_CTREE(field_tree),
1330 NULL, NULL, NULL, NULL,
1332 gtk_ctree_node_set_row_data(GTK_CTREE(field_tree), protocol_node,
1334 g_hash_table_insert(proto_array, (gpointer)i, protocol_node);
1337 len = proto_registrar_n();
1338 for (i = 0; i < len; i++) {
1339 char *strp, str[TAG_STRING_LEN+1];
1342 * If this field is a protocol, skip it - we already put
1345 if (proto_registrar_is_protocol(i))
1348 hfinfo = proto_registrar_get_nth(i);
1351 * If this field isn't at the head of the list of
1352 * fields with this name, skip this field - all
1353 * fields with the same name are really just versions
1354 * of the same field stored in different bits, and
1355 * should have the same type/radix/value list, and
1356 * just differ in their bit masks. (If a field isn't
1357 * a bitfield, but can be, say, 1 or 2 bytes long,
1358 * it can just be made FT_UINT16, meaning the
1359 * *maximum* length is 2 bytes, and be used
1362 if (hfinfo->same_name_prev != NULL)
1365 if (!proto_is_protocol_enabled(find_protocol_by_id(
1366 proto_registrar_get_parent(i)))) {
1370 /* Create a node for the item, and put it
1371 under its parent protocol. */
1372 protocol_node = g_hash_table_lookup(proto_array,
1373 GINT_TO_POINTER(proto_registrar_get_parent(i)));
1374 if (hfinfo->blurb != NULL && hfinfo->blurb[0] != '\0') {
1375 g_snprintf(str, TAG_STRING_LEN, "%s - %s (%s)", hfinfo->abbrev,
1376 hfinfo->name, hfinfo->blurb);
1378 g_snprintf(str, TAG_STRING_LEN, "%s - %s", hfinfo->abbrev,
1381 str[TAG_STRING_LEN]=0;
1383 item_node = gtk_ctree_insert_node(GTK_CTREE(field_tree),
1384 protocol_node, NULL,
1386 NULL, NULL, NULL, NULL,
1388 gtk_ctree_node_set_row_data(GTK_CTREE(field_tree),
1391 g_hash_table_destroy(proto_array);
1393 #else /* GTK_MAJOR_VERSION < 2 */
1395 /* GTK2 code using two levels iterator to enumerate all protocol fields */
1397 GtkTreeIter iter, child_iter;
1398 void *cookie, *cookie2;
1401 for (i = proto_get_first_protocol(&cookie); i != -1;
1402 i = proto_get_next_protocol(&cookie)) {
1403 char *strp, str[TAG_STRING_LEN+1];
1405 protocol = find_protocol_by_id(i);
1407 if (!proto_is_protocol_enabled(protocol)) {
1411 name = proto_get_protocol_short_name(protocol); /* name, short_name or filter name ? */
1412 hfinfo = proto_registrar_get_nth(i);
1414 gtk_tree_store_append(store, &iter, NULL);
1415 gtk_tree_store_set(store, &iter, 0, name, 1, hfinfo, -1);
1417 for (hfinfo = proto_get_first_protocol_field(i, &cookie2); hfinfo != NULL;
1418 hfinfo = proto_get_next_protocol_field(&cookie2)) {
1420 if (hfinfo->same_name_prev != NULL) /* ignore duplicate names */
1423 if (hfinfo->blurb != NULL && hfinfo->blurb[0] != '\0') {
1424 g_snprintf(str, TAG_STRING_LEN, "%s - %s (%s)",
1425 hfinfo->abbrev, hfinfo->name, hfinfo->blurb);
1427 g_snprintf(str, TAG_STRING_LEN, "%s - %s", hfinfo->abbrev,
1430 str[TAG_STRING_LEN]=0;
1432 gtk_tree_store_append(store, &child_iter, &iter);
1433 gtk_tree_store_set(store, &child_iter, 0, strp, 1, hfinfo, -1);
1436 g_object_unref(G_OBJECT(store));
1438 #endif /* GTK_MAJOR_VERSION < 2 */
1440 range_label = gtk_label_new("Range (offset:length)");
1441 gtk_misc_set_alignment(GTK_MISC(range_label), 0.0, 0.0);
1442 gtk_box_pack_start(GTK_BOX(value_vb), range_label, FALSE, FALSE, 0);
1444 range_entry = gtk_entry_new();
1445 gtk_box_pack_start(GTK_BOX(value_vb), range_entry, FALSE, FALSE, 0);
1449 list_bb = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_CANCEL, NULL);
1450 gtk_box_pack_start(GTK_BOX(main_vb), list_bb, FALSE, FALSE, 0);
1451 gtk_container_set_border_width (GTK_CONTAINER (list_bb), 0);
1453 ok_bt = OBJECT_GET_DATA(list_bb, GTK_STOCK_OK);
1454 gtk_widget_set_sensitive(ok_bt, FALSE);
1455 SIGNAL_CONNECT(ok_bt, "clicked", dfilter_expr_dlg_accept_cb, filter_te);
1457 cancel_bt = OBJECT_GET_DATA(list_bb, GTK_STOCK_CANCEL);
1458 window_set_cancel_button(window, cancel_bt, NULL);
1459 SIGNAL_CONNECT(cancel_bt, "clicked", dfilter_expr_dlg_cancel_cb, window);
1461 gtk_widget_grab_default(ok_bt);
1463 /* Catch the "activate" signal on the range and value text entries,
1464 so that if the user types Return there, we act as if the "Accept"
1465 button had been selected, as happens if Return is typed if some
1466 widget that *doesn't* handle the Return key has the input focus. */
1467 dlg_set_activate(range_entry, ok_bt);
1468 dlg_set_activate(value_entry, ok_bt);
1470 OBJECT_SET_DATA(window, E_DFILTER_EXPR_RELATION_LIST_KEY, relation_list);
1471 OBJECT_SET_DATA(window, E_DFILTER_EXPR_RANGE_LABEL_KEY, range_label);
1472 OBJECT_SET_DATA(window, E_DFILTER_EXPR_RANGE_ENTRY_KEY, range_entry);
1473 OBJECT_SET_DATA(window, E_DFILTER_EXPR_VALUE_LABEL_KEY, value_label);
1474 OBJECT_SET_DATA(window, E_DFILTER_EXPR_VALUE_ENTRY_KEY, value_entry);
1475 OBJECT_SET_DATA(window, E_DFILTER_EXPR_VALUE_LIST_KEY, value_list);
1476 OBJECT_SET_DATA(window, E_DFILTER_EXPR_VALUE_LIST_LABEL_KEY, value_list_label);
1477 OBJECT_SET_DATA(window, E_DFILTER_EXPR_VALUE_LIST_SW_KEY,
1478 value_list_scrolled_win);
1479 OBJECT_SET_DATA(window, E_DFILTER_EXPR_OK_BT_KEY, ok_bt);
1481 #if GTK_MAJOR_VERSION < 2
1483 * OK, we've finally built the entire list, complete with the row data,
1484 * and attached to the top-level widget pointers to the relevant
1485 * subwidgets, so it's safe to put the list in browse mode.
1487 gtk_clist_set_selection_mode (GTK_CLIST(field_tree),
1488 GTK_SELECTION_BROWSE);
1491 SIGNAL_CONNECT(window, "delete_event", dfilter_expr_dlg_delete_event_cb,
1495 * Catch the "destroy" signal on our top-level window, and,
1496 * when it's destroyed, disconnect the signal we'll be
1499 SIGNAL_CONNECT(window, "destroy", dfilter_expr_dlg_destroy_cb, filter_te);
1502 * Catch the "destroy" signal on the text entry widget to which
1503 * we're attached; if it's destroyed, we should destroy ourselves
1506 SIGNAL_CONNECT(filter_te, "destroy", dfilter_expr_dlg_cancel_cb, window);
1508 gtk_widget_show_all(window);
1509 window_present(window);