Replace "svn" with "git" all over the place.
[metze/wireshark/wip.git] / ui / 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  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26   /* stats_tree modifications by Deon van der Westhuysen, November 2013
27   * support for
28   *  - sorting by column,
29   *  - display a generic number of columns(driven by stats_tree.c
30   *  - copy to clipboard
31   *  - export to text, CSV or XML file
32   */
33
34 #include "config.h"
35 #include <string.h>
36
37 #include <gtk/gtk.h>
38
39 #include <wsutil/report_err.h>
40 #include <wsutil/file_util.h>
41
42 #include <epan/stats_tree_priv.h>
43
44 #include "ui/simple_dialog.h"
45 #include "../globals.h"
46 #include "../stat_menu.h"
47
48 #include "ui/gtk/gui_utils.h"
49 #include "ui/gtk/dlg_utils.h"
50 #include "ui/gtk/file_dlg.h"
51 #include "ui/gtk/tap_param_dlg.h"
52 #include "ui/gtk/main.h"
53
54 #include "ui/gtk/old-gtk-compat.h"
55
56 #include "ui/gtk/gui_stat_menu.h"
57
58 #ifdef _WIN32
59 #define USE_WIN32_FILE_DIALOGS
60 #endif
61
62 #ifdef USE_WIN32_FILE_DIALOGS
63 #include <gdk/gdkwin32.h>
64 #include <windows.h>
65 #include "ui/win32/file_dlg_win32.h"
66 #endif
67
68 void register_tap_listener_stats_tree_stat(void);
69
70 struct _st_node_pres {
71         GtkTreeIter*    iter;
72 };
73
74 struct _tree_cfg_pres {
75         tap_param_dlg* stat_dlg;
76 };
77
78 struct _tree_pres {
79         GString*        text;
80         GtkWidget*      win;
81         GtkTreeStore*   store;
82         GtkWidget*      tree;
83 };
84
85 /* Define fixed column indexes */
86 #define NODEPTR_COLUMN  0               /* Always first column */
87 #define N_RESERVED_COL  1               /* Number of columns for internal use - added before visible cols */
88
89
90 static void
91 draw_gtk_node(stat_node* node)
92 {
93         GtkTreeIter* parent =  NULL;
94         stat_node* child;
95         int             num_columns= node->st->num_columns+N_RESERVED_COL;
96         gint    *columns = (gint*) g_malloc(sizeof(gint)*num_columns);
97         GValue  *values = (GValue*) g_malloc0(sizeof(GValue)*num_columns);
98         gchar   **valstrs = stats_tree_get_values_from_node(node);
99         int             count;
100
101         columns[0]= 0;
102         g_value_init(values, G_TYPE_POINTER);
103         g_value_set_pointer(values, node);
104         for (count = N_RESERVED_COL; count<num_columns; count++) {
105                 columns[count]= count;
106                 g_value_init(values+count, G_TYPE_STRING);
107                 g_value_take_string (values+count,valstrs[count-N_RESERVED_COL]);
108         }
109
110         if (!node->pr) {
111                 node->pr = (st_node_pres *)g_malloc(sizeof(st_node_pres));
112
113                 if (node->st->pr->store) {
114                         node->pr->iter = (GtkTreeIter *)g_malloc0(sizeof(GtkTreeIter));
115
116                         if ( node->parent && node->parent->pr ) {
117                                 parent = node->parent->pr->iter;
118                         }
119                         gtk_tree_store_append (node->st->pr->store, node->pr->iter, parent);
120                         gtk_tree_store_set_valuesv(node->st->pr->store, node->pr->iter,
121                                                    columns, values, num_columns);
122                 }
123         }
124         if (node->st->pr->store && node->pr->iter) {
125                 /* skip reserved columns and first entry in the stats_tree values */
126                 /* list (the node name). These should already be set and static.  */
127                 gtk_tree_store_set_valuesv(node->st->pr->store, node->pr->iter,
128                                    columns+N_RESERVED_COL+1, values+N_RESERVED_COL+1,
129                                    num_columns-N_RESERVED_COL-1);
130         }
131
132         for (count = 0; count<num_columns; count++) {
133                 g_value_unset(values+count);
134         }
135         g_free(columns);
136         g_free(values);
137         g_free(valstrs);
138
139         if (node->children) {
140                 for (child = node->children; child; child = child->next )
141                         draw_gtk_node(child);
142         }
143
144 }
145
146 static void
147 draw_gtk_tree(void *psp)
148 {
149         stats_tree *st = (stats_tree *)psp;
150         stat_node* child;
151         int count;
152         gint sort_column= GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID;
153         GtkSortType order= GTK_SORT_DESCENDING;
154
155         for (count = 0; count<st->num_columns; count++) {
156                 gtk_tree_view_column_set_title(gtk_tree_view_get_column(GTK_TREE_VIEW(st->pr->tree),count),
157                                                                                 stats_tree_get_column_name(count));
158         }
159
160         gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (st->pr->store), &sort_column, &order);
161         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (st->pr->store),
162                                 GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_DESCENDING);
163
164         for (child = st->root.children; child; child = child->next ) {
165                 draw_gtk_node(child);
166
167                 if ( (!(child->st_flags&ST_FLG_DEF_NOEXPAND)) && child->pr->iter && st->pr->store ) {
168                         gtk_tree_view_expand_row(GTK_TREE_VIEW(st->pr->tree),
169                                  gtk_tree_model_get_path(GTK_TREE_MODEL(st->pr->store),child->pr->iter),
170                                                  FALSE);
171                 }
172         }
173
174         if      ((sort_column==GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)||
175                  (sort_column==GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID)) {
176                 sort_column= stats_tree_get_default_sort_col(st)+N_RESERVED_COL;
177                 order= stats_tree_is_default_sort_DESC(st)?GTK_SORT_DESCENDING:GTK_SORT_ASCENDING;
178         }
179
180         /* Only call this once the entire list is drawn - else Gtk seems */
181         /* to get sorting order wrong (sorting broken when new nodes are */
182         /* added after setting sort column.) Also for performance.         */
183         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (st->pr->store), sort_column, order);
184 }
185
186 static gboolean
187 copy_tree_to_clipboard
188 (GtkWidget *win _U_, stats_tree *st)
189 {
190         gint sort_column= N_RESERVED_COL;       /* default */
191         GtkSortType order= GTK_SORT_DESCENDING;
192         GString *s;
193
194         gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (st->pr->store), &sort_column, &order);
195         s= stats_tree_format_as_str(st,ST_FORMAT_PLAIN,sort_column-N_RESERVED_COL,order==GTK_SORT_DESCENDING);
196         copy_to_clipboard(s);
197         g_string_free (s,TRUE);
198
199         return TRUE;
200 }
201
202
203 #ifndef USE_WIN32_FILE_DIALOGS
204 static gboolean
205 gtk_save_as_statstree(GtkWidget *win, GString *file_name, int *file_type)
206 {
207         GtkWidget *saveas_w;
208         GtkWidget *main_vb;
209         GtkWidget *ft_hb, *ft_lb, *ft_combo_box;
210         char      *st_name;
211         gpointer   ptr;
212
213         saveas_w = file_selection_new("Wireshark: Save stats tree as ...",
214                                            GTK_WINDOW(win), FILE_SELECTION_SAVE);
215
216         main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE);
217         gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
218         file_selection_set_extra_widget(saveas_w, main_vb);
219         gtk_widget_show(main_vb);
220
221         /* File type row */
222         ft_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
223         gtk_box_pack_start(GTK_BOX(main_vb), ft_hb, FALSE, FALSE, 0);
224         gtk_widget_show(ft_hb);
225
226         ft_lb = gtk_label_new("Save as format:");
227         gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
228         gtk_widget_show(ft_lb);
229
230         ft_combo_box = ws_combo_box_new_text_and_pointer();
231         ws_combo_box_append_text_and_pointer(GTK_COMBO_BOX(ft_combo_box), "Plain text file (.txt)", GINT_TO_POINTER(ST_FORMAT_PLAIN));
232         ws_combo_box_append_text_and_pointer(GTK_COMBO_BOX(ft_combo_box), "Comma separated values (.csv)", GINT_TO_POINTER(ST_FORMAT_CSV));
233         ws_combo_box_append_text_and_pointer(GTK_COMBO_BOX(ft_combo_box), "XML document (.xml)", GINT_TO_POINTER(ST_FORMAT_XML));
234         ws_combo_box_append_text_and_pointer(GTK_COMBO_BOX(ft_combo_box), "YAML document (.yaml)", GINT_TO_POINTER(ST_FORMAT_YAML));
235
236         gtk_box_pack_start(GTK_BOX(ft_hb), ft_combo_box, FALSE, FALSE, 0);
237         gtk_widget_show(ft_combo_box);
238         ws_combo_box_set_active(GTK_COMBO_BOX(ft_combo_box), 0);
239
240         st_name = file_selection_run(saveas_w);
241         if (st_name == NULL) {
242                 /* User cancelled or closed the dialog. */
243                 return FALSE;
244         }
245
246         if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(ft_combo_box), &ptr)) {
247                 g_assert_not_reached();  /* Programming error: somehow nothing is active */
248         }
249
250         /* Save result from dialog box */
251         *file_type = GPOINTER_TO_INT(ptr);
252         g_string_printf(file_name, "%s", st_name);
253
254         /* We've crossed the Rubicon; get rid of the file save-as box. */
255         window_destroy(GTK_WIDGET(saveas_w));
256         g_free(st_name);
257         return TRUE;
258 }
259 #endif /* USE_WIN32_FILE_DIALOGS */
260
261 static gboolean
262 save_as_dialog(GtkWidget *win _U_, stats_tree *st)
263 {
264         gint sort_column= 1;    /* default */
265         GtkSortType order= GTK_SORT_DESCENDING;
266         GString *str_tree;
267         GString *file_name              = g_string_new("");
268         int file_type;
269         gchar *file_name_lower;
270         const gchar *file_ext;
271         FILE *f;
272         gboolean success= FALSE;
273         int last_errno;
274
275 #ifdef USE_WIN32_FILE_DIALOGS
276         if (win32_save_as_statstree(GDK_WINDOW_HWND(gtk_widget_get_window(st->pr->win)),
277                                                                 file_name, &file_type)) {
278 #else /* USE_WIN32_FILE_DIALOGS */
279         if (gtk_save_as_statstree(st->pr->win,file_name,&file_type)) {
280 #endif /* USE_WIN32_FILE_DIALOGS */
281
282                 /* add file extension as required */
283                 file_name_lower = g_utf8_strdown(file_name->str, -1);
284                 switch (file_type) {
285                         case ST_FORMAT_YAML:    file_ext = ".yaml";
286                                                                         break;
287                         case ST_FORMAT_XML:             file_ext = ".xml";
288                                                                         break;
289                         case ST_FORMAT_CSV:             file_ext = ".csv";
290                                                                         break;
291                         default:                                file_ext = ".txt";
292                                                                         break;
293                 }
294                 if (!g_str_has_suffix(file_name_lower, file_ext)) {
295                         /* Must add extenstion */
296                         g_string_append(file_name,file_ext);
297                 }
298                 g_free(file_name_lower);
299
300                 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (st->pr->store), &sort_column, &order);
301                 str_tree=stats_tree_format_as_str(st,(st_format_type)file_type,sort_column-N_RESERVED_COL,order==GTK_SORT_DESCENDING);
302
303                 /* actually save the file */
304                 f= ws_fopen (file_name->str,"w");
305                 last_errno= errno;
306                 if (f) {
307                         if (fputs(str_tree->str, f)!=EOF) {
308                                 success= TRUE;
309                         }
310                         last_errno= errno;
311                         fclose(f);
312                 }
313                 if (!success) {
314                         GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(st->pr->win),
315                                                                   GTK_DIALOG_DESTROY_WITH_PARENT,
316                                                                   GTK_MESSAGE_ERROR,
317                                                                   GTK_BUTTONS_CLOSE,
318                                                                   "Error saving file '%s': %s",
319                                                                   file_name->str, g_strerror (last_errno));
320                         gtk_dialog_run (GTK_DIALOG (dialog));
321                         gtk_widget_destroy (dialog);
322                 }
323
324                 g_string_free(str_tree, TRUE);
325         }
326
327         g_string_free(file_name, TRUE);
328
329         return TRUE;
330 }
331
332 static void
333 free_gtk_tree(GtkWindow *win _U_, stats_tree *st)
334 {
335         remove_tap_listener(st);
336
337         if (st->root.pr)
338                 st->root.pr->iter = NULL;
339
340         st->cfg->in_use = FALSE;
341         stats_tree_free(st);
342
343 }
344
345 static void
346 clear_node_pr(stat_node* n)
347 {
348         stat_node* c;
349         for (c = n->children; c; c = c->next) {
350                 clear_node_pr(c);
351         }
352
353         if (n->pr->iter) {
354                 gtk_tree_store_remove(n->st->pr->store, n->pr->iter);
355                 n->pr->iter = NULL;
356         }
357 }
358
359 static void
360 reset_tap(void* p)
361 {
362         stats_tree* st = (stats_tree *)p;
363         stat_node* c;
364
365         for (c = st->root.children; c; c = c->next) {
366                 clear_node_pr(c);
367         }
368
369         stats_tree_reinit(st);
370 /*      st->cfg->init(st); doesn't properly delete nodes */
371 }
372
373 static gint
374 st_sort_func(GtkTreeModel *model,
375                          GtkTreeIter *a,
376                          GtkTreeIter *b,
377                          gpointer user_data)
378 {
379         gint sort_column= 1;    /* default */
380         GtkSortType order= GTK_SORT_DESCENDING;
381         stat_node *node_a;
382         stat_node *node_b;
383         gint result;
384
385         gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (user_data), &sort_column, &order);
386                                                                                                                 
387         gtk_tree_model_get(model, a, NODEPTR_COLUMN, &node_a, -1);
388         gtk_tree_model_get(model, b, NODEPTR_COLUMN, &node_b, -1);
389
390         result= stats_tree_sort_compare(node_a,node_b,sort_column-N_RESERVED_COL,order==GTK_SORT_DESCENDING);
391         if (order==GTK_SORT_DESCENDING) {
392                 result= -result;
393         }
394         return result;
395 }
396
397 /* initializes the stats_tree window */
398 static void
399 init_gtk_tree(const char* opt_arg, void *userdata _U_)
400 {
401         gchar *abbr = stats_tree_get_abbr(opt_arg);
402         stats_tree* st = NULL;
403         stats_tree_cfg* cfg = NULL;
404         tree_pres* pr = (tree_pres *)g_malloc(sizeof(tree_pres));
405         gchar* title = NULL;
406         gchar* window_name = NULL;
407         GString* error_string;
408         GtkWidget *scr_win;
409         size_t init_strlen;
410         GtkWidget *main_vb, *bbox, *bt_close, *bt_copy, *bt_saveas;
411         GtkTreeViewColumn* column;
412         GtkCellRenderer* renderer;
413         GtkTreeSortable *sortable;
414         GType *col_types;
415         int count;
416
417         if (abbr) {
418                 cfg = stats_tree_get_cfg_by_abbr(abbr);
419
420                 if (cfg && cfg->in_use) {
421                         /* XXX: ! */
422                         report_failure("cannot open more than one tree of the same type at once");
423                         return;
424                 }
425
426                 if (cfg != NULL) {
427                         init_strlen = strlen(cfg->pr->stat_dlg->init_string);
428
429                         if (strncmp (opt_arg, cfg->pr->stat_dlg->init_string, init_strlen) == 0){
430                                 if (init_strlen == strlen(opt_arg)) {
431                                         st = stats_tree_new(cfg,pr,NULL);
432                                 } else {
433                                         st = stats_tree_new(cfg,pr,opt_arg+init_strlen+1);
434                                 }
435
436                         } else {
437                                 st = stats_tree_new(cfg,pr,NULL);
438                         }
439                 } else {
440                         report_failure("no such stats_tree (%s) in stats_tree registry",abbr);
441                         g_free(abbr);
442                         return;
443                 }
444                 g_free(abbr);
445
446         } else {
447                 report_failure("could not obtain stats_tree abbr from opt_arg");
448                 g_free(pr);
449                 return;
450         }
451
452         cfg->in_use = TRUE;
453
454         window_name = g_strdup_printf("%s Stats Tree", st->display_name);
455
456         st->pr->win = window_new_with_geom(GTK_WINDOW_TOPLEVEL,window_name,window_name);
457         gtk_window_set_default_size(GTK_WINDOW(st->pr->win), st->num_columns*80+80, 400);
458         g_free(window_name);
459
460         if(st->filter){
461                 title=g_strdup_printf("%s with filter: %s",st->display_name,st->filter);
462         } else {
463                 st->filter=NULL;
464                 title=g_strdup_printf("%s", st->display_name);
465         }
466
467         gtk_window_set_title(GTK_WINDOW(st->pr->win), title);
468         g_free(title);
469
470         main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
471         gtk_container_set_border_width(GTK_CONTAINER(main_vb), 12);
472         gtk_container_add(GTK_CONTAINER(st->pr->win), main_vb);
473
474         scr_win = scrolled_window_new(NULL, NULL);
475
476         col_types= (GType*)g_malloc(sizeof(GType)*(st->num_columns+N_RESERVED_COL));
477         col_types[0] = G_TYPE_POINTER;
478         for (count = 0; count<st->num_columns; count++) {
479                 col_types[count+N_RESERVED_COL] = G_TYPE_STRING;
480         }
481         st->pr->store = gtk_tree_store_newv (st->num_columns+N_RESERVED_COL,col_types);
482         g_free (col_types);
483
484         sortable= GTK_TREE_SORTABLE (st->pr->store);
485         st->pr->tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (st->pr->store));
486         gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(st->pr->tree), FALSE);
487         g_object_unref(G_OBJECT(st->pr->store));
488
489         gtk_container_add( GTK_CONTAINER(scr_win), st->pr->tree);
490
491         /* the columns */
492         for (count = 0; count<st->num_columns; count++) {
493                 renderer = gtk_cell_renderer_text_new ();
494                 column = gtk_tree_view_column_new_with_attributes (stats_tree_get_column_name(count),
495                                                                         renderer, "text", count+N_RESERVED_COL, NULL);
496                 gtk_tree_view_column_set_sort_column_id(column, count+N_RESERVED_COL);
497                 gtk_tree_sortable_set_sort_func(sortable,count+N_RESERVED_COL, st_sort_func, sortable, NULL);
498                 gtk_tree_view_column_set_resizable (column,TRUE);
499                 gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE);
500                 gtk_tree_view_append_column (GTK_TREE_VIEW (st->pr->tree), column);
501         }
502
503         gtk_tree_sortable_set_default_sort_func (sortable, NULL, NULL, NULL);
504
505         gtk_box_pack_start(GTK_BOX(main_vb), scr_win, TRUE, TRUE, 0);
506
507         error_string = register_tap_listener( cfg->tapname,
508                                               st,
509                                               st->filter,
510                                               cfg->flags,
511                                               reset_tap,
512                                               stats_tree_packet,
513                                               draw_gtk_tree);
514
515         if (error_string) {
516                 /* error, we failed to attach to the tap. clean up */
517                 /* destroy_stat_tree_window(st); */
518                 report_failure("stats_tree for: %s failed to attach to the tap: %s",cfg->name,error_string->str);
519                 g_string_free(error_string, TRUE);
520         }
521
522         /* Button row. */
523         bbox = dlg_button_row_new(GTK_STOCK_COPY, GTK_STOCK_SAVE_AS, GTK_STOCK_CLOSE, NULL);
524         gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
525
526         bt_close = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
527         window_set_cancel_button(st->pr->win, bt_close, window_cancel_button_cb);
528
529         g_signal_connect(GTK_WINDOW(st->pr->win), "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
530         g_signal_connect(GTK_WINDOW(st->pr->win), "destroy", G_CALLBACK(free_gtk_tree), st);
531
532         bt_copy = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_COPY);
533         g_signal_connect(GTK_WINDOW (bt_copy), "clicked", G_CALLBACK(copy_tree_to_clipboard), st);
534
535         bt_saveas = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_SAVE_AS);
536         g_signal_connect(GTK_WINDOW (bt_saveas), "clicked", G_CALLBACK(save_as_dialog), st);
537
538         gtk_widget_show_all(st->pr->win);
539         window_present(st->pr->win);
540
541         cf_retap_packets(&cfile);
542         gdk_window_raise(gtk_widget_get_window(st->pr->win));
543 }
544
545 static tap_param tree_stat_params[] = {
546         { PARAM_FILTER, "Filter", NULL }
547 };
548
549 static void
550 register_gtk_stats_tree_tap (gpointer k _U_, gpointer v, gpointer p _U_)
551 {
552         stats_tree_cfg* cfg = (stats_tree_cfg *)v;
553         gchar* display_name= stats_tree_get_displayname(cfg->name);
554
555         cfg->pr = (tree_cfg_pres *)g_malloc(sizeof(tree_cfg_pres));
556
557         cfg->pr->stat_dlg = (tap_param_dlg *)g_malloc(sizeof(tap_param_dlg));
558
559         cfg->pr->stat_dlg->win_title = g_strdup_printf("%s Stats Tree",display_name);
560         cfg->pr->stat_dlg->init_string = g_strdup_printf("%s,tree",cfg->abbr);
561         cfg->pr->stat_dlg->tap_init_cb = init_gtk_tree;
562         cfg->pr->stat_dlg->index = -1;
563         cfg->pr->stat_dlg->nparams = G_N_ELEMENTS(tree_stat_params);
564         cfg->pr->stat_dlg->params = tree_stat_params;
565         g_free(display_name);
566 }
567
568 static void
569 free_tree_presentation(stats_tree* st)
570 {
571         g_free(st->pr);
572 }
573
574 void
575 register_tap_listener_stats_tree_stat(void)
576 {
577
578         stats_tree_presentation(register_gtk_stats_tree_tap,
579                                 NULL,
580                                 NULL,
581                                 NULL,
582                                 NULL,
583                                 NULL,
584                                 free_tree_presentation,
585                                 NULL,
586                                 NULL,
587                                 NULL);
588 }
589
590 void gtk_stats_tree_cb(GtkAction *action, gpointer user_data _U_)
591 {
592         const gchar *action_name; 
593         gchar *abbr;
594         stats_tree_cfg* cfg = NULL;
595
596         action_name = gtk_action_get_name (action);
597         abbr = strrchr(action_name,'/');
598         if(abbr){
599                 abbr = abbr+1;
600         }else{
601                 abbr = g_strdup_printf("%s",action_name);
602         }
603         cfg = stats_tree_get_cfg_by_abbr(abbr);
604         if(cfg){
605                 tap_param_dlg_cb(action, cfg->pr->stat_dlg);
606         }else{
607         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
608                       "Failed to find the stat tree named %s",
609                       abbr);
610                 return;
611         }
612
613 }
614