Add support for PARAM_ENUM tap parameters, and use the tap_param_dlg
[obnox/wireshark/wip.git] / gtk / tap_param_dlg.c
1 /* tap_param_dlg.c
2  * Routines for parameter dialog used by gui taps
3  * Copyright 2003 Lars Roland
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., 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 <stdio.h>
31 #include <string.h>
32
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36
37 #include <gtk/gtk.h>
38
39 #include <epan/stat_cmd_args.h>
40
41 #include "../simple_dialog.h"
42 #include "../file.h"
43 #include "../globals.h"
44 #include "../stat_menu.h"
45
46 #include "gtk/stock_icons.h"
47 #include "gtk/dlg_utils.h"
48 #include "gtk/filter_dlg.h"
49 #include "gtk/gui_stat_menu.h"
50 #include "gtk/tap_param_dlg.h"
51 #include "gtk/gui_utils.h"
52 #include "gtk/gtkglobals.h"
53 #include "gtk/filter_autocomplete.h"
54
55
56 typedef struct _tap_param_dlg_list_item {
57     GtkWidget *dlg;
58     tap_param_dlg cont;
59     construct_args_t args;
60     GtkWidget **param_items;    /* items for params */
61     struct _tap_param_dlg_list_item *next;
62 } tap_param_dlg_list_item;
63
64 static tap_param_dlg_list_item *start_dlg_list=NULL;
65 static tap_param_dlg_list_item *end_dlg_list=NULL;
66 static tap_param_dlg_list_item *current_dlg = NULL;
67
68 static void
69 tap_param_dlg_cb(GtkWidget *w, gpointer data);
70
71 /*
72  * Register a stat that has a parameter dialog.
73  * We register it both as a command-line stat and a menu item stat.
74  */
75 void
76 register_dfilter_stat(tap_param_dlg *info, const char *name,
77     register_stat_group_t group)
78 {
79     char *full_name;
80
81     register_stat_cmd_arg(info->init_string, info->tap_init_cb, NULL);
82
83     /*
84      * This menu item will pop up a dialog box, so append "..."
85      * to it.
86      */
87     full_name = g_strdup_printf("%s...", name);
88     register_stat_menu_item(full_name, group, tap_param_dlg_cb, NULL,
89                             NULL, info);
90     g_free(full_name);
91 }              
92
93 void tap_param_dlg_update (void)
94 {
95     tap_param_dlg_list_item *dialog = start_dlg_list;
96     char *title;
97     
98     while(dialog != NULL) {
99         if(dialog->dlg) {
100             title = g_strdup_printf("Wireshark: %s: %s", dialog->cont.win_title , cf_get_display_name(&cfile));
101             gtk_window_set_title(GTK_WINDOW(dialog->dlg), title);
102             g_free(title);
103         }
104         dialog = dialog->next;
105     }
106 }
107
108 static void
109 dlg_destroy_cb(GtkWidget *item _U_, gpointer dialog_data)
110 {
111     tap_param_dlg_list_item *dlg_data = (tap_param_dlg_list_item *) dialog_data;
112     dlg_data->dlg = NULL;
113 }
114
115 static void
116 tap_param_dlg_start_button_clicked(GtkWidget *item _U_, gpointer dialog_data)
117 {
118     GString *params;
119     size_t i;
120     gint j;
121     
122     tap_param_dlg_list_item *dlg_data = (tap_param_dlg_list_item *) dialog_data;
123
124     params = g_string_new(dlg_data->cont.init_string);
125     for(i=0;i<dlg_data->cont.nparams;i++) {
126         g_string_append_c(params, ',');
127         switch (dlg_data->cont.params[i].type) {
128
129         case PARAM_ENUM:
130             j = gtk_combo_box_get_active(GTK_COMBO_BOX(dlg_data->param_items[i]));
131             g_string_append_printf(params,"%d",
132                                    dlg_data->cont.params[i].enum_vals[j].value);
133             break;
134
135         case PARAM_UINT:
136         case PARAM_STRING:
137         case PARAM_FILTER:
138             g_string_append(params,
139                             gtk_entry_get_text(GTK_ENTRY(dlg_data->param_items[i])));
140             break;
141         }
142     }
143     (dlg_data->cont.tap_init_cb)(params->str,NULL);
144     g_string_free(params, TRUE);
145 }
146
147
148 static void
149 tap_param_dlg_cb(GtkWidget *w _U_, gpointer data)
150 {
151     const char *filter;
152     char *title;
153     GtkWidget *dlg_box;
154     GtkWidget *item_box, *item, *label, *filter_bt;
155     GtkWidget *bbox, *start_button, *cancel_button;
156     size_t i, j;
157     char *label_with_colon;
158     
159     tap_param_dlg *dlg_data = (tap_param_dlg *) data;
160
161     if(dlg_data==NULL)
162         return;
163         
164     if(dlg_data->index==-1) {
165         /* Dialog is not registered */
166         if(start_dlg_list==NULL) {
167             start_dlg_list = (tap_param_dlg_list_item *) g_malloc(sizeof (tap_param_dlg_list_item));
168             end_dlg_list = start_dlg_list;
169             end_dlg_list->cont.index = 0; /* first entry in list -> index = 0 */
170         } else {
171             end_dlg_list->next = (tap_param_dlg_list_item *) g_malloc(sizeof (tap_param_dlg_list_item));
172             end_dlg_list->next->cont.index = end_dlg_list->cont.index + 1;
173             end_dlg_list = end_dlg_list->next;
174         }
175         end_dlg_list->dlg = NULL;
176         end_dlg_list->param_items = g_malloc(dlg_data->nparams * sizeof (GtkWidget *));
177         end_dlg_list->cont.win_title = dlg_data->win_title;
178         end_dlg_list->cont.init_string = dlg_data->init_string;
179         end_dlg_list->cont.tap_init_cb = dlg_data->tap_init_cb;
180         end_dlg_list->cont.nparams = dlg_data->nparams;
181         end_dlg_list->cont.params = dlg_data->params;
182         end_dlg_list->args.title = g_strdup_printf("%s Filter", dlg_data->win_title);
183         end_dlg_list->args.wants_apply_button = TRUE;
184         end_dlg_list->args.activate_on_ok = FALSE;
185         end_dlg_list->args.modal_and_transient = FALSE;
186         end_dlg_list->next = NULL;
187         dlg_data->index = end_dlg_list->cont.index;
188         current_dlg = end_dlg_list;
189     } else {
190         /* Dialog is registered, find it */
191         current_dlg = start_dlg_list;
192         while(dlg_data->index != current_dlg->cont.index)
193         {
194             if(current_dlg->next == NULL) {
195                 /* could not find any dialog */
196                 return;
197             }
198             current_dlg = current_dlg->next;
199         }
200     }
201
202     /* if the window is already open, bring it to front */
203     if(current_dlg->dlg){
204         gdk_window_raise(current_dlg->dlg->window);
205         return;
206     }
207
208     title = g_strdup_printf("Wireshark: %s: %s", current_dlg->cont.win_title , cf_get_display_name(&cfile));
209
210     current_dlg->dlg=dlg_window_new(title);
211     gtk_window_set_default_size(GTK_WINDOW(current_dlg->dlg), 300, -1);
212     g_free(title);
213
214     dlg_box=gtk_vbox_new(FALSE, 10);
215     gtk_container_set_border_width(GTK_CONTAINER(dlg_box), 10);
216     gtk_container_add(GTK_CONTAINER(current_dlg->dlg), dlg_box);
217     gtk_widget_show(dlg_box);
218
219     /* Parameter items */
220     for(i=0;i<current_dlg->cont.nparams;i++) {
221         /* Item box */
222         item_box=gtk_hbox_new(FALSE, 3);
223
224         switch (current_dlg->cont.params[i].type) {
225
226         case PARAM_UINT:
227         case PARAM_STRING:
228             /* Label */
229             label_with_colon=g_strdup_printf("%s:", current_dlg->cont.params[i].title);
230             label=gtk_label_new(label_with_colon);
231             g_free(label_with_colon);
232             gtk_box_pack_start(GTK_BOX(item_box), label, FALSE, TRUE, 0);
233             gtk_widget_show(label);
234
235             /* Entry */
236             item=gtk_entry_new();
237             break;
238
239         case PARAM_ENUM:
240             /* Label */
241             label_with_colon=g_strdup_printf("%s:", current_dlg->cont.params[i].title);
242             label=gtk_label_new(label_with_colon);
243             g_free(label_with_colon);
244             gtk_box_pack_start(GTK_BOX(item_box), label, FALSE, TRUE, 0);
245             gtk_widget_show(label);
246
247             /* Combo box */
248             item=gtk_combo_box_new_text();
249             for (j = 0; current_dlg->cont.params[i].enum_vals[j].name != NULL;
250                  j++)
251                 gtk_combo_box_append_text(GTK_COMBO_BOX(item),
252                                           current_dlg->cont.params[i].enum_vals[j].description);
253             gtk_combo_box_set_active(GTK_COMBO_BOX(item), 0);
254             break;
255
256         case PARAM_FILTER:
257             /* Filter button */
258             filter_bt=gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
259             g_signal_connect(filter_bt, "clicked", G_CALLBACK(display_filter_construct_cb), &(current_dlg->args));
260             gtk_box_pack_start(GTK_BOX(item_box), filter_bt, FALSE, TRUE, 0);
261             gtk_widget_show(filter_bt);
262
263             /* Entry */
264             item=gtk_entry_new();
265             filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
266             if(filter){
267                 gtk_entry_set_text(GTK_ENTRY(item), filter);
268             } else {
269                 colorize_filter_te_as_empty(item);
270             }
271             g_signal_connect(item, "changed", G_CALLBACK(filter_te_syntax_check_cb), NULL);
272             g_object_set_data(G_OBJECT(item_box), E_FILT_AUTOCOMP_PTR_KEY, NULL);
273             g_signal_connect(item, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
274             g_signal_connect(current_dlg->dlg, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
275             g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, item);
276             break;
277
278         default:
279             g_assert_not_reached();
280             item=NULL;
281             break;
282         }
283     
284         gtk_box_pack_start(GTK_BOX(item_box), item, TRUE, TRUE, 0);
285         current_dlg->param_items[i]=item;
286         gtk_widget_show(item);
287
288         gtk_box_pack_start(GTK_BOX(dlg_box), item_box, TRUE, TRUE, 0);
289         gtk_widget_show(item_box);
290     }
291
292     /* button box */
293     bbox = dlg_button_row_new(WIRESHARK_STOCK_CREATE_STAT, GTK_STOCK_CANCEL, NULL);
294     gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
295     gtk_widget_show(bbox);
296
297     start_button = g_object_get_data(G_OBJECT(bbox), WIRESHARK_STOCK_CREATE_STAT);
298     g_signal_connect(start_button, "clicked",
299                      G_CALLBACK(tap_param_dlg_start_button_clicked), current_dlg);
300
301     cancel_button = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
302     window_set_cancel_button(current_dlg->dlg, cancel_button, window_cancel_button_cb);
303
304     /* Catch the "activate" signal on all the text entries, so that
305        if the user types Return there, we act as if the "Create Stat"
306        button had been selected, as happens if Return is typed if
307        some widget that *doesn't* handle the Return key has the input
308        focus. */
309     for(i=0;i<current_dlg->cont.nparams;i++){
310         switch (current_dlg->cont.params[i].type) {
311
312         case PARAM_ENUM:
313             break;
314
315         case PARAM_UINT:
316         case PARAM_STRING:
317         case PARAM_FILTER:
318             dlg_set_activate(current_dlg->param_items[i], start_button);
319             break;
320         }
321     }
322
323     /* Give the initial focus to the first entry box. */
324     if(current_dlg->cont.nparams>0){
325         gtk_widget_grab_focus(current_dlg->param_items[0]);
326     }
327
328     gtk_widget_grab_default(start_button );
329
330     g_signal_connect(current_dlg->dlg, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
331     g_signal_connect(current_dlg->dlg, "destroy", G_CALLBACK(dlg_destroy_cb), current_dlg);
332
333     gtk_widget_show_all(current_dlg->dlg);
334     window_present(current_dlg->dlg);
335 }