Some work on generalizing the "display filter" tap parameter dialog box
[obnox/wireshark/wip.git] / gtk / tap_dfilter_dlg.c
1 /* tap_dfilter_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_dfilter_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_entries;      /* 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         const char *value;
119         GString *params;
120         size_t i;
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                 value=gtk_entry_get_text(GTK_ENTRY(dlg_data->param_entries[i]));
127                 params=g_string_append_c(params, ',');
128                 params=g_string_append(params, value);
129         }
130         (dlg_data->cont.tap_init_cb)(params->str,NULL);
131         g_string_free(params, TRUE);
132 }
133
134
135 static void
136 tap_param_dlg_cb(GtkWidget *w _U_, gpointer data)
137 {
138         const char *filter;
139         char *title;
140         GtkWidget *dlg_box;
141         GtkWidget *item_box, *item_entry, *label, *filter_bt;
142         GtkWidget *bbox, *start_button, *cancel_button;
143         size_t i;
144         
145         tap_param_dlg *dlg_data = (tap_param_dlg *) data;       
146
147         if(dlg_data==NULL)
148                 return;
149                 
150         if(dlg_data->index==-1) {
151                 /* Dialog is not registered */
152                 if(start_dlg_list==NULL) {
153                         start_dlg_list = (tap_param_dlg_list_item *) g_malloc(sizeof (tap_param_dlg_list_item));
154                         end_dlg_list = start_dlg_list;
155                         end_dlg_list->cont.index = 0; /* first entry in list -> index = 0 */
156                 } else {
157                         end_dlg_list->next = (tap_param_dlg_list_item *) g_malloc(sizeof (tap_param_dlg_list_item));
158                         end_dlg_list->next->cont.index = end_dlg_list->cont.index + 1;
159                         end_dlg_list = end_dlg_list->next;
160                 }
161                 end_dlg_list->dlg = NULL;
162                 end_dlg_list->param_entries = g_malloc(dlg_data->nparams * sizeof (GtkWidget *));
163                 end_dlg_list->cont.win_title = dlg_data->win_title;
164                 end_dlg_list->cont.init_string = dlg_data->init_string;
165                 end_dlg_list->cont.tap_init_cb = dlg_data->tap_init_cb;
166                 end_dlg_list->cont.nparams = dlg_data->nparams;
167                 end_dlg_list->cont.params = dlg_data->params;
168                 end_dlg_list->args.title = g_strdup_printf("%s Filter", dlg_data->win_title);
169                 end_dlg_list->args.wants_apply_button = TRUE;
170                 end_dlg_list->args.activate_on_ok = FALSE;
171         end_dlg_list->args.modal_and_transient = FALSE;
172                 end_dlg_list->next = NULL;
173                 dlg_data->index = end_dlg_list->cont.index;
174                 current_dlg = end_dlg_list;
175         } else {
176                 /* Dialog is registered, find it */
177                 current_dlg = start_dlg_list;
178                 while(dlg_data->index != current_dlg->cont.index)
179                 {
180                         if(current_dlg->next == NULL) {
181                                 /* could not find any dialog */
182                                 return;
183                         }
184                         current_dlg = current_dlg->next;
185                 }
186         }
187
188         /* if the window is already open, bring it to front */
189         if(current_dlg->dlg){
190                 gdk_window_raise(current_dlg->dlg->window);
191                 return;
192         }
193
194         title = g_strdup_printf("Wireshark: %s: %s", current_dlg->cont.win_title , cf_get_display_name(&cfile));
195
196         current_dlg->dlg=dlg_window_new(title);
197         gtk_window_set_default_size(GTK_WINDOW(current_dlg->dlg), 300, -1);
198         g_free(title);
199
200         dlg_box=gtk_vbox_new(FALSE, 10);
201         gtk_container_set_border_width(GTK_CONTAINER(dlg_box), 10);
202         gtk_container_add(GTK_CONTAINER(current_dlg->dlg), dlg_box);
203         gtk_widget_show(dlg_box);
204
205         /* Parameter items */
206         for(i=0;i<current_dlg->cont.nparams;i++) {
207                 /* Item box */
208                 item_box=gtk_hbox_new(FALSE, 3);
209
210                 /* Item entry */
211                 item_entry=gtk_entry_new();
212                 current_dlg->param_entries[i] = item_entry;
213
214                 switch (current_dlg->cont.params[i].type) {
215
216                 case PARAM_UINT:
217                 case PARAM_STRING:
218                         /* Label */
219                         label=gtk_label_new(current_dlg->cont.params[i].title);
220                         gtk_box_pack_start(GTK_BOX(item_box), label, FALSE, TRUE, 0);
221                         gtk_widget_show(label);
222                         break;
223
224                 case PARAM_FILTER:
225                         /* Filter button */
226                         filter_bt=gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
227                         g_signal_connect(filter_bt, "clicked", G_CALLBACK(display_filter_construct_cb), &(current_dlg->args));
228                         gtk_box_pack_start(GTK_BOX(item_box), filter_bt, FALSE, TRUE, 0);
229                         gtk_widget_show(filter_bt);
230                         g_signal_connect(item_entry, "changed", G_CALLBACK(filter_te_syntax_check_cb), NULL);
231                         g_object_set_data(G_OBJECT(item_box), E_FILT_AUTOCOMP_PTR_KEY, NULL);
232                         g_signal_connect(item_entry, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
233                         g_signal_connect(current_dlg->dlg, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
234
235                         /* prefs dialog */
236                         g_object_set_data(G_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, item_entry);
237                         /* prefs dialog */
238                         break;
239
240                 default:
241                         /* XXX - fill me in */
242                         break;
243                 }
244         
245                 gtk_box_pack_start(GTK_BOX(item_box), item_entry, TRUE, TRUE, 0);
246
247                 switch(current_dlg->cont.params[i].type){
248
249                 case PARAM_FILTER:
250                         filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
251                         if(filter){
252                                 gtk_entry_set_text(GTK_ENTRY(item_entry), filter);
253                         } else {
254                                 colorize_filter_te_as_empty(item_entry);
255                         }
256                         break;
257
258                 default:
259                         /* XXX - anything to do here? */
260                         break;
261                 }
262                 gtk_widget_show(item_entry);
263
264                 gtk_box_pack_start(GTK_BOX(dlg_box), item_box, TRUE, TRUE, 0);
265                 gtk_widget_show(item_box);
266         }
267
268         /* button box */
269         bbox = dlg_button_row_new(WIRESHARK_STOCK_CREATE_STAT, GTK_STOCK_CANCEL, NULL);
270         gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
271         gtk_widget_show(bbox);
272
273         start_button = g_object_get_data(G_OBJECT(bbox), WIRESHARK_STOCK_CREATE_STAT);
274         g_signal_connect(start_button, "clicked",
275                               G_CALLBACK(tap_param_dlg_start_button_clicked), current_dlg);
276
277         cancel_button = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
278         window_set_cancel_button(current_dlg->dlg, cancel_button, window_cancel_button_cb);
279
280         /* Catch the "activate" signal on all the text entries, so that
281            if the user types Return there, we act as if the "Create Stat"
282            button had been selected, as happens if Return is typed if
283            some widget that *doesn't* handle the Return key has the input
284            focus. */
285         for(i=0;i<current_dlg->cont.nparams;i++){
286                 dlg_set_activate(current_dlg->param_entries[i], start_button);
287         }
288
289         /* Give the initial focus to the first entry box. */
290         if(current_dlg->cont.nparams>0){
291                 gtk_widget_grab_focus(current_dlg->param_entries[0]);
292         }
293
294         gtk_widget_grab_default(start_button );
295
296         g_signal_connect(current_dlg->dlg, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
297         g_signal_connect(current_dlg->dlg, "destroy", G_CALLBACK(dlg_destroy_cb), current_dlg);
298
299         gtk_widget_show_all(current_dlg->dlg);
300         window_present(current_dlg->dlg);
301 }