1 /* prefs_filter_expressions.c
2 * Submitted by Edwin Groothuis <wireshark@mavetju.org>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include <epan/prefs.h>
32 #include <epan/column-info.h>
33 #include <epan/column.h>
34 #include <epan/strutil.h>
35 #include <epan/filter_expressions.h>
37 #include "../globals.h"
39 #include "ui/gtk/gtkglobals.h"
40 #include "ui/gtk/gui_utils.h"
41 #include "ui/gtk/packet_list.h"
42 #include "ui/gtk/filter_dlg.h"
43 #include "ui/gtk/filter_autocomplete.h"
44 #include "ui/gtk/filter_expression_save_dlg.h"
45 #include "ui/gtk/prefs_filter_expressions.h"
46 #include "ui/gtk/old-gtk-compat.h"
48 static void filter_expressions_list_new_cb(GtkWidget
*, gpointer
);
49 static void filter_expressions_list_remove_cb(GtkWidget
*, gpointer
);
50 static gboolean
filter_expressions_label_changed_cb(GtkCellRendererText
*, const gchar
*, const gchar
*, gpointer
);
51 static gboolean
filter_expressions_expression_changed_cb(GtkCellRendererText
*, const gchar
*, const gchar
*, gpointer
);
53 #define E_FILTER_EXPRESSION_COLUMNL "filter_expression_columnl"
54 #define E_FILTER_EXPRESSION_STORE "filter_expression_store"
61 N_COLUMN
/* The number of columns */
66 enable_toggled(GtkCellRendererToggle
*cell _U_
, gchar
*path_str
, gpointer data
)
68 GtkTreeModel
*model
= (GtkTreeModel
*)data
;
70 GtkTreePath
*path
= gtk_tree_path_new_from_string(path_str
);
71 struct filter_expression
*fe
;
73 gtk_tree_model_get_iter(model
, &iter
, path
);
74 gtk_tree_model_get(model
, &iter
, DATA_COLUMN
, &fe
, -1);
76 fe
->enabled
= !fe
->enabled
;
78 gtk_list_store_set(GTK_LIST_STORE(model
), &iter
, ENABLED_COLUMN
,
81 gtk_tree_path_free(path
);
82 } /* visible_toggled */
85 * Create and display the column selection widgets.
86 * Called as part of the creation of the Preferences notebook ( Edit ! Preferences )
89 filter_expressions_prefs_show(void) {
90 GtkWidget
*main_vb
, *bottom_hb
, *column_l
, *add_bt
, *remove_bt
;
91 GtkWidget
*list_vb
, *list_lb
, *list_sc
;
92 GtkWidget
*add_remove_hb
;
94 GtkCellRenderer
*renderer
;
95 GtkTreeViewColumn
*column
;
96 GtkTreeSelection
*sel
;
98 GtkTreeIter first_iter
;
99 gint first_row
= TRUE
;
100 struct filter_expression
*fe
;
101 static const gchar
*column_titles
[] = {"Enabled", "Label", "Filter Expression"};
103 /* Container for each row of widgets */
104 main_vb
= ws_gtk_box_new(GTK_ORIENTATION_VERTICAL
, 5, FALSE
);
105 gtk_container_set_border_width(GTK_CONTAINER(main_vb
), 5);
106 gtk_widget_show(main_vb
);
108 list_vb
= ws_gtk_box_new(GTK_ORIENTATION_VERTICAL
, 0, FALSE
);
109 gtk_container_set_border_width(GTK_CONTAINER(list_vb
), 5);
110 gtk_widget_show(list_vb
);
111 gtk_box_pack_start(GTK_BOX(main_vb
), list_vb
, TRUE
, TRUE
, 0);
113 list_lb
= gtk_label_new(("[The first list entry will be displayed as the "
114 "first button right of the Save button - Drag and drop entries to "
115 "change column order]"));
116 gtk_widget_show(list_lb
);
117 gtk_box_pack_start(GTK_BOX(list_vb
), list_lb
, FALSE
, FALSE
, 0);
119 list_sc
= scrolled_window_new(NULL
, NULL
);
120 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(list_sc
),
122 gtk_box_pack_start(GTK_BOX(list_vb
), list_sc
, TRUE
, TRUE
, 0);
123 gtk_widget_show(list_sc
);
125 store
= gtk_list_store_new(N_COLUMN
,
126 G_TYPE_BOOLEAN
, G_TYPE_STRING
, G_TYPE_STRING
,
129 column_l
= tree_view_new(GTK_TREE_MODEL(store
));
130 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(column_l
), TRUE
);
131 gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(column_l
), FALSE
);
132 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(column_l
), TRUE
);
133 gtk_widget_set_tooltip_text(column_l
, "Click on a label or expression to "
134 "change its name.\nDrag an item to change its order.\nTick 'Enable' "
135 "to enable the filter in the buttons.");
138 renderer
= gtk_cell_renderer_toggle_new();
139 g_signal_connect(renderer
, "toggled", G_CALLBACK(enable_toggled
), store
);
140 column
= gtk_tree_view_column_new_with_attributes(
141 column_titles
[ENABLED_COLUMN
], renderer
, "active", ENABLED_COLUMN
, NULL
);
142 gtk_tree_view_column_set_sizing(column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
143 gtk_tree_view_append_column(GTK_TREE_VIEW(column_l
), column
);
146 renderer
= gtk_cell_renderer_text_new();
147 g_object_set(G_OBJECT(renderer
), "editable", TRUE
, NULL
);
148 g_signal_connect(renderer
, "edited",
149 G_CALLBACK(filter_expressions_label_changed_cb
), GTK_TREE_MODEL(store
));
150 column
= gtk_tree_view_column_new_with_attributes(
151 column_titles
[LABEL_COLUMN
], renderer
, "text", LABEL_COLUMN
, NULL
);
152 gtk_tree_view_column_set_sizing(column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
153 gtk_tree_view_append_column(GTK_TREE_VIEW(column_l
), column
);
155 /* Expression editor */
156 renderer
= gtk_cell_renderer_text_new();
157 g_object_set(G_OBJECT(renderer
), "editable", TRUE
, NULL
);
158 g_signal_connect(renderer
, "edited",
159 G_CALLBACK(filter_expressions_expression_changed_cb
),
160 GTK_TREE_MODEL(store
));
161 column
= gtk_tree_view_column_new_with_attributes(
162 column_titles
[EXPRESSION_COLUMN
], renderer
, "text", EXPRESSION_COLUMN
, NULL
);
163 gtk_tree_view_column_set_sizing(column
, GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
164 gtk_tree_view_append_column(GTK_TREE_VIEW(column_l
), column
);
166 /* XXX - make this match the packet list prefs? */
167 sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(column_l
));
168 gtk_tree_selection_set_mode(sel
, GTK_SELECTION_SINGLE
);
170 gtk_container_add(GTK_CONTAINER(list_sc
), column_l
);
171 gtk_widget_show(column_l
);
173 fe
= *pfilter_expression_head
;
176 gtk_list_store_insert_with_values(store
, &iter
, G_MAXINT
,
177 ENABLED_COLUMN
, fe
->enabled
,
178 LABEL_COLUMN
, fe
->label
,
179 EXPRESSION_COLUMN
, fe
->expression
,
189 g_object_unref(G_OBJECT(store
));
191 /* Bottom row: Add/remove buttons */
192 bottom_hb
= ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 5, FALSE
);
193 gtk_box_pack_start(GTK_BOX(main_vb
), bottom_hb
, FALSE
, TRUE
, 0);
194 gtk_widget_show(bottom_hb
);
197 add_remove_hb
= ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 0, TRUE
);
198 gtk_container_set_border_width(GTK_CONTAINER(add_remove_hb
), 5);
199 gtk_box_pack_start(GTK_BOX(bottom_hb
), add_remove_hb
, FALSE
, FALSE
, 0);
200 gtk_widget_show(add_remove_hb
);
202 add_bt
= gtk_button_new_from_stock(GTK_STOCK_ADD
);
203 g_signal_connect(add_bt
, "clicked",
204 G_CALLBACK(filter_expressions_list_new_cb
), column_l
);
205 gtk_box_pack_start(GTK_BOX(add_remove_hb
), add_bt
, FALSE
, FALSE
, 0);
206 gtk_widget_set_tooltip_text(add_bt
,
207 "Add a new row at the end of the list.");
208 gtk_widget_show(add_bt
);
211 remove_bt
= gtk_button_new_from_stock(GTK_STOCK_REMOVE
);
212 g_signal_connect(remove_bt
, "clicked",
213 G_CALLBACK(filter_expressions_list_remove_cb
), column_l
);
214 gtk_box_pack_start(GTK_BOX(add_remove_hb
), remove_bt
, FALSE
, FALSE
, 0);
215 gtk_widget_set_tooltip_text(remove_bt
, "Remove the selected row.");
216 gtk_widget_show(remove_bt
);
218 /* select the first menu list row. */
219 /* Triggers call to column_list_select_cb(). */
220 if (first_row
== FALSE
)
221 gtk_tree_selection_select_iter(sel
, &first_iter
);
223 g_object_set_data(G_OBJECT(main_vb
), E_FILTER_EXPRESSION_COLUMNL
, column_l
);
224 g_object_set_data(G_OBJECT(main_vb
), E_FILTER_EXPRESSION_STORE
, store
);
230 filter_expressions_list_remove_cb(GtkWidget
*w _U_
, gpointer data
)
232 GtkTreeView
*column_l
= GTK_TREE_VIEW(data
);
233 GtkTreeSelection
*sel
;
236 struct filter_expression
*fe
;
238 sel
= gtk_tree_view_get_selection(column_l
);
239 if (!gtk_tree_selection_get_selected(sel
, &model
, &iter
))
242 gtk_tree_model_get(model
, &iter
, DATA_COLUMN
, &fe
, -1);
245 gtk_list_store_remove(GTK_LIST_STORE(model
), &iter
);
249 filter_expressions_list_new_cb(GtkWidget
*w _U_
, gpointer data _U_
)
251 const gchar
*label
= "New Label";
252 const gchar
*expression
= "New Expression";
253 GtkTreeView
*fe_l
= GTK_TREE_VIEW(data
);
257 GtkTreeViewColumn
*label_column
;
258 struct filter_expression
*fe
;
260 fe
= filter_expression_new(label
, expression
, TRUE
);
262 model
= gtk_tree_view_get_model(fe_l
);
263 gtk_list_store_insert_with_values(GTK_LIST_STORE(model
), &iter
, G_MAXINT
,
264 ENABLED_COLUMN
, fe
->enabled
,
265 LABEL_COLUMN
, fe
->label
,
266 EXPRESSION_COLUMN
, fe
->expression
,
270 /* Triggers call to column_list_select_cb() */
271 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(fe_l
), &iter
);
273 /* Set the cursor to the 'Title' column of the newly added row and enable
275 * XXX: If displaying the new title ["New column"] widens the title column
276 * of the treeview, then the set_cursor below doesn't properly generate an
277 * entry box around the title text. The width of the box appears to be the
278 * column width before the treeview title column was widened. Seems like a
281 * I haven't found a work-around.
283 path
= gtk_tree_model_get_path(model
, &iter
);
284 label_column
= gtk_tree_view_get_column(fe_l
, 2);
285 gtk_tree_view_set_cursor(fe_l
, path
, label_column
, TRUE
);
286 gtk_tree_path_free(path
);
291 filter_expressions_expression_changed_cb(GtkCellRendererText
*cell _U_
, const gchar
*str_path
, const gchar
*new_expression
, gpointer data
)
293 struct filter_expression
*fe
;
294 GtkTreeModel
*model
= (GtkTreeModel
*)data
;
295 GtkTreePath
*path
= gtk_tree_path_new_from_string(str_path
);
298 gtk_tree_model_get_iter(model
, &iter
, path
);
299 gtk_list_store_set(GTK_LIST_STORE(model
), &iter
, EXPRESSION_COLUMN
,
302 gtk_tree_model_get(model
, &iter
, DATA_COLUMN
, &fe
, -1);
304 g_free(fe
->expression
);
305 fe
->expression
= g_strdup(new_expression
);
308 gtk_tree_path_free(path
);
313 filter_expressions_label_changed_cb(GtkCellRendererText
*cell _U_
, const gchar
*str_path
, const gchar
*new_label
, gpointer data
)
315 struct filter_expression
*fe
;
316 GtkTreeModel
*model
= (GtkTreeModel
*)data
;
317 GtkTreePath
*path
= gtk_tree_path_new_from_string(str_path
);
320 gtk_tree_model_get_iter(model
, &iter
, path
);
321 gtk_list_store_set(GTK_LIST_STORE(model
), &iter
, LABEL_COLUMN
, new_label
, -1);
323 gtk_tree_model_get(model
, &iter
, DATA_COLUMN
, &fe
, -1);
326 fe
->label
= g_strdup(new_label
);
329 gtk_tree_path_free(path
);
335 filter_expressions_prefs_fetch(GtkWidget
*w
)
339 GtkTreeView
*column_l
;
342 struct filter_expression
*fe
;
343 gint first_row
= TRUE
;
346 column_l
= (GtkTreeView
*)g_object_get_data(G_OBJECT(w
),
347 E_FILTER_EXPRESSION_COLUMNL
);
348 model
= gtk_tree_view_get_model(column_l
);
349 store
= (GtkListStore
*)g_object_get_data(G_OBJECT(w
),
350 E_FILTER_EXPRESSION_STORE
);
352 /* Record the order of the items in the list. */
353 items_left
= gtk_tree_model_get_iter_first(model
, &iter
);
355 gtk_tree_model_get(model
, &iter
, DATA_COLUMN
, &fe
, -1);
358 items_left
= gtk_tree_model_iter_next (model
, &iter
);
361 filter_expression_reinit(FILTER_EXPRESSION_REINIT_DESTROY
| FILTER_EXPRESSION_REINIT_CREATE
);
363 gtk_list_store_clear(store
);
364 fe
= *pfilter_expression_head
;
367 gtk_list_store_insert_with_values(store
, &iter
, G_MAXINT
,
368 ENABLED_COLUMN
, fe
->enabled
,
369 LABEL_COLUMN
, fe
->label
,
370 EXPRESSION_COLUMN
, fe
->expression
,
382 * Editor modelines - http://www.wireshark.org/tools/modelines.html
387 * indent-tabs-mode: nil
390 * vi: set shiftwidth=4 tabstop=8 expandtab:
391 * :indentSize=4:tabSize=8:noTabs=true: