3 * Allow the user to construct a subexpression of a display filter
4 * expression, testing a particular field; display the tree of fields
5 * and the relations and values with which it can be compared.
7 * Copyright 2000, Jeffrey C. Foster <jfoste@woodward.com> and
8 * Guy Harris <guy@alum.mit.edu>
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 2000 Gerald Combs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
30 * may want to check the enable field to decide if protocol should be in tree
31 * improve speed of dialog box creation
32 * - I believe this is slow because of tree widget creation.
33 * 1) could improve the widget
34 * 2) keep a copy in memory after the first time.
35 * user can pop multiple tree dialogs by pressing the "Tree" button multiple
36 * times. not a good thing.
37 * Sort the protocols and children
45 #include <epan/ftypes/ftypes-int.h>
47 #include "ui/simple_dialog.h"
49 #include "ui/gtk/gui_utils.h"
50 #include "ui/gtk/dlg_utils.h"
51 #include "ui/gtk/dfilter_expr_dlg.h"
52 #include "ui/gtk/proto_hier_tree_model.h"
55 #define E_DFILTER_EXPR_TREE_KEY "dfilter_expr_tree"
56 #define E_DFILTER_EXPR_CURRENT_VAR_KEY "dfilter_expr_current_var"
57 #define E_DFILTER_EXPR_RELATION_LIST_KEY "dfilter_expr_relation_list"
58 #define E_DFILTER_EXPR_RANGE_LABEL_KEY "dfilter_expr_range_label"
59 #define E_DFILTER_EXPR_RANGE_ENTRY_KEY "dfilter_expr_range_entry"
60 #define E_DFILTER_EXPR_VALUE_LABEL_KEY "dfilter_expr_value_label"
61 #define E_DFILTER_EXPR_VALUE_ENTRY_KEY "dfilter_expr_value_entry"
62 #define E_DFILTER_EXPR_VALUE_LIST_LABEL_KEY "dfilter_expr_value_list_label"
63 #define E_DFILTER_EXPR_VALUE_LIST_KEY "dfilter_expr_value_list"
64 #define E_DFILTER_EXPR_VALUE_LIST_SW_KEY "dfilter_expr_value_list_sw"
65 #define E_DFILTER_EXPR_OK_BT_KEY "dfilter_expr_accept_bt"
66 #define E_DFILTER_EXPR_VALUE_KEY "dfilter_expr_value"
68 static void show_relations(GtkWidget *relation_list, ftenum_t ftype);
69 static gboolean relation_is_presence_test(const char *string);
70 static void add_relation_list(GtkWidget *relation_list, const char *relation, gboolean sensitive);
71 static void build_boolean_values(GtkWidget *value_list_scrolled_win,
72 GtkWidget *value_list,
73 const true_false_string *values);
74 static void build_enum_values(GtkWidget *value_list_scrolled_win,
75 GtkWidget *value_list,
76 const value_string *values);
77 static void add_value_list_item(GtkWidget *value_list, const gchar *string,
79 static void display_value_fields(header_field_info *hfinfo,
80 gboolean is_comparison, GtkWidget *value_label,
81 GtkWidget *value_entry,
82 GtkWidget *value_list_label, GtkWidget *value_list,
83 GtkWidget *value_list_scrolled_win,
84 GtkWidget *range_label,
85 GtkWidget *range_entry);
88 * Note that this is called every time the user clicks on an item,
89 * whether it is already selected or not.
92 field_select_row_cb(GtkTreeSelection *sel, gpointer tree)
94 GtkWidget *window = (GtkWidget *)gtk_widget_get_toplevel((GtkWidget *)tree);
95 GtkWidget *relation_list = (GtkWidget *)g_object_get_data(G_OBJECT(window),
96 E_DFILTER_EXPR_RELATION_LIST_KEY);
97 GtkWidget *range_label = (GtkWidget *)g_object_get_data(G_OBJECT(window),
98 E_DFILTER_EXPR_RANGE_LABEL_KEY);
99 GtkWidget *range_entry = (GtkWidget *)g_object_get_data(G_OBJECT(window),
100 E_DFILTER_EXPR_RANGE_ENTRY_KEY);
101 GtkWidget *value_label = (GtkWidget *)g_object_get_data(G_OBJECT(window),
102 E_DFILTER_EXPR_VALUE_LABEL_KEY);
103 GtkWidget *value_entry = (GtkWidget *)g_object_get_data(G_OBJECT(window),
104 E_DFILTER_EXPR_VALUE_ENTRY_KEY);
105 GtkWidget *value_list_label = (GtkWidget *)g_object_get_data(G_OBJECT(window),
106 E_DFILTER_EXPR_VALUE_LIST_LABEL_KEY);
107 GtkWidget *value_list = (GtkWidget *)g_object_get_data(G_OBJECT(window),
108 E_DFILTER_EXPR_VALUE_LIST_KEY);
109 GtkWidget *value_list_scrolled_win = (GtkWidget *)g_object_get_data(G_OBJECT(window),
110 E_DFILTER_EXPR_VALUE_LIST_SW_KEY);
111 GtkWidget *ok_bt = (GtkWidget *)g_object_get_data(G_OBJECT(window),
112 E_DFILTER_EXPR_OK_BT_KEY);
113 header_field_info *hfinfo, *cur_hfinfo;
114 const char *value_type;
115 char value_label_string[1024+1]; /* XXX - should be large enough */
119 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
121 gtk_tree_model_get(model, &iter, 0, &hfinfo, -1);
124 * What was the item that was last selected?
126 cur_hfinfo = (header_field_info *)g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_CURRENT_VAR_KEY);
127 if (cur_hfinfo == hfinfo) {
129 * It's still selected; no need to change anything.
135 * Mark it as currently selected.
137 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_CURRENT_VAR_KEY, hfinfo);
139 show_relations(relation_list, hfinfo->type);
142 * Set the label for the value to indicate what type of value
145 value_type = ftype_pretty_name(hfinfo->type);
146 if (value_type != NULL) {
148 * Indicate what type of value it is.
150 g_snprintf(value_label_string, sizeof value_label_string,
151 "Value (%s)", value_type);
152 gtk_label_set_text(GTK_LABEL(value_label), value_label_string);
156 * Clear the entry widget for the value, as whatever
157 * was there before doesn't apply.
159 gtk_entry_set_text(GTK_ENTRY(value_entry), "");
161 switch (hfinfo->type) {
165 * The list of values should be the strings for "true"
166 * and "false"; show them in the value list.
168 build_boolean_values(value_list_scrolled_win, value_list,
169 (const true_false_string *)hfinfo->strings);
181 * If this has a value_string table (not a range_string table) associated with it,
182 * fill up the list of values, otherwise clear the list of values.
184 /* XXX: ToDo: Implement "range-string" filter ? */
185 if ((hfinfo->strings != NULL) &&
186 ! (hfinfo->display & BASE_RANGE_STRING) &&
187 ! (hfinfo->display & BASE_VAL64_STRING) &&
188 ! ((hfinfo->display & FIELD_DISPLAY_E_MASK) == BASE_CUSTOM)) {
189 const value_string *vals = (const value_string *)hfinfo->strings;
190 if (hfinfo->display & BASE_EXT_STRING)
191 vals = VALUE_STRING_EXT_VS_P((value_string_ext *)vals);
192 build_enum_values(value_list_scrolled_win, value_list, vals);
194 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
199 * Clear the list of values.
201 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
206 * Display various items for the value, as appropriate.
207 * The relation we start out with is never a comparison.
209 display_value_fields(hfinfo, FALSE, value_label, value_entry,
210 value_list_label, value_list, value_list_scrolled_win, range_label, range_entry);
213 * XXX - in browse mode, there always has to be something
214 * selected, so this should always be sensitive.
216 gtk_widget_set_sensitive(ok_bt, TRUE);
220 show_relations(GtkWidget *relation_list, ftenum_t ftype)
224 * Clear out the currently displayed list of relations.
226 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(relation_list))));
229 * Add the supported relations.
231 add_relation_list(relation_list, "is present", TRUE);
232 add_relation_list(relation_list, "==",
233 ftype_can_eq(ftype) || (ftype_can_slice(ftype) && ftype_can_eq(FT_BYTES)));
234 add_relation_list(relation_list, "!=",
235 ftype_can_ne(ftype) || (ftype_can_slice(ftype) && ftype_can_ne(FT_BYTES)));
236 add_relation_list(relation_list, ">",
237 ftype_can_gt(ftype) || (ftype_can_slice(ftype) && ftype_can_gt(FT_BYTES)));
239 add_relation_list(relation_list, "<",
240 ftype_can_lt(ftype) || (ftype_can_slice(ftype) && ftype_can_lt(FT_BYTES)));
241 add_relation_list(relation_list, ">=",
242 ftype_can_ge(ftype) || (ftype_can_slice(ftype) && ftype_can_ge(FT_BYTES)));
243 add_relation_list(relation_list, "<=",
244 ftype_can_le(ftype) || (ftype_can_slice(ftype) && ftype_can_le(FT_BYTES)));
245 add_relation_list(relation_list, "contains",
246 ftype_can_contains(ftype) || (ftype_can_slice(ftype) && ftype_can_contains(FT_BYTES)));
247 add_relation_list(relation_list, "matches",
248 ftype_can_matches(ftype) || (ftype_can_slice(ftype) && ftype_can_matches(FT_BYTES)));
250 gtk_tree_model_get_iter_first(gtk_tree_view_get_model(GTK_TREE_VIEW(relation_list)), &iter);
251 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list)), &iter);
255 * Given a string that represents a test to be made on a field, returns
256 * TRUE if it tests for the field's presence, FALSE otherwise.
259 relation_is_presence_test(const char *string)
261 return (strcmp(string, "is present") == 0);
265 add_relation_list(GtkWidget *relation_list, const char *relation, gboolean sensitive)
267 GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(relation_list)));
270 /* XXX: I currently see no way to insensitive the item,
271 * so for a first step, just don't show it (as before these changes :-) */
276 gtk_list_store_append(store, &iter);
277 gtk_list_store_set(store, &iter, 0, relation, -1);
281 relation_list_sel_cb(GtkTreeSelection *sel, gpointer user_data _U_)
283 GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(gtk_tree_selection_get_tree_view(sel)));
284 GtkWidget *range_label =
285 (GtkWidget *)g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_RANGE_LABEL_KEY);
286 GtkWidget *range_entry =
287 (GtkWidget *)g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_RANGE_ENTRY_KEY);
288 GtkWidget *value_label =
289 (GtkWidget *)g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LABEL_KEY);
290 GtkWidget *value_entry =
291 (GtkWidget *)g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_ENTRY_KEY);
292 GtkWidget *value_list_label =
293 (GtkWidget *)g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_LABEL_KEY);
294 GtkWidget *value_list =
295 (GtkWidget *)g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_KEY);
296 GtkWidget *value_list_scrolled_win =
297 (GtkWidget *)g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_SW_KEY);
298 header_field_info *hfinfo =
299 (header_field_info *)g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_CURRENT_VAR_KEY);
305 * What's the relation?
307 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
309 gtk_tree_model_get(model, &iter, 0, &item_str, -1);
312 * Update the display of various items for the value, as appropriate.
314 display_value_fields(hfinfo,
315 !relation_is_presence_test(item_str),
316 value_label, value_entry, value_list_label, value_list,
317 value_list_scrolled_win, range_label, range_entry);
322 build_boolean_values(GtkWidget *value_list_scrolled_win, GtkWidget *value_list,
323 const true_false_string *values)
325 static const true_false_string true_false = { "True", "False" };
326 GtkTreeSelection *sel;
329 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list));
332 * Clear out the items for the list, and put in the names
333 * from the value_string list.
335 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
338 * Put the list in single mode, so we don't get any selection
339 * events while we're building it (i.e., so we don't get any
340 * on a list item BEFORE WE GET TO SET THE DATA FOR THE LIST
341 * ITEM SO THAT THE HANDLER CAN HANDLE IT).
343 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
349 values = &true_false;
350 add_value_list_item(value_list, values->true_string, (gpointer) values);
351 add_value_list_item(value_list, values->false_string, NULL);
354 * OK, we're done, so we can finally put it in browse mode.
355 * Select the first item, so that the user doesn't have to, under
356 * the assumption that they're most likely to test if something
357 * is true, not false.
359 gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
360 gtk_tree_model_get_iter_first(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list)), &iter);
361 gtk_tree_selection_select_iter(sel, &iter);
363 gtk_widget_show_all(value_list_scrolled_win);
367 build_enum_values(GtkWidget *value_list_scrolled_win _U_, GtkWidget *value_list,
368 const value_string *values)
370 GtkTreeSelection *sel;
372 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list));
374 * Clear out the items for the list, and put in the names
375 * from the value_string list.
377 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
380 * Put the list in single mode, so we don't get any selection
381 * events while we're building it (i.e., so we don't get any
382 * on a list item BEFORE WE GET TO SET THE DATA FOR THE LIST
383 * ITEM SO THAT THE HANDLER CAN HANDLE IT).
385 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
390 while (values->strptr != NULL) {
391 add_value_list_item(value_list, values->strptr, (const gpointer) values);
396 * OK, we're done, so we can finally put it in browse mode.
398 gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
402 add_value_list_item(GtkWidget *value_list, const gchar *string, const gpointer data)
404 GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list)));
407 gtk_list_store_append(store, &iter);
408 gtk_list_store_set(store, &iter, 0, string, 1, data, -1);
412 * Show or hide the various values fields as appropriate for the field
413 * and currently-selected relation.
416 display_value_fields(header_field_info *hfinfo, gboolean is_comparison,
417 GtkWidget *value_label, GtkWidget *value_entry,
418 GtkWidget *value_list_label,
419 GtkWidget *value_list _U_,
420 GtkWidget *value_list_scrolled_win, GtkWidget *range_label,
421 GtkWidget *range_entry)
424 gboolean show_value_label = FALSE;
425 gboolean show_value_list = FALSE;
426 gboolean show_range = FALSE;
431 * this is an FT_NONE variable, in which case you can
432 * only check whether it's present or absent in the
437 * this is a Boolean variable, in which case you
438 * can't specify a value to compare with, you can
439 * only specify whether to test for the Boolean
440 * being true or to test for it being false
444 * this isn't a Boolean variable, in which case you
445 * can test for its presence in the protocol tree,
446 * and the relation is such a test, in
447 * which case you don't compare with a value
449 * so we hide the value entry.
452 switch (hfinfo->type) {
456 show_value_label = TRUE; /* XXX: Allow value entry (contrary to the comment above) ?? */
457 show_value_list = TRUE;
470 show_value_label = TRUE;
471 if ((hfinfo->strings != NULL) && !(hfinfo->display & BASE_RANGE_STRING)) {
473 * We have a list of values to show.
475 show_value_list = TRUE;
482 * There is no list of names for values; only show the value_label if needed.
485 show_value_label = TRUE;
489 gtk_widget_set_sensitive(value_label, show_value_label);
490 gtk_widget_set_sensitive(value_entry, show_value_label);
492 gtk_widget_set_sensitive(value_list_label, show_value_list);
493 gtk_widget_set_sensitive(value_list_scrolled_win, show_value_list);
496 * Is this a comparison, and are ranges supported by this type?
497 * If both are true, show the range stuff, otherwise hide it.
499 show_range = (is_comparison && ftype_can_slice(hfinfo->type));
500 gtk_widget_set_sensitive(range_label, show_range);
501 gtk_widget_set_sensitive(range_entry, show_range);
505 value_list_sel_cb(GtkTreeSelection *sel, gpointer value_entry_arg)
507 GtkWidget *value_entry = (GtkWidget *)value_entry_arg;
508 GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(gtk_tree_selection_get_tree_view(sel)));
511 header_field_info *hfinfo = (header_field_info *)g_object_get_data(G_OBJECT(window),
512 E_DFILTER_EXPR_CURRENT_VAR_KEY);
513 const value_string *value = NULL;
514 gchar *value_display_string = NULL;
516 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
518 gtk_tree_model_get(model, &iter, 1, &value, -1);
521 * This should either be a numeric type or a Boolean type.
523 if (hfinfo->type == FT_BOOLEAN) {
525 * Boolean type; if the value key for the selected item
526 * is non-null, it's the item for "true", otherwise it's
527 * the item for "false". Compare with 1 if we're
528 * testing for "true", and compare with 0 if we're
529 * testing for "false".
532 value_display_string = g_strdup("1");
534 value_display_string = g_strdup("0");
537 * Numeric type; get the value corresponding to the
538 * selected item, and display it in the base for this
541 switch ((hfinfo->display) & FIELD_DISPLAY_E_MASK) {
546 switch (hfinfo->type) {
552 value_display_string = g_strdup_printf("%u", value->value);
559 value_display_string = g_strdup_printf("%d", value->value);
563 g_assert_not_reached();
569 value_display_string = g_strdup_printf("0x%x", value->value);
573 value_display_string = g_strdup_printf("%#o", value->value);
577 g_assert_not_reached();
581 gtk_entry_set_text(GTK_ENTRY(value_entry), value_display_string);
582 g_free (value_display_string);
586 dfilter_report_bad_value(const char *format, ...)
588 char error_msg_buf[1024];
591 va_start(args, format);
592 g_vsnprintf(error_msg_buf, sizeof error_msg_buf, format, args);
595 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_msg_buf);
599 dfilter_expr_dlg_accept_cb(GtkWidget *w, gpointer filter_te_arg)
601 GtkWidget *filter_te = (GtkWidget *)filter_te_arg;
602 GtkWidget *window = gtk_widget_get_toplevel(w);
603 GtkWidget *relation_list =
604 (GtkWidget *)g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_RELATION_LIST_KEY);
605 GtkWidget *range_entry =
606 (GtkWidget *)g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_RANGE_ENTRY_KEY);
607 GtkWidget *value_entry =
608 (GtkWidget *)g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_ENTRY_KEY);
609 header_field_info *hfinfo;
611 gchar *range_str, *stripped_range_str;
612 gchar *value_str, *stripped_value_str;
616 gboolean can_compare;
623 * Get the variable to be tested.
625 hfinfo = (header_field_info *)g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_CURRENT_VAR_KEY);
628 * Get the relation operator to use.
630 if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list)),
632 gtk_tree_model_get(model, &iter, 0, &item_str, -1);
634 /* Nothing selected */
639 * Get the range to use, if any.
641 if (gtk_widget_get_sensitive(range_entry)) {
642 range_str = g_strdup(gtk_entry_get_text(GTK_ENTRY(range_entry)));
644 * XXX - strip this even for strings?
645 * Doing so for strings means you can't match a string that has
646 * leading or trailing whitespace, but you can't see trailing
647 * whitespace in a text field, so it's not clear that it's
648 * a good idea to allow that.
650 stripped_range_str = g_strstrip(range_str);
651 if (strcmp(stripped_range_str, "") == 0) {
653 * No range was specified.
657 stripped_range_str = NULL;
661 * XXX - check it for validity?
665 stripped_range_str = NULL;
669 * If a range was specified, the type of the LHS of the
670 * comparison is FT_BYTES; otherwise, it's the type of the field.
672 if (range_str == NULL)
673 ftype = hfinfo->type;
678 * Make sure the relation is valid for the type in question.
679 * We may be offering relations that the type of the field
680 * can't support, because the field's type supports slicing,
681 * and the relation *is* supported on byte strings.
683 if (strcmp(item_str, "==") == 0)
684 can_compare = ftype_can_eq(ftype);
685 else if (strcmp(item_str, "!=") == 0)
686 can_compare = ftype_can_ne(ftype);
687 else if (strcmp(item_str, ">") == 0)
688 can_compare = ftype_can_gt(ftype);
689 else if (strcmp(item_str, "<") == 0)
690 can_compare = ftype_can_lt(ftype);
691 else if (strcmp(item_str, ">=") == 0)
692 can_compare = ftype_can_ge(ftype);
693 else if (strcmp(item_str, "<=") == 0)
694 can_compare = ftype_can_le(ftype);
695 else if (strcmp(item_str, "contains") == 0)
696 can_compare = ftype_can_contains(ftype);
697 else if (strcmp(item_str, "matches") == 0)
698 can_compare = ftype_can_matches(ftype);
700 can_compare = TRUE; /* not a comparison */
702 if (range_str == NULL) {
703 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
704 "That field can't be tested with \"%s\".",
707 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
708 "Ranges of that field can't be tested with \"%s\".",
717 * Get the value to use, if any.
719 if (gtk_widget_get_sensitive(value_entry)) {
720 value_str = g_strdup(gtk_entry_get_text(GTK_ENTRY(value_entry)));
721 stripped_value_str = g_strstrip(value_str);
722 if (strcmp(stripped_value_str, "") == 0) {
724 * This field takes a value, but they didn't supply
727 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
728 "That field must be compared with a value, "
729 "but you didn't specify a value with which to "
738 * Make sure the value is valid.
740 * If no range string was specified, it must be valid
741 * for the type of the field; if a range string was
742 * specified, must be valid for FT_BYTES.
744 if (strcmp(item_str, "contains") == 0) {
745 fvalue = fvalue_from_unparsed(ftype, stripped_value_str, TRUE,
746 dfilter_report_bad_value);
749 fvalue = fvalue_from_unparsed(ftype, stripped_value_str, FALSE,
750 dfilter_report_bad_value);
752 if (fvalue == NULL) {
756 * The dialog box was already popped up by
757 * "dfilter_report_bad_value()".
767 stripped_value_str = NULL;
771 * Insert the expression at the current cursor position.
772 * If there's a non-whitespace character to the left of it,
773 * insert a blank first; if there's a non-whitespace character
774 * to the right of it, insert a blank after it.
776 pos = gtk_editable_get_position(GTK_EDITABLE(filter_te));
777 chars = gtk_editable_get_chars(GTK_EDITABLE(filter_te), pos, pos + 1);
778 if (strcmp(chars, "") != 0 && !g_ascii_isspace(chars[0]))
779 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
782 gtk_editable_insert_text(GTK_EDITABLE(filter_te), hfinfo->abbrev,
783 (gint) strlen(hfinfo->abbrev), &pos);
784 if (range_str != NULL) {
785 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "[", 1, &pos);
786 gtk_editable_insert_text(GTK_EDITABLE(filter_te),
787 stripped_range_str, (gint) strlen(stripped_range_str), &pos);
788 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "]", 1, &pos);
791 if (!relation_is_presence_test(item_str)) {
792 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
793 gtk_editable_insert_text(GTK_EDITABLE(filter_te), item_str,
794 (gint) strlen(item_str), &pos);
796 if (value_str != NULL) {
797 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
799 * XXX - we should do this by generating an appropriate display
800 * filter value string for this field; that requires us to have
801 * a "generate display filter string" method for every FT_ type.
803 switch (hfinfo->type) {
808 case FT_ABSOLUTE_TIME:
810 * Always put quotes around the string.
817 * If the string contains white space, put quotes around it.
819 quote_it = (strpbrk(stripped_value_str, " \t") != NULL);
824 * Put quotes around the string.
826 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "\"",
829 gtk_editable_insert_text(GTK_EDITABLE(filter_te),
830 stripped_value_str, (gint) strlen(stripped_value_str), &pos);
833 * Put quotes around the string.
835 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "\"",
840 chars = gtk_editable_get_chars(GTK_EDITABLE(filter_te), pos + 1, pos + 2);
841 if (strcmp(chars, "") != 0 && !g_ascii_isspace(chars[0]))
842 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
846 * Put the cursor after the expression we just entered into
847 * the text entry widget.
849 gtk_editable_set_position(GTK_EDITABLE(filter_te), pos);
852 * We're done; destroy the dialog box (which is the top-level
853 * widget for the "Accept" button).
855 window_destroy(window);
860 dfilter_expr_dlg_cancel_cb(GtkWidget *w _U_, gpointer parent_w)
863 * User pressed the cancel button; close the dialog box.
865 window_destroy(GTK_WIDGET(parent_w));
868 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()" */
870 dfilter_expr_dlg_delete_event_cb(GtkWidget *w _U_, GdkEvent *event _U_,
873 dfilter_expr_dlg_cancel_cb(NULL, parent_w);
878 dfilter_expr_dlg_destroy_cb(GtkWidget *w, gpointer filter_te)
881 * The dialog box is being destroyed; disconnect from the
882 * "destroy" signal on the text entry box to which we're
883 * attached, as the handler for that signal is supposed
884 * to destroy us, but we're already gone.
886 g_signal_handlers_disconnect_by_func(filter_te, dfilter_expr_dlg_cancel_cb, w);
890 dfilter_expr_dlg_new(GtkWidget *filter_te)
892 GtkWidget *window, *main_vb, *main_hb;
894 GtkWidget *field_vb, *field_tree_lb, *field_tree, *tree_scrolled_win;
896 GtkWidget *relation_vb, *relation_label, *relation_list, *relation_list_scrolled_win;
897 /* GtkWidget *relation_present_rb, *relation_equals_rb, *relation_unequals_rb,
898 *relation_greater_rb, *relation_less_rb,
899 *relation_greaterequal_rb, *relation_lessequal_rb,
900 *relation_contains_rb, *relation_matches_rb;*/
902 GtkWidget *value_vb, *value_label, *value_entry;
903 GtkWidget *value_list_label, *value_list_scrolled_win, *value_list;
904 GtkWidget *range_label, *range_entry;
906 GtkWidget *list_bb, *ok_bt, *cancel_bt;
907 ProtoHierTreeModel *store_proto;
909 GtkTreeSelection *selection;
910 GtkCellRenderer *renderer;
911 GtkTreeViewColumn *column;
912 GtkListStore *l_store;
913 GtkTreeSelection *l_sel;
915 proto_initialize_all_prefixes();
917 window = dlg_conf_window_new("Wireshark: Filter Expression");
918 gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
919 gtk_container_set_border_width(GTK_CONTAINER(window), 5);
921 main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE);
922 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
923 gtk_container_add(GTK_CONTAINER(window), main_vb);
925 main_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5, FALSE);
926 gtk_container_set_border_width(GTK_CONTAINER(main_hb), 5);
927 gtk_box_pack_start(GTK_BOX (main_vb), main_hb, TRUE, TRUE, 0);
929 field_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE);
930 gtk_container_set_border_width(GTK_CONTAINER(field_vb), 5);
931 gtk_box_pack_start(GTK_BOX (main_hb), field_vb, TRUE, TRUE, 0);
933 field_tree_lb = gtk_label_new("Field name");
934 gtk_misc_set_alignment(GTK_MISC(field_tree_lb), 0.0f, 0.0f);
935 gtk_box_pack_start(GTK_BOX(field_vb), field_tree_lb, FALSE, FALSE, 0);
937 tree_scrolled_win = scrolled_window_new(NULL, NULL);
938 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(tree_scrolled_win),
940 gtk_box_pack_start(GTK_BOX(field_vb), tree_scrolled_win, TRUE, TRUE, 0);
941 gtk_widget_set_size_request(tree_scrolled_win, 300, -1);
944 field_tree = tree_view_new(GTK_TREE_MODEL(NULL));
945 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(field_tree), FALSE);
946 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(field_tree));
947 gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
948 renderer = gtk_cell_renderer_text_new();
949 column = gtk_tree_view_column_new_with_attributes("Field name", renderer,
951 gtk_tree_view_append_column(GTK_TREE_VIEW(field_tree), column);
952 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
953 gtk_tree_view_column_set_sort_column_id(column, 0);
954 g_signal_connect(selection, "changed", G_CALLBACK(field_select_row_cb), field_tree);
955 gtk_container_add(GTK_CONTAINER(tree_scrolled_win), field_tree);
957 relation_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE);
958 gtk_container_set_border_width(GTK_CONTAINER(relation_vb), 5);
959 gtk_box_pack_start(GTK_BOX (main_hb), relation_vb, TRUE, TRUE, 0);
961 relation_label = gtk_label_new("Relation");
962 gtk_misc_set_alignment(GTK_MISC(relation_label), 0.0f, 0.0f);
963 gtk_box_pack_start(GTK_BOX(relation_vb), relation_label, FALSE, FALSE, 0);
965 relation_list_scrolled_win = scrolled_window_new(NULL, NULL);
966 /* never use a scrollbar in x direction, show the complete relation string */
967 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(relation_list_scrolled_win),
968 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
969 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(relation_list_scrolled_win),
972 l_store = gtk_list_store_new(1, G_TYPE_STRING);
973 relation_list = tree_view_new(GTK_TREE_MODEL(l_store));
974 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(relation_list), FALSE);
975 g_object_unref(G_OBJECT(l_store));
976 renderer = gtk_cell_renderer_text_new();
977 column = gtk_tree_view_column_new_with_attributes("relation", renderer,
979 gtk_tree_view_append_column(GTK_TREE_VIEW(relation_list), column);
980 l_sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list));
981 gtk_tree_selection_set_mode(l_sel, GTK_SELECTION_BROWSE);
982 gtk_container_add(GTK_CONTAINER(relation_list_scrolled_win), relation_list);
983 gtk_box_pack_start(GTK_BOX(relation_vb), relation_list_scrolled_win, TRUE, TRUE, 0);
986 * OK, show the relation label and range stuff as it would be
987 * with everything turned on, so it'll request as much space
988 * as it'll ever need, so the dialog box and widgets start out
989 * with the right sizes.
991 * XXX - this doesn't work. It *doesn't* request as much space
992 * as it'll ever need.
994 * XXX - FT_UINT8 doesn't support ranges, so even if it did work,
995 * it wouldn't work right.
997 * XXX - this no longer affects the range stuff, as that's
998 * controlled both by the type and by the relational operator
1001 show_relations(relation_list, FT_UINT8);
1004 relation_present_rb = gtk_radio_button_new_with_mnemonic_from_widget(NULL, "is present");
1005 gtk_box_pack_start(GTK_BOX(relation_vb), relation_present_rb, FALSE, FALSE, 0);
1007 relation_equals_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "==");
1008 gtk_box_pack_start(GTK_BOX(relation_vb), relation_equals_rb, FALSE, FALSE, 0);
1010 relation_unequals_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "!=");
1011 gtk_box_pack_start(GTK_BOX(relation_vb), relation_unequals_rb, FALSE, FALSE, 0);
1013 relation_greater_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), ">");
1014 gtk_box_pack_start(GTK_BOX(relation_vb), relation_greater_rb, FALSE, FALSE, 0);
1016 relation_less_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "<");
1017 gtk_box_pack_start(GTK_BOX(relation_vb), relation_less_rb, FALSE, FALSE, 0);
1019 relation_greaterequal_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), ">=");
1020 gtk_box_pack_start(GTK_BOX(relation_vb), relation_greaterequal_rb, FALSE, FALSE, 0);
1022 relation_lessequal_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "<=");
1023 gtk_box_pack_start(GTK_BOX(relation_vb), relation_lessequal_rb, FALSE, FALSE, 0);
1025 relation_contains_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "contains");
1026 gtk_box_pack_start(GTK_BOX(relation_vb), relation_contains_rb, FALSE, FALSE, 0);
1028 relation_matches_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "matches");
1029 gtk_box_pack_start(GTK_BOX(relation_vb), relation_matches_rb, FALSE, FALSE, 0);
1032 value_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE);
1033 gtk_container_set_border_width(GTK_CONTAINER(value_vb), 5);
1034 gtk_box_pack_start(GTK_BOX (main_hb), value_vb, TRUE, TRUE, 0);
1036 value_label = gtk_label_new("Value");
1037 gtk_misc_set_alignment(GTK_MISC(value_label), 0.0f, 0.0f);
1038 gtk_box_pack_start(GTK_BOX(value_vb), value_label, FALSE, FALSE, 0);
1040 value_entry = gtk_entry_new();
1041 gtk_box_pack_start(GTK_BOX(value_vb), value_entry, FALSE, FALSE, 0);
1043 value_list_label = gtk_label_new("Predefined values:");
1044 gtk_misc_set_alignment(GTK_MISC(value_list_label), 0.0f, 0.0f);
1045 gtk_box_pack_start(GTK_BOX(value_vb), value_list_label, FALSE, FALSE, 0);
1047 value_list_scrolled_win = scrolled_window_new(NULL, NULL);
1048 gtk_box_pack_start(GTK_BOX(value_vb), value_list_scrolled_win, TRUE,
1051 l_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
1052 value_list = tree_view_new(GTK_TREE_MODEL(l_store));
1053 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(value_list), FALSE);
1054 g_object_unref(G_OBJECT(l_store));
1055 renderer = gtk_cell_renderer_text_new();
1056 column = gtk_tree_view_column_new_with_attributes("value", renderer,
1058 gtk_tree_view_append_column(GTK_TREE_VIEW(value_list), column);
1059 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list)),
1060 "changed", G_CALLBACK(value_list_sel_cb), value_entry);
1063 * The value stuff may be hidden or shown depending on what
1064 * relation was selected; connect to the "changed" signal
1065 * for the relation list, so we can make that happen.
1067 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list)),
1068 "changed", G_CALLBACK(relation_list_sel_cb), NULL);
1069 l_sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list));
1070 gtk_tree_selection_set_mode(l_sel, GTK_SELECTION_SINGLE);
1071 #if ! GTK_CHECK_VERSION(3,8,0)
1072 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(value_list_scrolled_win),
1075 gtk_container_add(GTK_CONTAINER(value_list_scrolled_win),
1078 /* This remains hidden until an enumerated field is selected */
1081 * Put the items in the Tree; we don't want to do that until
1082 * we've constructed the value list and set the tree's
1083 * E_DFILTER_EXPR_VALUE_LIST_KEY data to point to it, and
1084 * constructed the "Accept" button and set the tree's
1085 * E_DFILTER_EXPR_OK_BT_KEY data to point to it, so that
1086 * when the list item is "helpfully" automatically selected for us
1087 * we're ready to cope with the selection signal.
1090 store_proto = proto_hier_tree_model_new();
1091 store = gtk_tree_model_sort_new_with_model(GTK_TREE_MODEL(store_proto));
1092 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), 1, GTK_SORT_ASCENDING);
1093 g_object_unref(G_OBJECT(store_proto));
1095 gtk_tree_view_set_model(GTK_TREE_VIEW(field_tree), GTK_TREE_MODEL(store));
1096 gtk_tree_view_set_search_column(GTK_TREE_VIEW(field_tree), 1);
1097 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(field_tree), TRUE);
1098 g_object_unref(G_OBJECT(store));
1100 range_label = gtk_label_new("Range (offset:length)");
1101 gtk_misc_set_alignment(GTK_MISC(range_label), 0.0f, 0.0f);
1102 gtk_box_pack_start(GTK_BOX(value_vb), range_label, FALSE, FALSE, 0);
1104 range_entry = gtk_entry_new();
1105 gtk_box_pack_start(GTK_BOX(value_vb), range_entry, FALSE, FALSE, 0);
1109 list_bb = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_CANCEL, NULL);
1110 gtk_box_pack_start(GTK_BOX(main_vb), list_bb, FALSE, FALSE, 0);
1111 gtk_container_set_border_width (GTK_CONTAINER (list_bb), 0);
1113 ok_bt = (GtkWidget *)g_object_get_data(G_OBJECT(list_bb), GTK_STOCK_OK);
1114 gtk_widget_set_sensitive(ok_bt, FALSE);
1115 g_signal_connect(ok_bt, "clicked", G_CALLBACK(dfilter_expr_dlg_accept_cb), filter_te);
1117 cancel_bt = (GtkWidget *)g_object_get_data(G_OBJECT(list_bb), GTK_STOCK_CANCEL);
1118 window_set_cancel_button(window, cancel_bt, NULL);
1119 g_signal_connect(cancel_bt, "clicked", G_CALLBACK(dfilter_expr_dlg_cancel_cb), window);
1121 gtk_widget_grab_default(ok_bt);
1123 /* Catch the "activate" signal on the range and value text entries,
1124 so that if the user types Return there, we act as if the "Accept"
1125 button had been selected, as happens if Return is typed if some
1126 widget that *doesn't* handle the Return key has the input focus. */
1127 dlg_set_activate(range_entry, ok_bt);
1128 dlg_set_activate(value_entry, ok_bt);
1130 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_RELATION_LIST_KEY, relation_list);
1131 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_RANGE_LABEL_KEY, range_label);
1132 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_RANGE_ENTRY_KEY, range_entry);
1133 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LABEL_KEY, value_label);
1134 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_ENTRY_KEY, value_entry);
1135 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_KEY, value_list);
1136 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_LABEL_KEY, value_list_label);
1137 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_SW_KEY,
1138 value_list_scrolled_win);
1139 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_OK_BT_KEY, ok_bt);
1141 g_signal_connect(window, "delete_event", G_CALLBACK(dfilter_expr_dlg_delete_event_cb), window);
1144 * Catch the "destroy" signal on our top-level window, and,
1145 * when it's destroyed, disconnect the signal we'll be
1148 g_signal_connect(window, "destroy", G_CALLBACK(dfilter_expr_dlg_destroy_cb), filter_te);
1151 * Catch the "destroy" signal on the text entry widget to which
1152 * we're attached; if it's destroyed, we should destroy ourselves
1155 g_signal_connect(filter_te, "destroy", G_CALLBACK(dfilter_expr_dlg_cancel_cb), window);
1157 gtk_widget_show_all(window);
1158 window_present(window);