b8acbeb3899fd85734227743192b56cc1fb34b27
[obnox/wireshark/wip.git] / gtk / find_dlg.c
1 /* find_dlg.c
2  * Routines for "find frame" window
3  *
4  * $Id: find_dlg.c,v 1.10 2000/05/08 04:53:20 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
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 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <gtk/gtk.h>
32
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36
37 #ifndef __G_LIB_H__
38 #include <glib.h>
39 #endif
40
41 #include "proto.h"
42 #include "dfilter.h"
43 #include "globals.h"
44
45 #include "ui_util.h"
46 #include "find_dlg.h"
47 #include "filter_prefs.h"
48 #include "simple_dialog.h"
49 #include "dlg_utils.h"
50
51 /* Capture callback data keys */
52 #define E_FIND_FILT_KEY     "find_filter_te"
53 #define E_FIND_BACKWARD_KEY "find_backward"
54
55 static void
56 find_frame_ok_cb(GtkWidget *ok_bt, gpointer parent_w);
57
58 static void
59 find_frame_close_cb(GtkWidget *close_bt, gpointer parent_w);
60
61 static void
62 find_frame_destroy_cb(GtkWidget *win, gpointer user_data);
63
64 /*
65  * Keep a static pointer to the current "Find Frame" window, if any, so
66  * that if somebody tries to do "Find Frame" while there's already a
67  * "Find Frame" window up, we just pop up the existing one, rather than
68  * creating a new one.
69  */
70 static GtkWidget *find_frame_w;
71
72 void
73 find_frame_cb(GtkWidget *w, gpointer d)
74 {
75   GtkWidget     *main_vb, *filter_hb, *filter_bt, *filter_te,
76                 *direction_hb, *forward_rb, *backward_rb,
77                 *bbox, *ok_bt, *cancel_bt;
78   GtkAccelGroup *accel_group;
79
80   if (find_frame_w != NULL) {
81     /* There's already a "Find Frame" dialog box; reactivate it. */
82     reactivate_window(find_frame_w);
83     return;
84   }
85
86   find_frame_w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
87   gtk_window_set_title(GTK_WINDOW(find_frame_w), "Ethereal: Find Frame");
88   gtk_signal_connect(GTK_OBJECT(find_frame_w), "destroy",
89         GTK_SIGNAL_FUNC(find_frame_destroy_cb), NULL);
90
91   /* Accelerator group for the accelerators (or, as they're called in
92      Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
93      Ctrl+<key> is an accelerator). */
94   accel_group = gtk_accel_group_new();
95   gtk_window_add_accel_group(GTK_WINDOW(find_frame_w), accel_group);
96   
97   /* Container for each row of widgets */
98   main_vb = gtk_vbox_new(FALSE, 3);
99   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
100   gtk_container_add(GTK_CONTAINER(find_frame_w), main_vb);
101   gtk_widget_show(main_vb);
102   
103   /* Filter row */
104   filter_hb = gtk_hbox_new(FALSE, 3);
105   gtk_container_add(GTK_CONTAINER(main_vb), filter_hb);
106   gtk_widget_show(filter_hb);
107   
108   filter_bt = gtk_button_new_with_label("Filter:");
109   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
110     GTK_SIGNAL_FUNC(filter_browse_cb), NULL);
111   gtk_box_pack_start(GTK_BOX(filter_hb), filter_bt, FALSE, TRUE, 0);
112   gtk_widget_show(filter_bt);
113   
114   filter_te = gtk_entry_new();
115   if (cf.sfilter) gtk_entry_set_text(GTK_ENTRY(filter_te), cf.sfilter);
116   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
117   gtk_box_pack_start(GTK_BOX(filter_hb), filter_te, TRUE, TRUE, 0);
118   gtk_widget_show(filter_te);
119   
120   /* Misc row: Forward and reverse radio buttons */
121   direction_hb = gtk_hbox_new(FALSE, 3);
122   gtk_container_add(GTK_CONTAINER(main_vb), direction_hb);
123   gtk_widget_show(direction_hb);
124
125   forward_rb = dlg_radio_button_new_with_label_with_mnemonic(NULL, "_Forward",
126                         accel_group);
127   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(forward_rb), !cf.sbackward);
128   gtk_box_pack_start(GTK_BOX(direction_hb), forward_rb, TRUE, TRUE, 0);
129   gtk_widget_show(forward_rb);
130
131   backward_rb = dlg_radio_button_new_with_label_with_mnemonic(
132                gtk_radio_button_group(GTK_RADIO_BUTTON(forward_rb)),
133                "_Backward", accel_group);
134   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(backward_rb), cf.sbackward);
135   gtk_box_pack_start(GTK_BOX(direction_hb), backward_rb, TRUE, TRUE, 0);
136   gtk_widget_show(backward_rb);
137
138   /* Button row: OK and cancel buttons */
139   bbox = gtk_hbutton_box_new();
140   gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
141   gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
142   gtk_container_add(GTK_CONTAINER(main_vb), bbox);
143   gtk_widget_show(bbox);
144
145   ok_bt = gtk_button_new_with_label ("OK");
146   gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
147     GTK_SIGNAL_FUNC(find_frame_ok_cb), GTK_OBJECT(find_frame_w));
148   GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
149   gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
150   gtk_widget_grab_default(ok_bt);
151   gtk_widget_show(ok_bt);
152
153   cancel_bt = gtk_button_new_with_label ("Cancel");
154   gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
155     GTK_SIGNAL_FUNC(find_frame_close_cb), GTK_OBJECT(find_frame_w));
156   GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
157   gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
158   gtk_widget_show(cancel_bt);
159
160   /* Attach pointers to needed widgets to the capture prefs window/object */
161   gtk_object_set_data(GTK_OBJECT(find_frame_w), E_FIND_FILT_KEY, filter_te);
162   gtk_object_set_data(GTK_OBJECT(find_frame_w), E_FIND_BACKWARD_KEY, backward_rb);
163
164   /* Catch the "activate" signal on the frame number text entry, so that
165      if the user types Return there, we act as if the "OK" button
166      had been selected, as happens if Return is typed if some widget
167      that *doesn't* handle the Return key has the input focus. */
168   dlg_set_activate(filter_te, ok_bt);
169
170   /* Catch the "key_press_event" signal in the window, so that we can catch
171      the ESC key being pressed and act as if the "Cancel" button had
172      been selected. */
173   dlg_set_cancel(find_frame_w, cancel_bt);
174
175   /* Give the initial focus to the "Filter" entry box. */
176   gtk_widget_grab_focus(filter_te);
177
178   gtk_widget_show(find_frame_w);
179 }
180
181 static void
182 find_frame_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
183 {
184   GtkWidget *filter_te, *backward_rb;
185   gchar *filter_text;
186   dfilter *sfcode;
187
188   filter_te = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_FIND_FILT_KEY);
189   backward_rb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w), E_FIND_BACKWARD_KEY);
190
191   filter_text = gtk_entry_get_text(GTK_ENTRY(filter_te));
192
193   /*
194    * Try to compile the filter.
195    */
196   if (dfilter_compile(filter_text, &sfcode) != 0) {
197     /* The attempt failed; report an error. */
198     simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
199     return;
200   }
201
202   /* Was it empty? */
203   if (sfcode == NULL) {
204     /* Yes - complain. */
205     simple_dialog(ESD_TYPE_WARN, NULL,
206        "You didn't specify a filter to use when searching for a frame.");
207     return;
208   }
209
210   /*
211    * Remember the filter.
212    */
213   if (cf.sfilter)
214     g_free(cf.sfilter);
215   cf.sfilter = g_strdup(filter_text);
216
217   cf.sbackward = GTK_TOGGLE_BUTTON (backward_rb)->active;
218
219   if (!find_packet(&cf, sfcode)) {
220     /* We didn't find the packet. */
221     simple_dialog(ESD_TYPE_WARN, NULL, "No packet matched that filter.");
222     return;
223   }
224
225   gtk_widget_destroy(GTK_WIDGET(parent_w));
226 }
227
228 static void
229 find_frame_close_cb(GtkWidget *close_bt, gpointer parent_w)
230 {
231   gtk_grab_remove(GTK_WIDGET(parent_w));
232   gtk_widget_destroy(GTK_WIDGET(parent_w));
233 }
234
235 static void
236 find_frame_destroy_cb(GtkWidget *win, gpointer user_data)
237 {
238   GtkWidget *find_frame_filter_w;
239
240   /* Is there a filter edit/selection dialog associated with this
241      Find Frame dialog? */
242   find_frame_filter_w = gtk_object_get_data(GTK_OBJECT(win), E_FILT_DIALOG_PTR_KEY);
243
244   if (find_frame_filter_w != NULL) {
245     /* Yes.  Destroy it. */
246     gtk_widget_destroy(find_frame_filter_w);
247   }
248
249   /* Note that we no longer have a "Find Frame" dialog box. */
250   find_frame_w = NULL;
251 }