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 * times. not a good thing.
39 * Sort the protocols and children
50 #include "../simple_dialog.h"
53 #include "gtk/gui_utils.h"
54 #include "gtk/dlg_utils.h"
55 #include "gtk/proto_dlg.h"
56 #include "gtk/filter_dlg.h"
57 #include "gtk/dfilter_expr_dlg.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.
102 field_select_row_cb(GtkTreeSelection *sel, gpointer tree)
104 GtkWidget *window = gtk_widget_get_toplevel(tree);
105 GtkWidget *relation_list = g_object_get_data(G_OBJECT(window),
106 E_DFILTER_EXPR_RELATION_LIST_KEY);
107 GtkWidget *range_label = g_object_get_data(G_OBJECT(window),
108 E_DFILTER_EXPR_RANGE_LABEL_KEY);
109 GtkWidget *range_entry = g_object_get_data(G_OBJECT(window),
110 E_DFILTER_EXPR_RANGE_ENTRY_KEY);
111 GtkWidget *value_label = g_object_get_data(G_OBJECT(window),
112 E_DFILTER_EXPR_VALUE_LABEL_KEY);
113 GtkWidget *value_entry = g_object_get_data(G_OBJECT(window),
114 E_DFILTER_EXPR_VALUE_ENTRY_KEY);
115 GtkWidget *value_list_label = g_object_get_data(G_OBJECT(window),
116 E_DFILTER_EXPR_VALUE_LIST_LABEL_KEY);
117 GtkWidget *value_list = g_object_get_data(G_OBJECT(window),
118 E_DFILTER_EXPR_VALUE_LIST_KEY);
119 GtkWidget *value_list_scrolled_win = g_object_get_data(G_OBJECT(window),
120 E_DFILTER_EXPR_VALUE_LIST_SW_KEY);
121 GtkWidget *ok_bt = g_object_get_data(G_OBJECT(window),
122 E_DFILTER_EXPR_OK_BT_KEY);
123 header_field_info *hfinfo, *cur_hfinfo;
124 const char *value_type;
125 char value_label_string[1024+1]; /* XXX - should be large enough */
129 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
131 gtk_tree_model_get(model, &iter, 1, &hfinfo, -1);
134 * What was the item that was last selected?
136 cur_hfinfo = g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_CURRENT_VAR_KEY);
137 if (cur_hfinfo == hfinfo) {
139 * It's still selected; no need to change anything.
145 * Mark it as currently selected.
147 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_CURRENT_VAR_KEY, hfinfo);
149 show_relations(relation_list, hfinfo->type);
152 * Set the label for the value to indicate what type of value
155 value_type = ftype_pretty_name(hfinfo->type);
156 if (value_type != NULL) {
158 * Indicate what type of value it is.
160 g_snprintf(value_label_string, sizeof value_label_string,
161 "Value (%s)", value_type);
162 gtk_label_set_text(GTK_LABEL(value_label), value_label_string);
166 * Clear the entry widget for the value, as whatever
167 * was there before doesn't apply.
169 gtk_entry_set_text(GTK_ENTRY(value_entry), "");
171 switch (hfinfo->type) {
175 * The list of values should be the strings for "true"
176 * and "false"; show them in the value list.
178 build_boolean_values(value_list_scrolled_win, value_list,
191 * If this has a value_string table (not a range_string table) associated with it,
192 * fill up the list of values, otherwise clear the list of values.
194 /* XXX: ToDo: Implement "range-string" filter ? */
195 if ((hfinfo->strings != NULL) && !(hfinfo->display & BASE_RANGE_STRING)) {
196 const value_string *vals = hfinfo->strings;
197 if (hfinfo->display & BASE_EXT_STRING)
198 vals = VALUE_STRING_EXT_VS_P((value_string_ext *) vals);
199 build_enum_values(value_list_scrolled_win, value_list, vals);
201 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
206 * Clear the list of values.
208 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
213 * Display various items for the value, as appropriate.
214 * The relation we start out with is never a comparison.
216 display_value_fields(hfinfo, FALSE, value_label, value_entry,
217 value_list_label, value_list, value_list_scrolled_win, range_label, range_entry);
220 * XXX - in browse mode, there always has to be something
221 * selected, so this should always be sensitive.
223 gtk_widget_set_sensitive(ok_bt, TRUE);
227 show_relations(GtkWidget *relation_list, ftenum_t ftype)
231 * Clear out the currently displayed list of relations.
233 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(relation_list))));
236 * Add the supported relations.
238 add_relation_list(relation_list, "is present", TRUE);
239 add_relation_list(relation_list, "==",
240 ftype_can_eq(ftype) || (ftype_can_slice(ftype) && ftype_can_eq(FT_BYTES)));
241 add_relation_list(relation_list, "!=",
242 ftype_can_ne(ftype) || (ftype_can_slice(ftype) && ftype_can_ne(FT_BYTES)));
243 add_relation_list(relation_list, ">",
244 ftype_can_gt(ftype) || (ftype_can_slice(ftype) && ftype_can_gt(FT_BYTES)));
246 add_relation_list(relation_list, "<",
247 ftype_can_lt(ftype) || (ftype_can_slice(ftype) && ftype_can_lt(FT_BYTES)));
248 add_relation_list(relation_list, ">=",
249 ftype_can_ge(ftype) || (ftype_can_slice(ftype) && ftype_can_ge(FT_BYTES)));
250 add_relation_list(relation_list, "<=",
251 ftype_can_le(ftype) || (ftype_can_slice(ftype) && ftype_can_le(FT_BYTES)));
252 add_relation_list(relation_list, "contains",
253 ftype_can_contains(ftype) || (ftype_can_slice(ftype) && ftype_can_contains(FT_BYTES)));
254 #if defined(HAVE_LIBPCRE) || GLIB_CHECK_VERSION(2,14,0)
255 add_relation_list(relation_list, "matches",
256 ftype_can_matches(ftype) || (ftype_can_slice(ftype) && ftype_can_matches(FT_BYTES)));
259 gtk_tree_model_get_iter_first(gtk_tree_view_get_model(GTK_TREE_VIEW(relation_list)), &iter);
260 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list)), &iter);
264 * Given a string that represents a test to be made on a field, returns
265 * TRUE if it tests for the field's presence, FALSE otherwise.
268 relation_is_presence_test(const char *string)
270 return (strcmp(string, "is present") == 0);
274 add_relation_list(GtkWidget *relation_list, const char *relation, gboolean sensitive)
276 GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(relation_list)));
279 /* XXX: I currently see no way to insensitive the item,
280 * so for a first step, just don't show it (as before these changes :-) */
285 gtk_list_store_append(store, &iter);
286 gtk_list_store_set(store, &iter, 0, relation, -1);
290 relation_list_sel_cb(GtkTreeSelection *sel, gpointer user_data _U_)
292 GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(gtk_tree_selection_get_tree_view(sel)));
293 GtkWidget *range_label =
294 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_RANGE_LABEL_KEY);
295 GtkWidget *range_entry =
296 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_RANGE_ENTRY_KEY);
297 GtkWidget *value_label =
298 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LABEL_KEY);
299 GtkWidget *value_entry =
300 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_ENTRY_KEY);
301 GtkWidget *value_list_label =
302 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_LABEL_KEY);
303 GtkWidget *value_list =
304 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_KEY);
305 GtkWidget *value_list_scrolled_win =
306 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_SW_KEY);
307 header_field_info *hfinfo =
308 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_CURRENT_VAR_KEY);
314 * What's the relation?
316 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
318 gtk_tree_model_get(model, &iter, 0, &item_str, -1);
321 * Update the display of various items for the value, as appropriate.
323 display_value_fields(hfinfo,
324 !relation_is_presence_test(item_str),
325 value_label, value_entry, value_list_label, value_list,
326 value_list_scrolled_win, range_label, range_entry);
331 build_boolean_values(GtkWidget *value_list_scrolled_win, GtkWidget *value_list,
332 const true_false_string *values)
334 static const true_false_string true_false = { "True", "False" };
335 GtkTreeSelection *sel;
338 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list));
341 * Clear out the items for the list, and put in the names
342 * from the value_string list.
344 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
347 * Put the list in single mode, so we don't get any selection
348 * events while we're building it (i.e., so we don't get any
349 * on a list item BEFORE WE GET TO SET THE DATA FOR THE LIST
350 * ITEM SO THAT THE HANDLER CAN HANDLE IT).
352 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
358 values = &true_false;
359 add_value_list_item(value_list, values->true_string, (const gpointer) values);
360 add_value_list_item(value_list, values->false_string, NULL);
363 * OK, we're done, so we can finally put it in browse mode.
364 * Select the first item, so that the user doesn't have to, under
365 * the assumption that they're most likely to test if something
366 * is true, not false.
368 gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
369 gtk_tree_model_get_iter_first(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list)), &iter);
370 gtk_tree_selection_select_iter(sel, &iter);
372 gtk_widget_show_all(value_list_scrolled_win);
376 build_enum_values(GtkWidget *value_list_scrolled_win _U_, GtkWidget *value_list,
377 const value_string *values)
379 GtkTreeSelection *sel;
381 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list));
383 * Clear out the items for the list, and put in the names
384 * from the value_string list.
386 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
389 * Put the list in single mode, so we don't get any selection
390 * events while we're building it (i.e., so we don't get any
391 * on a list item BEFORE WE GET TO SET THE DATA FOR THE LIST
392 * ITEM SO THAT THE HANDLER CAN HANDLE IT).
394 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
399 while (values->strptr != NULL) {
400 add_value_list_item(value_list, values->strptr,
401 (const gpointer) values);
406 * OK, we're done, so we can finally put it in browse mode.
408 gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
412 add_value_list_item(GtkWidget *value_list, const gchar *string, const gpointer data)
414 GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list)));
417 gtk_list_store_append(store, &iter);
418 gtk_list_store_set(store, &iter, 0, string, 1, data, -1);
422 * Show or hide the various values fields as appropriate for the field
423 * and currently-selected relation.
426 display_value_fields(header_field_info *hfinfo, gboolean is_comparison,
427 GtkWidget *value_label, GtkWidget *value_entry,
428 GtkWidget *value_list_label,
429 GtkWidget *value_list _U_,
430 GtkWidget *value_list_scrolled_win, GtkWidget *range_label,
431 GtkWidget *range_entry)
434 gboolean show_value_label = FALSE;
435 gboolean show_value_list = FALSE;
436 gboolean show_range = FALSE;
441 * this is an FT_NONE variable, in which case you can
442 * only check whether it's present or absent in the
447 * this is a Boolean variable, in which case you
448 * can't specify a value to compare with, you can
449 * only specify whether to test for the Boolean
450 * being true or to test for it being false
454 * this isn't a Boolean variable, in which case you
455 * can test for its presence in the protocol tree,
456 * and the relation is such a test, in
457 * which case you don't compare with a value
459 * so we hide the value entry.
462 switch (hfinfo->type) {
466 show_value_label = TRUE; /* XXX: Allow value entry (contrary to the comment above) ?? */
467 show_value_list = TRUE;
480 show_value_label = TRUE;
481 if ((hfinfo->strings != NULL) && !(hfinfo->display & BASE_RANGE_STRING)) {
483 * We have a list of values to show.
485 show_value_list = TRUE;
492 * There is no list of names for values; only show the value_label if needed.
495 show_value_label = TRUE;
499 gtk_widget_set_sensitive(value_label, show_value_label);
500 gtk_widget_set_sensitive(value_entry, show_value_label);
502 gtk_widget_set_sensitive(value_list_label, show_value_list);
503 gtk_widget_set_sensitive(value_list_scrolled_win, show_value_list);
506 * Is this a comparison, and are ranges supported by this type?
507 * If both are true, show the range stuff, otherwise hide it.
509 show_range = (is_comparison && ftype_can_slice(hfinfo->type));
510 gtk_widget_set_sensitive(range_label, show_range);
511 gtk_widget_set_sensitive(range_entry, show_range);
515 value_list_sel_cb(GtkTreeSelection *sel, gpointer value_entry_arg)
517 GtkWidget *value_entry = value_entry_arg;
518 GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(gtk_tree_selection_get_tree_view(sel)));
521 header_field_info *hfinfo = g_object_get_data(G_OBJECT(window),
522 E_DFILTER_EXPR_CURRENT_VAR_KEY);
523 const value_string *value = NULL;
524 gchar *value_display_string = NULL;
526 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
528 gtk_tree_model_get(model, &iter, 1, &value, -1);
531 * This should either be a numeric type or a Boolean type.
533 if (hfinfo->type == FT_BOOLEAN) {
535 * Boolean type; if the value key for the selected item
536 * is non-null, it's the item for "true", otherwise it's
537 * the item for "false". Compare with 1 if we're
538 * testing for "true", and compare with 0 if we're
539 * testing for "false".
542 value_display_string = g_strdup("1");
544 value_display_string = g_strdup("0");
547 * Numeric type; get the value corresponding to the
548 * selected item, and display it in the base for this
551 switch ((hfinfo->display) & BASE_DISPLAY_E_MASK) {
555 switch (hfinfo->type) {
561 value_display_string = g_strdup_printf("%u", value->value);
568 value_display_string = g_strdup_printf("%d", value->value);
572 g_assert_not_reached();
577 value_display_string = g_strdup_printf("0x%x", value->value);
581 value_display_string = g_strdup_printf("%#o", value->value);
585 g_assert_not_reached();
589 gtk_entry_set_text(GTK_ENTRY(value_entry), value_display_string);
590 g_free (value_display_string);
594 dfilter_report_bad_value(const char *format, ...)
596 char error_msg_buf[1024];
599 va_start(args, format);
600 g_vsnprintf(error_msg_buf, sizeof error_msg_buf, format, args);
603 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_msg_buf);
607 dfilter_expr_dlg_accept_cb(GtkWidget *w, gpointer filter_te_arg)
609 GtkWidget *filter_te = filter_te_arg;
610 GtkWidget *window = gtk_widget_get_toplevel(w);
611 GtkWidget *relation_list =
612 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_RELATION_LIST_KEY);
613 GtkWidget *range_entry =
614 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_RANGE_ENTRY_KEY);
615 GtkWidget *value_entry =
616 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_ENTRY_KEY);
617 header_field_info *hfinfo;
619 gchar *range_str, *stripped_range_str;
620 gchar *value_str, *stripped_value_str;
624 gboolean can_compare;
631 * Get the variable to be tested.
633 hfinfo = g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_CURRENT_VAR_KEY);
636 * Get the relation operator to use.
638 if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list)),
640 gtk_tree_model_get(model, &iter, 0, &item_str, -1);
642 /* Nothing selected */
647 * Get the range to use, if any.
649 if (GTK_WIDGET_SENSITIVE(range_entry)) {
650 range_str = g_strdup(gtk_entry_get_text(GTK_ENTRY(range_entry)));
652 * XXX - strip this even for strings?
653 * Doing so for strings means you can't match a string that has
654 * leading or trailing whitespace, but you can't see trailing
655 * whitespace in a text field, so it's not clear that it's
656 * a good idea to allow that.
658 stripped_range_str = g_strstrip(range_str);
659 if (strcmp(stripped_range_str, "") == 0) {
661 * No range was specified.
665 stripped_range_str = NULL;
669 * XXX - check it for validity?
673 stripped_range_str = NULL;
677 * If a range was specified, the type of the LHS of the
678 * comparison is FT_BYTES; otherwise, it's the type of the field.
680 if (range_str == NULL)
681 ftype = hfinfo->type;
686 * Make sure the relation is valid for the type in question.
687 * We may be offering relations that the type of the field
688 * can't support, because the field's type supports slicing,
689 * and the relation *is* supported on byte strings.
691 if (strcmp(item_str, "==") == 0)
692 can_compare = ftype_can_eq(ftype);
693 else if (strcmp(item_str, "!=") == 0)
694 can_compare = ftype_can_ne(ftype);
695 else if (strcmp(item_str, ">") == 0)
696 can_compare = ftype_can_gt(ftype);
697 else if (strcmp(item_str, "<") == 0)
698 can_compare = ftype_can_lt(ftype);
699 else if (strcmp(item_str, ">=") == 0)
700 can_compare = ftype_can_ge(ftype);
701 else if (strcmp(item_str, "<=") == 0)
702 can_compare = ftype_can_le(ftype);
703 else if (strcmp(item_str, "contains") == 0)
704 can_compare = ftype_can_contains(ftype);
705 else if (strcmp(item_str, "matches") == 0)
706 can_compare = ftype_can_matches(ftype);
708 can_compare = TRUE; /* not a comparison */
710 if (range_str == NULL) {
711 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
712 "That field can't be tested with \"%s\".",
715 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
716 "Ranges of that field can't be tested with \"%s\".",
725 * Get the value to use, if any.
727 if (GTK_WIDGET_SENSITIVE(value_entry)) {
728 value_str = g_strdup(gtk_entry_get_text(GTK_ENTRY(value_entry)));
729 stripped_value_str = g_strstrip(value_str);
730 if (strcmp(stripped_value_str, "") == 0) {
732 * This field takes a value, but they didn't supply
735 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
736 "That field must be compared with a value, "
737 "but you didn't specify a value with which to "
746 * Make sure the value is valid.
748 * If no range string was specified, it must be valid
749 * for the type of the field; if a range string was
750 * specified, must be valid for FT_BYTES.
752 if (strcmp(item_str, "contains") == 0) {
753 fvalue = fvalue_from_unparsed(ftype, stripped_value_str, TRUE,
754 dfilter_report_bad_value);
757 fvalue = fvalue_from_unparsed(ftype, stripped_value_str, FALSE,
758 dfilter_report_bad_value);
760 if (fvalue == NULL) {
764 * The dialog box was already popped up by
765 * "dfilter_report_bad_value()".
775 stripped_value_str = NULL;
779 * Insert the expression at the current cursor position.
780 * If there's a non-whitespace character to the left of it,
781 * insert a blank first; if there's a non-whitespace character
782 * to the right of it, insert a blank after it.
784 pos = gtk_editable_get_position(GTK_EDITABLE(filter_te));
785 chars = gtk_editable_get_chars(GTK_EDITABLE(filter_te), pos, pos + 1);
786 if (strcmp(chars, "") != 0 && !isspace((unsigned char)chars[0]))
787 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
790 gtk_editable_insert_text(GTK_EDITABLE(filter_te), hfinfo->abbrev,
791 (gint) strlen(hfinfo->abbrev), &pos);
792 if (range_str != NULL) {
793 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "[", 1, &pos);
794 gtk_editable_insert_text(GTK_EDITABLE(filter_te),
795 stripped_range_str, (gint) strlen(stripped_range_str), &pos);
796 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "]", 1, &pos);
799 if (item_str != NULL && !relation_is_presence_test(item_str)) {
800 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
801 gtk_editable_insert_text(GTK_EDITABLE(filter_te), item_str,
802 (gint) strlen(item_str), &pos);
804 if (value_str != NULL) {
805 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
807 * XXX - we should do this by generating an appropriate display
808 * filter value string for this field; that requires us to have
809 * a "generate display filter string" method for every FT_ type.
811 switch (hfinfo->type) {
816 case FT_ABSOLUTE_TIME:
818 * Always put quotes around the string.
825 * If the string contains white space, put quotes around it.
827 quote_it = (strpbrk(stripped_value_str, " \t") != NULL);
832 * Put quotes around the string.
834 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "\"",
837 gtk_editable_insert_text(GTK_EDITABLE(filter_te),
838 stripped_value_str, (gint) strlen(stripped_value_str), &pos);
841 * Put quotes around the string.
843 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "\"",
848 chars = gtk_editable_get_chars(GTK_EDITABLE(filter_te), pos + 1, pos + 2);
849 if (strcmp(chars, "") != 0 && !isspace((unsigned char)chars[0]))
850 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
854 * Put the cursor after the expression we just entered into
855 * the text entry widget.
857 gtk_editable_set_position(GTK_EDITABLE(filter_te), pos);
860 * We're done; destroy the dialog box (which is the top-level
861 * widget for the "Accept" button).
863 window_destroy(window);
868 dfilter_expr_dlg_cancel_cb(GtkWidget *w _U_, gpointer parent_w)
871 * User pressed the cancel button; close the dialog box.
873 window_destroy(GTK_WIDGET(parent_w));
876 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()" */
878 dfilter_expr_dlg_delete_event_cb(GtkWidget *w _U_, GdkEvent *event _U_,
881 dfilter_expr_dlg_cancel_cb(NULL, parent_w);
886 dfilter_expr_dlg_destroy_cb(GtkWidget *w, gpointer filter_te)
889 * The dialog box is being destroyed; disconnect from the
890 * "destroy" signal on the text entry box to which we're
891 * attached, as the handler for that signal is supposed
892 * to destroy us, but we're already gone.
894 g_signal_handlers_disconnect_by_func(filter_te, dfilter_expr_dlg_cancel_cb, w);
898 * Length of string used for protocol fields.
900 #define TAG_STRING_LEN 256
903 dfilter_expr_dlg_new(GtkWidget *filter_te)
905 GtkWidget *window, *main_vb, *main_hb;
907 GtkWidget *field_vb, *field_tree_lb, *field_tree, *tree_scrolled_win;
909 GtkWidget *relation_vb, *relation_label, *relation_list, *relation_list_scrolled_win;
910 /* GtkWidget *relation_present_rb, *relation_equals_rb, *relation_unequals_rb,
911 *relation_greater_rb, *relation_less_rb,
912 *relation_greaterequal_rb, *relation_lessequal_rb,
913 *relation_contains_rb, *relation_matches_rb;*/
915 GtkWidget *value_vb, *value_label, *value_entry;
916 GtkWidget *value_list_label, *value_list_scrolled_win, *value_list;
917 GtkWidget *range_label, *range_entry;
919 GtkWidget *list_bb, *ok_bt, *cancel_bt;
920 header_field_info *hfinfo;
922 protocol_t *protocol;
924 GtkTreeSelection *selection;
925 GtkCellRenderer *renderer;
926 GtkTreeViewColumn *column;
927 GtkListStore *l_store;
928 GtkTreeSelection *l_sel;
930 proto_initialize_all_prefixes();
932 window = dlg_conf_window_new("Wireshark: Filter Expression");
933 gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
934 gtk_container_set_border_width(GTK_CONTAINER(window), 5);
936 main_vb = gtk_vbox_new(FALSE, 5);
937 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
938 gtk_container_add(GTK_CONTAINER(window), main_vb);
940 main_hb = gtk_hbox_new(FALSE, 5);
941 gtk_container_set_border_width(GTK_CONTAINER(main_hb), 5);
942 gtk_container_add(GTK_CONTAINER(main_vb), main_hb);
944 field_vb = gtk_vbox_new(FALSE, 5);
945 gtk_container_set_border_width(GTK_CONTAINER(field_vb), 5);
946 gtk_container_add(GTK_CONTAINER(main_hb), field_vb);
948 field_tree_lb = gtk_label_new("Field name");
949 gtk_misc_set_alignment(GTK_MISC(field_tree_lb), 0.0f, 0.0f);
950 gtk_box_pack_start(GTK_BOX(field_vb), field_tree_lb, FALSE, FALSE, 0);
952 tree_scrolled_win = scrolled_window_new(NULL, NULL);
953 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(tree_scrolled_win),
955 gtk_box_pack_start(GTK_BOX(field_vb), tree_scrolled_win, TRUE, TRUE, 0);
956 gtk_widget_set_size_request(tree_scrolled_win, 300, -1);
959 store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
960 field_tree = tree_view_new(GTK_TREE_MODEL(store));
961 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(field_tree), FALSE);
962 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(field_tree));
963 gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
964 renderer = gtk_cell_renderer_text_new();
965 column = gtk_tree_view_column_new_with_attributes("Field name", renderer,
967 gtk_tree_view_append_column(GTK_TREE_VIEW(field_tree), column);
968 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
969 gtk_tree_view_column_set_sort_column_id(column, 0);
970 g_signal_connect(selection, "changed", G_CALLBACK(field_select_row_cb), field_tree);
971 gtk_container_add(GTK_CONTAINER(tree_scrolled_win), field_tree);
973 relation_vb = gtk_vbox_new(FALSE, 5);
974 gtk_container_set_border_width(GTK_CONTAINER(relation_vb), 5);
975 gtk_container_add(GTK_CONTAINER(main_hb), relation_vb);
977 relation_label = gtk_label_new("Relation");
978 gtk_misc_set_alignment(GTK_MISC(relation_label), 0.0f, 0.0f);
979 gtk_box_pack_start(GTK_BOX(relation_vb), relation_label, FALSE, FALSE, 0);
981 relation_list_scrolled_win = scrolled_window_new(NULL, NULL);
982 /* never use a scrollbar in x direction, show the complete relation string */
983 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(relation_list_scrolled_win),
984 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
985 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(relation_list_scrolled_win),
988 l_store = gtk_list_store_new(1, G_TYPE_STRING);
989 relation_list = tree_view_new(GTK_TREE_MODEL(l_store));
990 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(relation_list), FALSE);
991 g_object_unref(G_OBJECT(l_store));
992 renderer = gtk_cell_renderer_text_new();
993 column = gtk_tree_view_column_new_with_attributes("relation", renderer,
995 gtk_tree_view_append_column(GTK_TREE_VIEW(relation_list), column);
996 l_sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list));
997 gtk_tree_selection_set_mode(l_sel, GTK_SELECTION_BROWSE);
998 gtk_container_add(GTK_CONTAINER(relation_list_scrolled_win), relation_list);
999 gtk_box_pack_start(GTK_BOX(relation_vb), relation_list_scrolled_win, TRUE, TRUE, 0);
1002 * OK, show the relation label and range stuff as it would be
1003 * with everything turned on, so it'll request as much space
1004 * as it'll ever need, so the dialog box and widgets start out
1005 * with the right sizes.
1007 * XXX - this doesn't work. It *doesn't* request as much space
1008 * as it'll ever need.
1010 * XXX - FT_UINT8 doesn't support ranges, so even if it did work,
1011 * it wouldn't work right.
1013 * XXX - this no longer affects the range stuff, as that's
1014 * controlled both by the type and by the relational operator
1017 show_relations(relation_list, FT_UINT8);
1020 relation_present_rb = gtk_radio_button_new_with_mnemonic_from_widget(NULL, "is present");
1021 gtk_box_pack_start(GTK_BOX(relation_vb), relation_present_rb, FALSE, FALSE, 0);
1023 relation_equals_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "==");
1024 gtk_box_pack_start(GTK_BOX(relation_vb), relation_equals_rb, FALSE, FALSE, 0);
1026 relation_unequals_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "!=");
1027 gtk_box_pack_start(GTK_BOX(relation_vb), relation_unequals_rb, FALSE, FALSE, 0);
1029 relation_greater_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), ">");
1030 gtk_box_pack_start(GTK_BOX(relation_vb), relation_greater_rb, FALSE, FALSE, 0);
1032 relation_less_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "<");
1033 gtk_box_pack_start(GTK_BOX(relation_vb), relation_less_rb, FALSE, FALSE, 0);
1035 relation_greaterequal_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), ">=");
1036 gtk_box_pack_start(GTK_BOX(relation_vb), relation_greaterequal_rb, FALSE, FALSE, 0);
1038 relation_lessequal_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "<=");
1039 gtk_box_pack_start(GTK_BOX(relation_vb), relation_lessequal_rb, FALSE, FALSE, 0);
1041 relation_contains_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "contains");
1042 gtk_box_pack_start(GTK_BOX(relation_vb), relation_contains_rb, FALSE, FALSE, 0);
1044 relation_matches_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "matches");
1045 gtk_box_pack_start(GTK_BOX(relation_vb), relation_matches_rb, FALSE, FALSE, 0);
1048 value_vb = gtk_vbox_new(FALSE, 5);
1049 gtk_container_set_border_width(GTK_CONTAINER(value_vb), 5);
1050 gtk_container_add(GTK_CONTAINER(main_hb), value_vb);
1052 value_label = gtk_label_new("Value");
1053 gtk_misc_set_alignment(GTK_MISC(value_label), 0.0f, 0.0f);
1054 gtk_box_pack_start(GTK_BOX(value_vb), value_label, FALSE, FALSE, 0);
1056 value_entry = gtk_entry_new();
1057 gtk_box_pack_start(GTK_BOX(value_vb), value_entry, FALSE, FALSE, 0);
1059 value_list_label = gtk_label_new("Predefined values:");
1060 gtk_misc_set_alignment(GTK_MISC(value_list_label), 0.0f, 0.0f);
1061 gtk_box_pack_start(GTK_BOX(value_vb), value_list_label, FALSE, FALSE, 0);
1063 value_list_scrolled_win = scrolled_window_new(NULL, NULL);
1064 gtk_box_pack_start(GTK_BOX(value_vb), value_list_scrolled_win, TRUE,
1067 l_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
1068 value_list = tree_view_new(GTK_TREE_MODEL(l_store));
1069 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(value_list), FALSE);
1070 g_object_unref(G_OBJECT(l_store));
1071 renderer = gtk_cell_renderer_text_new();
1072 column = gtk_tree_view_column_new_with_attributes("value", renderer,
1074 gtk_tree_view_append_column(GTK_TREE_VIEW(value_list), column);
1075 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list)),
1076 "changed", G_CALLBACK(value_list_sel_cb), value_entry);
1079 * The value stuff may be hidden or shown depending on what
1080 * relation was selected; connect to the "changed" signal
1081 * for the relation list, so we can make that happen.
1083 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list)),
1084 "changed", G_CALLBACK(relation_list_sel_cb), NULL);
1085 l_sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list));
1086 gtk_tree_selection_set_mode(l_sel, GTK_SELECTION_SINGLE);
1087 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(value_list_scrolled_win),
1089 /* This remains hidden until an enumerated field is selected */
1092 * Put the items in the Tree; we don't want to do that until
1093 * we've constructed the value list and set the tree's
1094 * E_DFILTER_EXPR_VALUE_LIST_KEY data to point to it, and
1095 * constructed the "Accept" button and set the tree's
1096 * E_DFILTER_EXPR_OK_BT_KEY data to point to it, so that
1097 * when the list item is "helpfully" automatically selected for us
1098 * we're ready to cope with the selection signal.
1102 /* GTK2 code using two levels iterator to enumerate all protocol fields */
1104 GtkTreeIter iter, child_iter;
1105 void *cookie, *cookie2;
1107 for (i = proto_get_first_protocol(&cookie); i != -1;
1108 i = proto_get_next_protocol(&cookie)) {
1109 char *strp, str[TAG_STRING_LEN+1];
1111 protocol = find_protocol_by_id(i);
1113 if (!proto_is_protocol_enabled(protocol)) {
1117 g_snprintf(str, TAG_STRING_LEN, "%s - %s",
1118 proto_get_protocol_short_name(protocol),
1119 proto_get_protocol_long_name(protocol));
1122 hfinfo = proto_registrar_get_nth(i);
1124 gtk_tree_store_append(store, &iter, NULL);
1125 gtk_tree_store_set(store, &iter, 0, strp, 1, hfinfo, -1);
1127 for (hfinfo = proto_get_first_protocol_field(i, &cookie2); hfinfo != NULL;
1128 hfinfo = proto_get_next_protocol_field(&cookie2)) {
1130 if (hfinfo->same_name_prev != NULL) /* ignore duplicate names */
1133 if (hfinfo->blurb != NULL && hfinfo->blurb[0] != '\0') {
1134 g_snprintf(str, TAG_STRING_LEN, "%s - %s (%s)",
1135 hfinfo->abbrev, hfinfo->name, hfinfo->blurb);
1137 g_snprintf(str, TAG_STRING_LEN, "%s - %s", hfinfo->abbrev,
1140 gtk_tree_store_append(store, &child_iter, &iter);
1141 gtk_tree_store_set(store, &child_iter, 0, strp, 1, hfinfo, -1);
1144 g_object_unref(G_OBJECT(store));
1147 range_label = gtk_label_new("Range (offset:length)");
1148 gtk_misc_set_alignment(GTK_MISC(range_label), 0.0f, 0.0f);
1149 gtk_box_pack_start(GTK_BOX(value_vb), range_label, FALSE, FALSE, 0);
1151 range_entry = gtk_entry_new();
1152 gtk_box_pack_start(GTK_BOX(value_vb), range_entry, FALSE, FALSE, 0);
1156 list_bb = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_CANCEL, NULL);
1157 gtk_box_pack_start(GTK_BOX(main_vb), list_bb, FALSE, FALSE, 0);
1158 gtk_container_set_border_width (GTK_CONTAINER (list_bb), 0);
1160 ok_bt = g_object_get_data(G_OBJECT(list_bb), GTK_STOCK_OK);
1161 gtk_widget_set_sensitive(ok_bt, FALSE);
1162 g_signal_connect(ok_bt, "clicked", G_CALLBACK(dfilter_expr_dlg_accept_cb), filter_te);
1164 cancel_bt = g_object_get_data(G_OBJECT(list_bb), GTK_STOCK_CANCEL);
1165 window_set_cancel_button(window, cancel_bt, NULL);
1166 g_signal_connect(cancel_bt, "clicked", G_CALLBACK(dfilter_expr_dlg_cancel_cb), window);
1168 gtk_widget_grab_default(ok_bt);
1170 /* Catch the "activate" signal on the range and value text entries,
1171 so that if the user types Return there, we act as if the "Accept"
1172 button had been selected, as happens if Return is typed if some
1173 widget that *doesn't* handle the Return key has the input focus. */
1174 dlg_set_activate(range_entry, ok_bt);
1175 dlg_set_activate(value_entry, ok_bt);
1177 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_RELATION_LIST_KEY, relation_list);
1178 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_RANGE_LABEL_KEY, range_label);
1179 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_RANGE_ENTRY_KEY, range_entry);
1180 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LABEL_KEY, value_label);
1181 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_ENTRY_KEY, value_entry);
1182 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_KEY, value_list);
1183 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_LABEL_KEY, value_list_label);
1184 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_SW_KEY,
1185 value_list_scrolled_win);
1186 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_OK_BT_KEY, ok_bt);
1188 g_signal_connect(window, "delete_event", G_CALLBACK(dfilter_expr_dlg_delete_event_cb), window);
1191 * Catch the "destroy" signal on our top-level window, and,
1192 * when it's destroyed, disconnect the signal we'll be
1195 g_signal_connect(window, "destroy", G_CALLBACK(dfilter_expr_dlg_destroy_cb), filter_te);
1198 * Catch the "destroy" signal on the text entry widget to which
1199 * we're attached; if it's destroyed, we should destroy ourselves
1202 g_signal_connect(filter_te, "destroy", G_CALLBACK(dfilter_expr_dlg_cancel_cb), window);
1204 gtk_widget_show_all(window);
1205 window_present(window);