Fix the wireless settings button for AirPCap devices in the
[obnox/wireshark/wip.git] / gtk / proto_hier_stats_dlg.c
1 /* proto_hier_stats_dlg.c
2  *
3  * $Id$
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  */
23
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <stdio.h>
30 #include <string.h>
31
32 #include <gtk/gtk.h>
33
34 #include "../proto_hier_stats.h"
35 #include "../simple_dialog.h"
36
37 #include "gtk/proto_hier_stats_dlg.h"
38 #include "gtk/dlg_utils.h"
39 #include "gtk/gui_utils.h"
40 #include "gtk/filter_utils.h"
41 #include "gtk/gtkglobals.h"
42 #include "gtk/help_dlg.h"
43 #include "gtk/utf8_entities.h"
44
45
46 enum {
47     PROTOCOL_COLUMN,
48     PRCT_PKTS_COLUMN,
49     PKTS_COLUMN,
50     PRCT_BYTES_COLUMN,
51     BYTES_COLUMN,
52     BANDWIDTH_COLUMN,
53     END_PKTS_COLUMN,
54     END_BYTES_COLUMN,
55     END_BANDWIDTH_COLUMN,
56     FILTER_NAME,
57     PRCT_PKTS_VALUE_COLUMN,
58     PRCT_BYTES_VALUE_COLUMN,
59     NUM_STAT_COLUMNS /* must be the last */
60 };
61
62 typedef struct {
63     GtkTreeView  *tree_view;
64     GtkTreeIter  *iter;
65     ph_stats_t   *ps;
66 } draw_info_t;
67
68 static GtkWidget *tree;
69
70 #define PCT(x,y) (100.0 * (float)(x) / (float)(y))
71 #define BANDWIDTH(bytes,secs) ((bytes) * 8.0 / ((secs) * 1000.0 * 1000.0))
72
73 static void
74 proto_hier_select_filter_cb(GtkWidget *widget _U_, gpointer callback_data _U_, guint callback_action)
75 {
76     char *str = NULL;
77     const char *filter = NULL;
78     GtkTreeSelection *sel;
79     GtkTreeModel *model;
80     GtkTreeIter iter;
81
82     sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(tree));
83     gtk_tree_selection_get_selected (sel, &model, &iter);
84     gtk_tree_model_get (model, &iter, FILTER_NAME, &filter, -1);
85     if (filter && 0 != strlen(filter)) {
86         str = g_strdup_printf("%s", filter);
87     } else {
88         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not acquire information to build a filter!\nTry expanding or choosing another item.");
89         return;
90     }
91
92     apply_selected_filter (callback_action, str);
93
94     g_free (str);
95 }
96
97
98 /* Action callbacks */
99 static void
100 apply_as_selected_cb(GtkWidget *widget, gpointer user_data)
101 {
102         proto_hier_select_filter_cb( widget , user_data, CALLBACK_MATCH(ACTYPE_SELECTED, 0));
103 }
104 static void
105 apply_as_not_selected_cb(GtkWidget *widget, gpointer user_data)
106 {
107         proto_hier_select_filter_cb( widget , user_data, CALLBACK_MATCH(ACTYPE_NOT_SELECTED, 0));
108 }
109 static void
110 apply_as_and_selected_cb(GtkWidget *widget, gpointer user_data)
111 {
112         proto_hier_select_filter_cb( widget , user_data, CALLBACK_MATCH(ACTYPE_AND_SELECTED, 0));
113 }
114 static void
115 apply_as_or_selected_cb(GtkWidget *widget, gpointer user_data)
116 {
117         proto_hier_select_filter_cb( widget , user_data, CALLBACK_MATCH(ACTYPE_OR_SELECTED, 0));
118 }
119 static void
120 apply_as_and_not_selected_cb(GtkWidget *widget, gpointer user_data)
121 {
122         proto_hier_select_filter_cb( widget , user_data, CALLBACK_MATCH(ACTYPE_AND_NOT_SELECTED, 0));
123 }
124 static void
125 apply_as_or_not_selected_cb(GtkWidget *widget, gpointer user_data)
126 {
127         proto_hier_select_filter_cb( widget , user_data, CALLBACK_MATCH(ACTYPE_OR_NOT_SELECTED, 0));
128 }
129
130 static void
131 prep_as_selected_cb(GtkWidget *widget, gpointer user_data)
132 {
133         proto_hier_select_filter_cb( widget , user_data, CALLBACK_PREPARE(ACTYPE_SELECTED, 0));
134 }
135 static void
136 prep_as_not_selected_cb(GtkWidget *widget, gpointer user_data)
137 {
138         proto_hier_select_filter_cb( widget , user_data, CALLBACK_PREPARE(ACTYPE_NOT_SELECTED, 0));
139 }
140 static void
141 prep_as_and_selected_cb(GtkWidget *widget, gpointer user_data)
142 {
143         proto_hier_select_filter_cb( widget , user_data, CALLBACK_PREPARE(ACTYPE_AND_SELECTED, 0));
144 }
145 static void
146 prep_as_or_selected_cb(GtkWidget *widget, gpointer user_data)
147 {
148         proto_hier_select_filter_cb( widget , user_data, CALLBACK_PREPARE(ACTYPE_OR_SELECTED, 0));
149 }
150 static void
151 prep_as_and_not_selected_cb(GtkWidget *widget, gpointer user_data)
152 {
153         proto_hier_select_filter_cb( widget , user_data, CALLBACK_PREPARE(ACTYPE_AND_NOT_SELECTED, 0));
154 }
155 static void
156 prep_as_or_not_selected_cb(GtkWidget *widget, gpointer user_data)
157 {
158         proto_hier_select_filter_cb( widget , user_data, CALLBACK_PREPARE(ACTYPE_OR_NOT_SELECTED, 0));
159 }
160
161 static void
162 find_selected_cb(GtkWidget *widget, gpointer user_data)
163 {
164         proto_hier_select_filter_cb( widget , user_data, CALLBACK_FIND_FRAME(ACTYPE_SELECTED, 0));
165 }
166 static void
167 find_not_selected_cb(GtkWidget *widget, gpointer user_data)
168 {
169         proto_hier_select_filter_cb( widget , user_data, CALLBACK_FIND_FRAME(ACTYPE_NOT_SELECTED, 0));
170 }
171 static void
172 find_prev_selected_cb(GtkWidget *widget, gpointer user_data)
173 {
174         proto_hier_select_filter_cb( widget , user_data, CALLBACK_FIND_PREVIOUS(ACTYPE_SELECTED, 0));
175 }
176 static void
177 find_prev_not_selected_cb(GtkWidget *widget, gpointer user_data)
178 {
179         proto_hier_select_filter_cb( widget , user_data, CALLBACK_FIND_PREVIOUS(ACTYPE_NOT_SELECTED, 0));
180 }
181 static void
182 find_next_selected_cb(GtkWidget *widget, gpointer user_data)
183 {
184         proto_hier_select_filter_cb( widget , user_data, CALLBACK_FIND_NEXT(ACTYPE_SELECTED, 0));
185 }
186 static void
187 find_next_not_selected_cb(GtkWidget *widget, gpointer user_data)
188 {
189         proto_hier_select_filter_cb( widget , user_data, CALLBACK_FIND_NEXT(ACTYPE_NOT_SELECTED, 0));
190 }
191 static void
192 color_selected_cb(GtkWidget *widget, gpointer user_data)
193 {
194         proto_hier_select_filter_cb( widget , user_data, CALLBACK_COLORIZE(ACTYPE_SELECTED, 0));
195 }
196
197
198 static const char *ui_desc_proto_hier_stats_filter_popup =
199 "<ui>\n"
200 "  <popup name='ProtoHierStatsFilterPopup'>\n"
201 "    <menu action='/Apply as Filter'>\n"
202 "      <menuitem action='/Apply as Filter/Selected'/>\n"
203 "      <menuitem action='/Apply as Filter/Not Selected'/>\n"
204 "      <menuitem action='/Apply as Filter/" UTF8_HORIZONTAL_ELLIPSIS " and Selected'/>\n"
205 "      <menuitem action='/Apply as Filter/" UTF8_HORIZONTAL_ELLIPSIS " or Selected'/>\n"
206 "      <menuitem action='/Apply as Filter/" UTF8_HORIZONTAL_ELLIPSIS " and not Selected'/>\n"
207 "      <menuitem action='/Apply as Filter/" UTF8_HORIZONTAL_ELLIPSIS " or not Selected'/>\n"
208 "    </menu>\n"
209 "    <menu action='/Prepare a Filter'>\n"
210 "      <menuitem action='/Prepare a Filter/Selected'/>\n"
211 "      <menuitem action='/Prepare a Filter/Not Selected'/>\n"
212 "      <menuitem action='/Prepare a Filter/" UTF8_HORIZONTAL_ELLIPSIS " and Selected'/>\n"
213 "      <menuitem action='/Prepare a Filter/" UTF8_HORIZONTAL_ELLIPSIS " or Selected'/>\n"
214 "      <menuitem action='/Prepare a Filter/" UTF8_HORIZONTAL_ELLIPSIS " and not Selected'/>\n"
215 "      <menuitem action='/Prepare a Filter/" UTF8_HORIZONTAL_ELLIPSIS " or not Selected'/>\n"
216 "    </menu>\n"
217 "    <menu action='/Find Frame'>\n"
218 "      <menu action='/Find Frame/Find Frame'>\n"
219 "        <menuitem action='/Find Frame/Selected'/>\n"
220 "        <menuitem action='/Find Frame/Not Selected'/>\n"
221 "      </menu>\n"
222 "      <menu action='/Find Frame/Find Next'>\n"
223 "        <menuitem action='/Find Next/Selected'/>\n"
224 "        <menuitem action='/Find Next/Not Selected'/>\n"
225 "      </menu>\n"
226 "      <menu action='/Find Frame/Find Previous'>\n"
227 "        <menuitem action='/Find Previous/Selected'/>\n"
228 "        <menuitem action='/Find Previous/Not Selected'/>\n"
229 "      </menu>\n"
230 "    </menu>\n"
231 "    <menu action='/Colorize Procedure'>\n"
232 "     <menuitem action='/Colorize Procedure/Colorize Protocol'/>\n"
233 "    </menu>\n"
234 "  </popup>\n"
235 "</ui>\n";
236
237 /*
238  * GtkActionEntry
239  * typedef struct {
240  *   const gchar     *name;
241  *   const gchar     *stock_id;
242  *   const gchar     *label;
243  *   const gchar     *accelerator;
244  *   const gchar     *tooltip;
245  *   GCallback  callback;
246  * } GtkActionEntry;
247  * const gchar *name;                   The name of the action.
248  * const gchar *stock_id;               The stock id for the action, or the name of an icon from the icon theme.
249  * const gchar *label;                  The label for the action. This field should typically be marked for translation,
250  *                                                              see gtk_action_group_set_translation_domain().
251  *                                                              If label is NULL, the label of the stock item with id stock_id is used.
252  * const gchar *accelerator;    The accelerator for the action, in the format understood by gtk_accelerator_parse().
253  * const gchar *tooltip;                The tooltip for the action. This field should typically be marked for translation,
254  *                              see gtk_action_group_set_translation_domain().
255  * GCallback callback;                  The function to call when the action is activated.
256  *
257  */
258 static const GtkActionEntry proto_hier_stats_popup_entries[] = {
259   { "/Apply as Filter",                                                 NULL, "Apply as Filter",                                NULL, NULL,                                                             NULL },
260   { "/Prepare a Filter",                                                NULL, "Prepare a Filter",                               NULL, NULL,                                                             NULL },
261   { "/Find Frame",                                                              NULL, "Find Frame",                                             NULL, NULL,                                                             NULL },
262   { "/Find Frame/Find Frame",                                   NULL, "Find Frame",                                             NULL, NULL,                                                             NULL },
263   { "/Find Frame/Find Next",                                    NULL, "Find Next" ,                                             NULL, NULL,                                                             NULL },
264   { "/Find Frame/Find Previous",                                NULL, "Find Previous",                                  NULL, NULL,                                                             NULL },
265   { "/Colorize Procedure",                                              NULL, "Colorize Procedure",                             NULL, NULL,                                                             NULL },
266   { "/Apply as Filter/Selected",                                NULL, "Selected",                                               NULL, "Selected",                                               G_CALLBACK(apply_as_selected_cb) },
267   { "/Apply as Filter/Not Selected",            NULL, "Not Selected",                           NULL, "Not Selected",                           G_CALLBACK(apply_as_not_selected_cb) },
268   { "/Apply as Filter/" UTF8_HORIZONTAL_ELLIPSIS " and Selected",               NULL, UTF8_HORIZONTAL_ELLIPSIS " and Selected",                         NULL, UTF8_HORIZONTAL_ELLIPSIS " and Selected",                         G_CALLBACK(apply_as_and_selected_cb) },
269   { "/Apply as Filter/" UTF8_HORIZONTAL_ELLIPSIS " or Selected",                        NULL, UTF8_HORIZONTAL_ELLIPSIS " or Selected",                          NULL, UTF8_HORIZONTAL_ELLIPSIS " or Selected",                          G_CALLBACK(apply_as_or_selected_cb) },
270   { "/Apply as Filter/" UTF8_HORIZONTAL_ELLIPSIS " and not Selected",   NULL, UTF8_HORIZONTAL_ELLIPSIS " and not Selected",                     NULL, UTF8_HORIZONTAL_ELLIPSIS " and not Selected",                     G_CALLBACK(apply_as_and_not_selected_cb) },
271   { "/Apply as Filter/" UTF8_HORIZONTAL_ELLIPSIS " or not Selected",            NULL, UTF8_HORIZONTAL_ELLIPSIS " or not Selected",                      NULL, UTF8_HORIZONTAL_ELLIPSIS " or not Selected",                      G_CALLBACK(apply_as_or_not_selected_cb) },
272   { "/Prepare a Filter/Selected",                               NULL, "Selected",                                               NULL, "selcted",                                                G_CALLBACK(prep_as_selected_cb) },
273   { "/Prepare a Filter/Not Selected",           NULL, "Not Selected",                           NULL, "Not Selected",                           G_CALLBACK(prep_as_not_selected_cb) },
274   { "/Prepare a Filter/" UTF8_HORIZONTAL_ELLIPSIS " and Selected",              NULL, UTF8_HORIZONTAL_ELLIPSIS " and Selected",                         NULL, UTF8_HORIZONTAL_ELLIPSIS " and Selected",                         G_CALLBACK(prep_as_and_selected_cb) },
275   { "/Prepare a Filter/" UTF8_HORIZONTAL_ELLIPSIS " or Selected",               NULL, UTF8_HORIZONTAL_ELLIPSIS " or Selected",                          NULL, UTF8_HORIZONTAL_ELLIPSIS " or Selected",                          G_CALLBACK(prep_as_or_selected_cb) },
276   { "/Prepare a Filter/" UTF8_HORIZONTAL_ELLIPSIS " and not Selected",  NULL, UTF8_HORIZONTAL_ELLIPSIS " and not Selected",                     NULL, UTF8_HORIZONTAL_ELLIPSIS " and not Selected",                     G_CALLBACK(prep_as_and_not_selected_cb) },
277   { "/Prepare a Filter/" UTF8_HORIZONTAL_ELLIPSIS " or not Selected",   NULL, UTF8_HORIZONTAL_ELLIPSIS " or not Selected",                      NULL, UTF8_HORIZONTAL_ELLIPSIS " or not Selected",                      G_CALLBACK(prep_as_or_not_selected_cb) },
278   { "/Find Frame/Selected",                                             NULL, "Selected",                                               NULL, "Selected",                                               G_CALLBACK(find_selected_cb) },
279   { "/Find Frame/Not Selected",                                 NULL, "Not Selected",                                   NULL, "Not Selected",                                   G_CALLBACK(find_not_selected_cb) },
280   { "/Find Previous/Selected",                                  NULL, "Selected",                                               NULL, "Selected",                                               G_CALLBACK(find_prev_selected_cb) },
281   { "/Find Previous/Not Selected",                              NULL, "Not Selected",                                   NULL, "Not Selected",                                   G_CALLBACK(find_prev_not_selected_cb) },
282   { "/Find Next/Selected",                                              NULL, "Selected",                                               NULL, "Selected",                                               G_CALLBACK(find_next_selected_cb) },
283   { "/Find Next/Not Selected",                                  NULL, "Not Selected",                                   NULL, "Not Selected",                                   G_CALLBACK(find_next_not_selected_cb) },
284   { "/Colorize Procedure/Colorize Protocol",    NULL, "Colorize Protocol",                              NULL, "Colorize Protocol",                              G_CALLBACK(color_selected_cb) },
285 };
286
287 static void
288 fill_in_tree_node(GNode *node, gpointer data)
289 {
290     ph_stats_node_t *stats = node->data;
291     draw_info_t     *di = data;
292     ph_stats_t      *ps = di->ps;
293     draw_info_t     child_di;
294     double          seconds;
295     gchar           *text[NUM_STAT_COLUMNS];
296     float           percent_packets, percent_bytes;
297     GtkTreeView     *tree_view = di->tree_view;
298     GtkTreeIter     *iter = di->iter;
299     GtkTreeStore    *store;
300     GtkTreeIter      new_iter;
301
302     seconds = ps->last_time - ps->first_time;
303
304     percent_packets = (float) PCT(stats->num_pkts_total, ps->tot_packets);
305     percent_bytes = (float) PCT(stats->num_bytes_total, ps->tot_bytes);
306     text[PROTOCOL_COLUMN] = (gchar *) (stats->hfinfo->name);
307     text[PRCT_PKTS_COLUMN] = g_strdup_printf("%.2f %%", percent_packets);
308     text[PKTS_COLUMN] = g_strdup_printf("%u", stats->num_pkts_total);
309     text[PRCT_BYTES_COLUMN] = g_strdup_printf("%.2f %%", percent_bytes);
310     text[BYTES_COLUMN] = g_strdup_printf("%u", stats->num_bytes_total);
311     if (seconds > 0.0) {
312         text[BANDWIDTH_COLUMN] = g_strdup_printf("%.3f",
313             BANDWIDTH(stats->num_bytes_total, seconds));
314     } else {
315         text[BANDWIDTH_COLUMN] = "n.c.";
316     }
317     text[END_PKTS_COLUMN] = g_strdup_printf("%u", stats->num_pkts_last);
318     text[END_BYTES_COLUMN] = g_strdup_printf("%u", stats->num_bytes_last);
319     if (seconds > 0.0) {
320         text[END_BANDWIDTH_COLUMN] = g_strdup_printf("%.3f",
321             BANDWIDTH(stats->num_bytes_last, seconds));
322     } else {
323         text[END_BANDWIDTH_COLUMN] = "n.c.";
324     }
325
326     store = GTK_TREE_STORE(gtk_tree_view_get_model(tree_view));
327     gtk_tree_store_append(store, &new_iter, iter);
328     gtk_tree_store_set(store, &new_iter,
329                        PROTOCOL_COLUMN, text[PROTOCOL_COLUMN],
330                        PRCT_PKTS_COLUMN, text[PRCT_PKTS_COLUMN],
331                        PKTS_COLUMN, text[PKTS_COLUMN],
332                        PRCT_BYTES_COLUMN, text[PRCT_BYTES_COLUMN],
333                        BYTES_COLUMN, text[BYTES_COLUMN],
334                        BANDWIDTH_COLUMN, text[BANDWIDTH_COLUMN],
335                        END_PKTS_COLUMN, text[END_PKTS_COLUMN],
336                        END_BYTES_COLUMN, text[END_BYTES_COLUMN],
337                        END_BANDWIDTH_COLUMN, text[END_BANDWIDTH_COLUMN],
338                        FILTER_NAME, stats->hfinfo->abbrev,
339                        PRCT_PKTS_VALUE_COLUMN, percent_packets,
340                        PRCT_BYTES_VALUE_COLUMN, percent_bytes,
341                        -1);
342
343     g_free(text[PRCT_PKTS_COLUMN]);
344     g_free(text[PKTS_COLUMN]);
345     g_free(text[PRCT_BYTES_COLUMN]);
346     g_free(text[BYTES_COLUMN]);
347     if (seconds > 0.0) g_free(text[BANDWIDTH_COLUMN]);
348     g_free(text[END_PKTS_COLUMN]);
349     g_free(text[END_BYTES_COLUMN]);
350     if (seconds > 0.0) g_free(text[END_BANDWIDTH_COLUMN]);
351
352     child_di.tree_view = tree_view;
353     child_di.iter = &new_iter;
354     child_di.ps = ps;
355
356     g_node_children_foreach(node, G_TRAVERSE_ALL,
357                             fill_in_tree_node, &child_di);
358 }
359
360 static void
361 fill_in_tree(GtkWidget *tree_lcl, ph_stats_t *ps)
362 {
363     draw_info_t di;
364
365     di.tree_view = GTK_TREE_VIEW(tree_lcl);
366     di.iter = NULL;
367     di.ps = ps;
368
369     g_node_children_foreach(ps->stats_tree, G_TRAVERSE_ALL,
370                             fill_in_tree_node, &di);
371 }
372
373
374 static gboolean
375 proto_hier_show_popup_menu_cb(GtkWidget *widget _U_, GdkEvent *event, GtkWidget *popup_menu_object)
376 {
377     GdkEventButton *bevent = (GdkEventButton *)event;
378
379     if (event->type==GDK_BUTTON_PRESS && bevent->button==3) {
380         /* If this is a right click on one of our columns, popup the context menu */
381         gtk_menu_popup(GTK_MENU(popup_menu_object), NULL, NULL, NULL, NULL, bevent->button, bevent->time);
382     }
383
384     return FALSE;
385 }
386
387 static void
388 proto_hier_create_popup_menu(void)
389 {
390
391         GtkUIManager *ui_manager;
392         GtkActionGroup *action_group;
393         GError *error = NULL;
394         GtkWidget *popup_menu_object;
395
396         action_group = gtk_action_group_new ("ProtoHierStatsTFilterPopupActionGroup");
397         gtk_action_group_add_actions (action_group,                                                                     /* the action group */
398                                                                 (gpointer)proto_hier_stats_popup_entries,               /* an array of action descriptions */
399                                                                 G_N_ELEMENTS(proto_hier_stats_popup_entries),   /* the number of entries */
400                                                                 NULL);                                                                                  /* data to pass to the action callbacks */
401
402         ui_manager = gtk_ui_manager_new ();
403         gtk_ui_manager_insert_action_group (ui_manager,
404                 action_group,
405                 0); /* the position at which the group will be inserted */
406         gtk_ui_manager_add_ui_from_string (ui_manager,ui_desc_proto_hier_stats_filter_popup, -1, &error);
407         if (error != NULL)
408     {
409         fprintf (stderr, "Warning: building proto hier ststs filter popup failed: %s\n",
410                 error->message);
411         g_error_free (error);
412         error = NULL;
413     }
414         popup_menu_object = gtk_ui_manager_get_widget(ui_manager, "/ProtoHierStatsFilterPopup");
415         g_signal_connect(tree, "button_press_event", G_CALLBACK(proto_hier_show_popup_menu_cb), popup_menu_object);
416
417 }
418
419 #define MAX_DLG_HEIGHT 450
420 #define DEF_DLG_WIDTH  700
421 static void
422 create_tree(GtkWidget *container, ph_stats_t *ps)
423 {
424     GtkWidget   *sw;
425     GtkTreeView       *tree_view;
426     GtkTreeStore      *store;
427     GtkCellRenderer   *renderer;
428     GtkTreeViewColumn *column;
429
430     /* Scrolled Window */
431     sw = scrolled_window_new(NULL, NULL);
432     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
433                                         GTK_SHADOW_IN);
434     gtk_container_add(GTK_CONTAINER(container), sw);
435
436     store = gtk_tree_store_new(NUM_STAT_COLUMNS, G_TYPE_STRING, G_TYPE_STRING,
437                                G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
438                                G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
439                                G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_FLOAT,
440                                G_TYPE_FLOAT);
441     tree = tree_view_new(GTK_TREE_MODEL(store));
442     g_object_unref(G_OBJECT(store));
443     tree_view = GTK_TREE_VIEW(tree);
444     gtk_tree_view_set_headers_visible(tree_view, TRUE);
445     gtk_tree_view_set_headers_clickable(tree_view, FALSE);
446     renderer = gtk_cell_renderer_text_new();
447     column = gtk_tree_view_column_new_with_attributes("Protocol", renderer,
448                                                       "text", PROTOCOL_COLUMN,
449                                                       NULL);
450     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
451     gtk_tree_view_append_column(tree_view, column);
452     renderer = gtk_cell_renderer_progress_new();
453     column = gtk_tree_view_column_new_with_attributes("% Packets", renderer,
454                                                       "text", PRCT_PKTS_COLUMN,
455                                                       "value", PRCT_PKTS_VALUE_COLUMN,
456                                                       NULL);
457     gtk_tree_view_column_set_expand(column, TRUE);
458     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
459     gtk_tree_view_append_column(tree_view, column);
460     renderer = gtk_cell_renderer_text_new();
461     column = gtk_tree_view_column_new_with_attributes("Packets", renderer,
462                                                       "text", PKTS_COLUMN,
463                                                       NULL);
464     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
465     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
466     gtk_tree_view_append_column(tree_view, column);
467     renderer = gtk_cell_renderer_progress_new();
468     column = gtk_tree_view_column_new_with_attributes("% Bytes", renderer,
469                                                       "text", PRCT_BYTES_COLUMN,
470                                                       "value", PRCT_BYTES_VALUE_COLUMN,
471                                                       NULL);
472     gtk_tree_view_column_set_expand(column, TRUE);
473     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
474     gtk_tree_view_append_column(tree_view, column);
475     renderer = gtk_cell_renderer_text_new();
476     column = gtk_tree_view_column_new_with_attributes("Bytes", renderer,
477                                                       "text", BYTES_COLUMN,
478                                                       NULL);
479     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
480     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
481     gtk_tree_view_append_column(tree_view, column);
482     renderer = gtk_cell_renderer_text_new();
483     column = gtk_tree_view_column_new_with_attributes("Mbit/s", renderer,
484                                                       "text", BANDWIDTH_COLUMN,
485                                                       NULL);
486     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
487     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
488     gtk_tree_view_append_column(tree_view, column);
489     renderer = gtk_cell_renderer_text_new();
490     column = gtk_tree_view_column_new_with_attributes("End Packets", renderer,
491                                                       "text", END_PKTS_COLUMN,
492                                                       NULL);
493     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
494     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
495     gtk_tree_view_append_column(tree_view, column);
496     renderer = gtk_cell_renderer_text_new();
497     column = gtk_tree_view_column_new_with_attributes("End Bytes", renderer,
498                                                       "text", END_BYTES_COLUMN,
499                                                       NULL);
500     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
501     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
502     gtk_tree_view_append_column(tree_view, column);
503     renderer = gtk_cell_renderer_text_new();
504     column = gtk_tree_view_column_new_with_attributes("End Mbit/s", renderer,
505                                                       "text", END_BANDWIDTH_COLUMN,
506                                                       NULL);
507     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
508     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
509     gtk_tree_view_append_column(tree_view, column);
510
511     /* Fill in the data. */
512     fill_in_tree(tree, ps);
513
514     gtk_widget_set_size_request(tree, DEF_DLG_WIDTH, MAX_DLG_HEIGHT);
515     gtk_tree_view_expand_all(tree_view);
516
517     proto_hier_create_popup_menu ();
518
519     gtk_container_add(GTK_CONTAINER(sw), tree);
520 }
521
522 void
523 proto_hier_stats_cb(GtkWidget *w _U_, gpointer d _U_)
524 {
525     ph_stats_t *ps;
526     GtkWidget  *dlg, *close_bt, *help_bt, *vbox, *bbox;
527     GtkWidget  *label;
528     char       title[256];
529     const char *current_filter;
530
531     /* Get the statistics. */
532     ps = ph_stats_new();
533     if (ps == NULL) {
534         /* The user gave up before we finished; don't pop up
535            a statistics window. */
536         return;
537     }
538
539     dlg = window_new(GTK_WINDOW_TOPLEVEL, "Wireshark: Protocol Hierarchy Statistics");
540
541     vbox = gtk_vbox_new(FALSE, 5);
542     gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
543     gtk_container_add(GTK_CONTAINER(dlg), vbox);
544
545     current_filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
546
547     if (current_filter && strlen(current_filter) != 0) {
548         g_snprintf(title, sizeof(title), "Display filter: %s", current_filter);
549     } else {
550         g_strlcpy(title, "Display filter: none", sizeof(title));
551     }
552     label = gtk_label_new(title);
553     gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
554
555     /* Data section */
556     create_tree(vbox, ps);
557
558     ph_stats_free(ps);
559
560     /* Button row. */
561     bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
562     gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
563     gtk_widget_show(bbox);
564
565     close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
566     window_set_cancel_button(dlg, close_bt, window_cancel_button_cb);
567
568     help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
569     g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_STATS_PROTO_HIERARCHY_DIALOG);
570
571     g_signal_connect(dlg, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
572
573     gtk_widget_show_all(dlg);
574     window_present(dlg);
575 }
576
577 /*
578  * Editor modelines
579  *
580  * Local Variables:
581  * c-basic-offset: 4
582  * tab-width: 8
583  * indent-tabs-mode: nil
584  * End:
585  *
586  * ex: set shiftwidth=4 tabstop=8 expandtab
587  * :indentSize=4:tabSize=8:noTabs=true:
588  */