http://bugs.ethereal.com/bugzilla/show_bug.cgi?id=377
[obnox/wireshark/wip.git] / gtk / stats_tree_stat.c
1 /* stats_tree_stat.c
2  * GTK Tap implementation of stats_tree
3  * 2005, Luis E. G. Ontanon
4  *
5  * $Id$
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <string.h>
31 #include <gtk/gtk.h>
32
33 #include <epan/stats_tree_priv.h>
34 #include <epan/report_err.h>
35
36 #include "simple_dialog.h"
37 #include "globals.h"
38 #include "gui_utils.h"
39 #include "dlg_utils.h"
40 #include "compat_macros.h"
41 #include "../stat_menu.h"
42 #include "../tap_dfilter_dlg.h"
43
44 struct _st_node_pres {
45 #if GTK_MAJOR_VERSION >= 2
46         GtkTreeIter*    iter;
47 #else
48         GtkCTreeNode*   node;
49 #endif
50 };
51
52 struct _tree_cfg_pres {
53         tap_dfilter_dlg* stat_dlg;
54 };
55
56 struct _tree_pres {
57         GString*        text;
58         GtkWidget*      win;
59
60 #if GTK_MAJOR_VERSION >= 2
61         GtkTreeStore*   store;
62         GtkWidget*      tree;
63 #else
64         GtkWidget*      ctree;
65 #endif
66 };
67
68 /* the columns of the tree pane */
69 enum _stat_tree_columns {
70         TITLE_COLUMN,
71         COUNT_COLUMN,
72         RATE_COLUMN,
73         PERCENT_COLUMN,
74         N_COLUMNS
75 };
76
77 /* used for converting numbers */
78 #define NUM_BUF_SIZE  32
79
80 /* creates the gtk representation for a stat_node
81  * node: the node
82  */
83 static void setup_gtk_node_pr(stat_node* node) {
84 #if GTK_MAJOR_VERSION >= 2
85         GtkTreeIter* parent =  NULL;
86 #else
87         GtkCTreeNode* parent = NULL;
88         static gchar *text[] = {
89                 NULL,
90                 "",
91                 "",
92                 ""
93         };
94 #endif
95         
96
97         node->pr = g_malloc(sizeof(st_node_pres));
98
99 #if GTK_MAJOR_VERSION >= 2
100         if (node->st->pr->store) {
101                 node->pr->iter = g_malloc0(sizeof(GtkTreeIter));
102
103                 if ( node->parent && node->parent->pr ) {
104                         parent = node->parent->pr->iter;
105                 }
106                 gtk_tree_store_append (node->st->pr->store, node->pr->iter, parent);
107                 gtk_tree_store_set(node->st->pr->store, node->pr->iter, TITLE_COLUMN, node->name, RATE_COLUMN, "", COUNT_COLUMN, "", -1);
108         }
109 #else
110         if (node->st->pr->ctree) {
111                 if ( node->parent && node->parent->pr ) {
112                         parent = node->parent->pr->node;
113                 }
114
115                 text[0] = node->name;
116                 node->pr->node = gtk_ctree_insert_node(GTK_CTREE(node->st->pr->ctree),
117                     parent, NULL, text, 0, NULL, NULL, NULL, NULL, FALSE, FALSE);
118                 if (!parent) {
119                         /* Force the children of the root node to be expanded. */
120                         gtk_ctree_expand(GTK_CTREE(node->st->pr->ctree),
121                             node->pr->node);
122                 }
123         }
124 #endif
125 }
126
127
128 static void draw_gtk_node(stat_node* node) {
129         static gchar value[NUM_BUF_SIZE];
130         static gchar rate[NUM_BUF_SIZE];
131         static gchar percent[NUM_BUF_SIZE];
132         stat_node* child;
133         
134         stats_tree_get_strs_from_node(node, value, rate, percent);
135         
136 #if GTK_MAJOR_VERSION >= 2
137         if (node->st->pr->store) {
138                 gtk_tree_store_set(node->st->pr->store, node->pr->iter,
139                                                    RATE_COLUMN, rate,
140                                                    COUNT_COLUMN, value,
141                                                    PERCENT_COLUMN, percent,
142                                                    -1);
143         }
144 #else
145         if (node->st->pr->ctree) {
146                 gtk_ctree_node_set_text(GTK_CTREE(node->st->pr->ctree),
147                                         node->pr->node, RATE_COLUMN, rate);
148                 gtk_ctree_node_set_text(GTK_CTREE(node->st->pr->ctree),
149                                         node->pr->node, COUNT_COLUMN, value);
150                 gtk_ctree_node_set_text(GTK_CTREE(node->st->pr->ctree),
151                                         node->pr->node, PERCENT_COLUMN, percent);
152         }
153 #endif
154         
155         if (node->children) {
156                 for (child = node->children; child; child = child->next )
157                         draw_gtk_node(child);
158         }
159 }
160
161 static void draw_gtk_tree( void *psp  ) {
162         stats_tree *st = psp;
163         stat_node* child;
164
165         for (child = st->root.children; child; child = child->next ) {
166                 draw_gtk_node(child);
167
168 #if GTK_MAJOR_VERSION >= 2
169                 gtk_tree_view_expand_row(GTK_TREE_VIEW(st->pr->tree),
170                                                                  gtk_tree_model_get_path(GTK_TREE_MODEL(st->pr->store),
171                                                                                                                  child->pr->iter),
172                                                                  FALSE);
173 #endif
174         }
175
176 }
177
178 void protect_thread_critical_region(void);
179 void unprotect_thread_critical_region(void);
180
181 static void free_gtk_tree(GtkWindow *win _U_, stats_tree *st)
182 {
183         
184         protect_thread_critical_region();
185         remove_tap_listener(st);
186         unprotect_thread_critical_region();
187         
188 #if GTK_MAJOR_VERSION >= 2
189         if (st->root.pr)
190                 st->root.pr->iter = NULL;
191 #endif
192         
193         stats_tree_free(st);
194         
195 }
196
197
198 /* initializes the stats_tree window */
199 static void init_gtk_tree(const char* optarg) {
200         guint8* abbr = stats_tree_get_abbr(optarg);
201         stats_tree* st = NULL;
202         stats_tree_cfg* cfg = NULL;
203         tree_pres* pr = g_malloc(sizeof(tree_pres));
204         guint8* title = NULL;
205         guint8* window_name = NULL;
206         GString* error_string;
207         GtkWidget *scr_win;
208         guint init_strlen;
209         GtkWidget *main_vb, *bbox, *bt_close;
210 #if GTK_MAJOR_VERSION >= 2
211         GtkTreeViewColumn* column;
212         GtkCellRenderer* renderer;
213 #else
214         static char *titles[] = {
215                 "Topic / Item",
216                 "Count",
217                 "Rate",
218                 "Percent",
219         };
220         int i;
221 #endif
222         
223         if (abbr) {
224                 cfg = stats_tree_get_cfg_by_abbr(abbr);
225                 
226                 if (cfg != NULL) {
227                         init_strlen = strlen(cfg->pr->stat_dlg->init_string);
228                         
229                         if (strncmp (optarg, cfg->pr->stat_dlg->init_string, init_strlen) == 0){
230                                 if (init_strlen == strlen(optarg)) {
231                                         st = stats_tree_new(cfg,pr,NULL);
232                                 } else { 
233                                         st = stats_tree_new(cfg,pr,((guint8*)optarg)+init_strlen+1);
234                                 }
235                                 
236                         } else {
237                                 st = stats_tree_new(cfg,pr,NULL);
238                         }
239                 } else {
240                         report_failure("no such stats_tree (%s) found in stats_tree registry",abbr);
241                 }
242                 g_free(abbr);
243                 
244         } else {
245                 report_failure("could not obtain stats_tree abbr from optarg");         
246         }
247
248         window_name = g_strdup_printf("%s Stats Tree", cfg->name);
249         
250         st->pr->win = window_new_with_geom(GTK_WINDOW_TOPLEVEL,window_name,window_name);
251         gtk_window_set_default_size(GTK_WINDOW(st->pr->win), 400, 400);
252         g_free(window_name);
253     
254         if(st->filter){
255                 title=g_strdup_printf("%s with filter: %s",cfg->name,st->filter);
256         } else {
257                 st->filter=NULL;
258                 title=g_strdup_printf("%s", cfg->name);
259         }
260         
261         gtk_window_set_title(GTK_WINDOW(st->pr->win), title);
262         g_free(title);
263
264         main_vb = gtk_vbox_new(FALSE, 3);
265         gtk_container_border_width(GTK_CONTAINER(main_vb), 12);
266         gtk_container_add(GTK_CONTAINER(st->pr->win), main_vb);
267
268         scr_win = scrolled_window_new(NULL, NULL);
269
270 #if GTK_MAJOR_VERSION >= 2
271         
272         st->pr->store = gtk_tree_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING,
273                                                                         G_TYPE_STRING, G_TYPE_STRING);
274         
275         st->pr->tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (st->pr->store));
276         
277         gtk_container_add( GTK_CONTAINER(scr_win), st->pr->tree);
278         
279         /* the columns */
280         renderer = gtk_cell_renderer_text_new ();
281         column = gtk_tree_view_column_new_with_attributes ("Topic / Item", renderer,
282                                                                                                            "text", TITLE_COLUMN,
283                                                                                                            NULL);
284         gtk_tree_view_column_set_resizable (column,TRUE);
285         gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE);
286         gtk_tree_view_append_column (GTK_TREE_VIEW (st->pr->tree), column);
287         
288         renderer = gtk_cell_renderer_text_new ();
289         column = gtk_tree_view_column_new_with_attributes ("Count", renderer,
290                                                                                                            "text", COUNT_COLUMN,
291                                                                                                            NULL);
292         
293         gtk_tree_view_column_set_resizable (column,TRUE);
294         gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE);
295         gtk_tree_view_append_column (GTK_TREE_VIEW (st->pr->tree), column);
296         
297         renderer = gtk_cell_renderer_text_new ();
298         column = gtk_tree_view_column_new_with_attributes ("Rate", renderer,
299                                                                                                            "text", RATE_COLUMN,
300                                                                                                            NULL);
301         gtk_tree_view_column_set_resizable (column,TRUE);
302         gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE);
303         gtk_tree_view_append_column (GTK_TREE_VIEW (st->pr->tree), column);
304         
305         renderer = gtk_cell_renderer_text_new ();
306         column = gtk_tree_view_column_new_with_attributes ("Percent", renderer,
307                                                                                                            "text", PERCENT_COLUMN,
308                                                                                                            NULL);
309         gtk_tree_view_column_set_resizable(column,TRUE);
310         gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE);
311         gtk_tree_view_append_column (GTK_TREE_VIEW (st->pr->tree), column);
312 #else
313
314         st->pr->ctree = gtk_ctree_new_with_titles (N_COLUMNS, 0, titles);
315         for (i = 0; i < N_COLUMNS; i++) {
316                 /*
317                  * XXX - unfortunately, GtkCTree columns can't be
318                  * both auto-resizing and resizeable.
319                  */
320                 gtk_clist_set_column_auto_resize(GTK_CLIST(st->pr->ctree), i,
321                     TRUE);
322         }
323         
324         gtk_container_add( GTK_CONTAINER(scr_win), st->pr->ctree);
325 #endif
326
327         gtk_container_add( GTK_CONTAINER(main_vb), scr_win);
328         
329         error_string = register_tap_listener( cfg->tapname,
330                                                                                   st,
331                                                                                   st->filter,
332                                                                                   NULL,
333                                                                                   stats_tree_packet,
334                                                                                   draw_gtk_tree);
335         
336         if (error_string) {
337                 /* error, we failed to attach to the tap. clean up */
338                 simple_dialog( ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str );
339                 /* destroy_stat_tree_window(st); */
340                 report_failure("stats_tree for: %s failed to attach to the tap: %s",cfg->name,error_string->str);
341                 g_string_free(error_string, TRUE);
342         }
343                 
344         /* Button row. */
345         bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
346         gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
347
348         bt_close = OBJECT_GET_DATA(bbox, GTK_STOCK_CLOSE);
349         window_set_cancel_button(st->pr->win, bt_close, window_cancel_button_cb);
350
351         SIGNAL_CONNECT(GTK_WINDOW(st->pr->win), "delete_event", window_delete_event_cb, NULL);
352         SIGNAL_CONNECT(GTK_WINDOW(st->pr->win), "destroy", free_gtk_tree, st);
353         
354         gtk_widget_show_all(st->pr->win);
355         window_present(st->pr->win);
356         
357 #if GTK_MAJOR_VERSION >= 2
358         gtk_tree_view_set_model(GTK_TREE_VIEW(st->pr->tree),GTK_TREE_MODEL(st->pr->store));
359 #endif
360         
361         st->cfg->init(st);
362
363         cf_retap_packets(&cfile);
364 }
365
366
367 static void register_gtk_stats_tree_tap (gpointer k _U_, gpointer v, gpointer p _U_) {
368         stats_tree_cfg* cfg = v;
369
370         cfg->pr = g_malloc(sizeof(tree_pres));
371         
372         cfg->pr->stat_dlg = g_malloc(sizeof(tap_dfilter_dlg));
373         
374         cfg->pr->stat_dlg->win_title = g_strdup_printf("%s Stats Tree",cfg->name);
375         cfg->pr->stat_dlg->init_string = g_strdup_printf("%s,tree",cfg->abbr);
376         cfg->pr->stat_dlg->tap_init_cb = init_gtk_tree;
377         cfg->pr->stat_dlg->index = -1;
378         
379         register_dfilter_stat(cfg->pr->stat_dlg, cfg->name,
380             REGISTER_STAT_GROUP_NONE);
381 }
382
383 static void free_tree_presentation(stats_tree* st) {
384         g_free(st->pr);
385 }
386
387 void
388 register_tap_listener_stats_tree_stat(void)
389 {
390         
391         stats_tree_presentation(register_gtk_stats_tree_tap,
392                                                         setup_gtk_node_pr, NULL,
393                                                         NULL,
394                                                         NULL, NULL, free_tree_presentation, NULL, NULL, NULL);
395 }