st->name was moved to st->cfg->name
[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 /*
27  TODO:
28
29  - GTK1 something better than just a textbox
30  
31 */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include <string.h>
38 #include <gtk/gtk.h>
39
40 #include <epan/stats_tree_priv.h>
41
42 #include "simple_dialog.h"
43 #include "globals.h"
44 #include "tap_menu.h"
45 #include "ui_util.h"
46 #include "dlg_utils.h"
47 #include "compat_macros.h"
48 #include "tap_dfilter_dlg.h"
49 #include "../tap_dfilter_dlg.h"
50
51 struct _st_node_pres {
52 #if GTK_MAJOR_VERSION >= 2
53         GtkTreeIter*    iter;
54 #else
55         /* g_malloc(0) ??? */
56         void*           dummy;
57 #endif
58 };
59
60 struct _tree_cfg_pres {
61         tap_dfilter_dlg* stat_dlg;
62 };
63
64 struct _tree_pres {
65         GString*                text;
66         GtkWidget*              win;
67         
68 #if GTK_MAJOR_VERSION >= 2
69         GtkTreeStore*   store;
70         GtkWidget*              tree;
71 #else
72         GtkWidget*              textbox;
73 #endif
74 };
75
76 /* the columns of the tree pane */
77 enum _stat_tree_columns {
78         COUNT_COLUMN,
79         RATE_COLUMN,
80         TITLE_COLUMN,
81         PERCENT_COLUMN,
82         N_COLUMNS
83 };
84
85 /* used for converting numbers */
86 #define NUM_BUF_SIZE  32
87
88 /* creates the gtk representation for a stat_node
89  * node: the node
90  */
91 static void setup_gtk_node_pr(stat_node* node) {
92 #if GTK_MAJOR_VERSION >= 2
93         GtkTreeIter* parent =  NULL;
94 #endif
95         
96
97         node->pr = g_malloc(sizeof(st_node_pres));
98
99 #if GTK_MAJOR_VERSION >= 2
100         
101         if ( node->parent && node->parent->pr ) {
102                 parent = node->parent->pr->iter;
103         }
104         
105         if (node->st->pr->store) {
106                 node->pr->iter = g_malloc0(sizeof(GtkTreeIter));
107
108                 gtk_tree_store_append (node->st->pr->store, node->pr->iter, parent);
109                 gtk_tree_store_set(node->st->pr->store, node->pr->iter, TITLE_COLUMN, node->name, RATE_COLUMN, "", COUNT_COLUMN, "", -1);
110         }
111 #else
112         node->pr->dummy = NULL;
113         
114 #endif
115 }
116
117
118 #if GTK_MAJOR_VERSION >= 2
119 static void draw_gtk_node(stat_node* node) {
120         static gchar value[NUM_BUF_SIZE];
121         static gchar rate[NUM_BUF_SIZE];
122         static gchar percent[NUM_BUF_SIZE];
123         stat_node* child;
124         
125         get_strings_from_node(node, value, rate, percent);
126         
127         if (node->st->pr->store) {
128                 gtk_tree_store_set(node->st->pr->store, node->pr->iter,
129                                                    RATE_COLUMN, rate,
130                                                    COUNT_COLUMN, value,
131                                                    PERCENT_COLUMN, percent,
132                                                    -1);
133         }
134         
135         if (node->children) {
136                 for (child = node->children; child; child = child->next )
137                         draw_gtk_node(child);
138         }
139 }
140 #else
141 static void draw_gtk_node(stat_node* node _U_) {}
142 #endif
143
144 static void draw_gtk_tree( void *psp  ) {
145         stats_tree *st = psp;
146         stat_node* child;
147
148 #if GTK_MAJOR_VERSION >= 2
149
150         for (child = st->root.children; child; child = child->next ) {
151                 draw_gtk_node(child);
152         }
153 #else
154         GString* text = g_string_new("");
155         gchar* fmt;
156         
157         fmt = g_strdup_printf(" %%s%%-%us%%12s\t%%12s\t%%12s\n",stats_branch_max_name_len(&st->root,0));
158         g_string_sprintfa(text,fmt,"",st->cfg->name,"Value","Rate","Percent");
159         g_free(fmt);
160         g_string_sprintfa(text,"-------------------------------------------------------------------\n");
161
162         
163         for (child = st->root.children; child; child = child->next ) {
164                 stat_branch_to_str(child,text,0);
165         }
166         
167         gtk_text_freeze(GTK_TEXT(st->pr->textbox));
168         gtk_text_set_point(GTK_TEXT(st->pr->textbox),0);
169         gtk_text_forward_delete(GTK_TEXT(st->pr->textbox),gtk_text_get_length(GTK_TEXT(st->pr->textbox)));
170         gtk_text_insert(GTK_TEXT(st->pr->textbox),NULL,
171                                         NULL,NULL,text->str,-1);
172         gtk_text_thaw(GTK_TEXT(st->pr->textbox));
173         
174         g_string_free(text,TRUE);
175 #endif  
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         free_stats_tree(st);
194         
195 }
196
197
198 /* initializes the stats_tree window */
199 static void init_gtk_tree(char* optarg) {
200         guint8* abbr = get_st_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 #endif
214         
215         if (abbr) {
216                 cfg = get_stats_tree_by_abbr(abbr);
217                 
218                 if (cfg != NULL) {
219                         init_strlen = strlen(cfg->pr->stat_dlg->init_string);
220                         
221                         if (strncmp (optarg, cfg->pr->stat_dlg->init_string, init_strlen) == 0){
222                                 if (init_strlen == strlen(optarg)) {
223                                         st = new_stats_tree(cfg,pr,NULL);
224                                 } else { 
225                                         st = new_stats_tree(cfg,pr,((guint8*)optarg)+init_strlen+1);
226                                 }
227                                 
228                         } else {
229                                 st = new_stats_tree(cfg,pr,NULL);
230                         }
231                 } else {
232                         g_error("no such stats_tree (%s) found in stats_tree registry",abbr);
233                 }
234                 g_free(abbr);
235                 
236         } else {
237                 g_error("could not obtain stats_tree abbr from optarg");                
238         }
239
240         window_name = g_strdup_printf("%s Stats Tree", cfg->name);
241         
242         st->pr->win = window_new_with_geom(GTK_WINDOW_TOPLEVEL,window_name,window_name);
243         gtk_window_set_default_size(GTK_WINDOW(st->pr->win), 400, 400);
244         g_free(window_name);
245     
246         if(st->filter){
247                 title=g_strdup_printf("%s with filter: %s",cfg->name,st->filter);
248         } else {
249                 st->filter=NULL;
250                 title=g_strdup_printf("%s", cfg->name);
251         }
252         
253     gtk_window_set_title(GTK_WINDOW(st->pr->win), title);
254         g_free(title);
255
256         main_vb = gtk_vbox_new(FALSE, 3);
257         gtk_container_border_width(GTK_CONTAINER(main_vb), 12);
258         gtk_container_add(GTK_CONTAINER(st->pr->win), main_vb);
259
260     scr_win = scrolled_window_new(NULL, NULL);
261
262 #if GTK_MAJOR_VERSION >= 2
263         
264         st->pr->store = gtk_tree_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING,
265                                                                         G_TYPE_STRING, G_TYPE_STRING);
266         
267         st->pr->tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (st->pr->store));
268         
269         gtk_container_add( GTK_CONTAINER(scr_win), st->pr->tree);
270         gtk_container_add( GTK_CONTAINER(main_vb), scr_win);
271         
272         /* the columns */
273         renderer = gtk_cell_renderer_text_new ();
274         column = gtk_tree_view_column_new_with_attributes ("Topic / Item", renderer,
275                                                                                                            "text", TITLE_COLUMN,
276                                                                                                            NULL);
277         gtk_tree_view_column_set_resizable (column,TRUE);
278         gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE);
279         gtk_tree_view_append_column (GTK_TREE_VIEW (st->pr->tree), column);
280         
281         renderer = gtk_cell_renderer_text_new ();
282         column = gtk_tree_view_column_new_with_attributes ("Count", renderer,
283                                                                                                            "text", COUNT_COLUMN,
284                                                                                                            NULL);
285         
286         gtk_tree_view_column_set_resizable (column,TRUE);
287         gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE);
288         gtk_tree_view_append_column (GTK_TREE_VIEW (st->pr->tree), column);
289         
290         renderer = gtk_cell_renderer_text_new ();
291         column = gtk_tree_view_column_new_with_attributes ("Rate", renderer,
292                                                                                                            "text", RATE_COLUMN,
293                                                                                                            NULL);
294         gtk_tree_view_column_set_resizable (column,TRUE);
295         gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE);
296         gtk_tree_view_append_column (GTK_TREE_VIEW (st->pr->tree), column);
297         
298         renderer = gtk_cell_renderer_text_new ();
299         column = gtk_tree_view_column_new_with_attributes ("Percent", renderer,
300                                                                                                            "text", PERCENT_COLUMN,
301                                                                                                            NULL);
302         gtk_tree_view_column_set_resizable(column,TRUE);
303         gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE);
304         gtk_tree_view_append_column (GTK_TREE_VIEW (st->pr->tree), column);
305 #else
306         st->pr->textbox = gtk_text_new(NULL,NULL);
307         gtk_text_set_editable(GTK_TEXT(st->pr->textbox),TRUE);
308         gtk_container_add( GTK_CONTAINER(scr_win), GTK_WIDGET(st->pr->textbox));
309         gtk_container_add( GTK_CONTAINER(main_vb), scr_win);
310 #endif
311         
312         error_string = register_tap_listener( cfg->tapname,
313                                                                                   st,
314                                                                                   st->filter,
315                                                                                   NULL,
316                                                                                   stats_tree_packet,
317                                                                                   draw_gtk_tree);
318         
319         if (error_string) {
320                 /* error, we failed to attach to the tap. clean up */
321                 simple_dialog( ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str );
322                 /* destroy_stat_tree_window(st); */
323                 g_error("stats_tree for: %s failed to attach to the tap: %s",cfg->name,error_string->str);
324                 g_string_free(error_string, TRUE);
325         }
326                 
327         /* Button row. */
328     bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
329     gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
330
331     bt_close = OBJECT_GET_DATA(bbox, GTK_STOCK_CLOSE);
332     window_set_cancel_button(st->pr->win, bt_close, window_cancel_button_cb);
333
334         SIGNAL_CONNECT(GTK_WINDOW(st->pr->win), "delete_event", window_delete_event_cb, NULL);
335         SIGNAL_CONNECT(GTK_WINDOW(st->pr->win), "destroy", free_gtk_tree, st);
336         
337         gtk_widget_show_all(st->pr->win);
338         window_present(st->pr->win);
339         
340 #if GTK_MAJOR_VERSION >= 2
341         gtk_tree_view_set_model(GTK_TREE_VIEW(st->pr->tree),GTK_TREE_MODEL(st->pr->store));
342 #endif
343         
344         st->cfg->init(st);
345
346         cf_retap_packets(&cfile);
347 }
348
349
350 static void register_gtk_stats_tree_tap (gpointer k _U_, gpointer v, gpointer p _U_) {
351         stats_tree_cfg* cfg = v;
352         guint8* s;
353
354         s = g_strdup_printf("%s,tree",cfg->abbr);
355         
356         register_ethereal_tap(s, init_gtk_tree);
357         
358         cfg->pr = g_malloc(sizeof(tree_pres));
359         
360         cfg->pr->stat_dlg = g_malloc(sizeof(tap_dfilter_dlg));
361         
362         cfg->pr->stat_dlg->win_title = g_strdup_printf("%s Stats Tree",cfg->name);
363         cfg->pr->stat_dlg->init_string = g_strdup_printf("%s,tree",cfg->abbr);
364         cfg->pr->stat_dlg->tap_init_cb = init_gtk_tree;
365         cfg->pr->stat_dlg->index = -1;
366         
367         register_tap_menu_item(cfg->name, REGISTER_TAP_GROUP_NONE,
368                                                    gtk_tap_dfilter_dlg_cb, NULL, NULL, cfg->pr->stat_dlg);
369 }
370
371 static void free_tree_presentation(stats_tree* st) {
372         g_free(st->pr);
373 }
374
375 void
376 register_tap_listener_stats_tree_stat(void)
377 {
378         
379         stats_tree_presentation(register_gtk_stats_tree_tap,
380                                                         setup_gtk_node_pr, NULL,
381                                                         NULL,
382                                                         NULL, NULL, free_tree_presentation, NULL, NULL, NULL);
383 }