Sync up my changes so far to the content list (now called object
[obnox/wireshark/wip.git] / gtk / file_dlg.c
1 /* file_dlg.c
2  * Utilities to use when constructing file selection dialogs
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <gtk/gtk.h>
30 #if 0
31 #include <gdk/gdkkeysyms.h>
32 #endif
33
34 #include <epan/filesystem.h>
35
36 #if 0
37 #include "globals.h"
38 #endif
39
40 #include "gtkglobals.h"
41 #include "gui_utils.h"
42 #if 0
43 #include "dlg_utils.h"
44 #endif
45 #include "file_dlg.h"
46 #include "keys.h"
47 #include "compat_macros.h"
48 #if 0
49 #include "main.h"
50 #endif
51
52 #include <string.h>
53 #if 0
54 #include <stdio.h>
55 #endif
56 #include <errno.h>
57
58 static gchar *last_open_dir = NULL;
59 static gboolean updated_last_open_dir = FALSE;
60
61 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 4) || GTK_MAJOR_VERSION < 2
62 static void file_selection_browse_ok_cb(GtkWidget *w, gpointer data);
63 #endif
64 static void file_selection_browse_destroy_cb(GtkWidget *win, GtkWidget* file_te);
65
66 /* Keys ... */
67 #define E_FS_CALLER_PTR_KEY       "fs_caller_ptr"
68
69 /* Create a file selection dialog box window that belongs to Wireshark's
70    main window. */
71 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
72 GtkWidget *
73 file_selection_new(const gchar *title, file_selection_action_t action)
74 {
75   GtkWidget *win;
76   GtkFileChooserAction gtk_action;
77 #ifdef _WIN32
78   char *u3devicedocumentpath;
79 #endif 
80   const gchar *ok_button_text;
81
82   switch (action) {
83
84   case FILE_SELECTION_OPEN:
85     gtk_action = GTK_FILE_CHOOSER_ACTION_OPEN;
86     ok_button_text = GTK_STOCK_OPEN;
87     break;
88
89   case FILE_SELECTION_READ_BROWSE:
90     gtk_action = GTK_FILE_CHOOSER_ACTION_OPEN;
91     ok_button_text = GTK_STOCK_OK;
92     break;
93
94   case FILE_SELECTION_SAVE:
95     gtk_action = GTK_FILE_CHOOSER_ACTION_SAVE;
96     ok_button_text = GTK_STOCK_SAVE;
97     break;
98
99   case FILE_SELECTION_WRITE_BROWSE:
100     gtk_action = GTK_FILE_CHOOSER_ACTION_SAVE;
101     ok_button_text = GTK_STOCK_OK;
102     break;
103
104   case FILE_SELECTION_CREATE_FOLDER:
105     gtk_action = GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER;
106     ok_button_text = GTK_STOCK_OK;
107     break;
108
109   default:
110     g_assert_not_reached();
111     gtk_action = -1;
112     ok_button_text = NULL;
113     break;
114   }
115   win = gtk_file_chooser_dialog_new(title, GTK_WINDOW(top_level), gtk_action,
116 #ifndef _WIN32
117                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
118                                     ok_button_text, GTK_RESPONSE_ACCEPT,
119 #else
120                                     ok_button_text, GTK_RESPONSE_ACCEPT,
121                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
122 #endif
123                                     NULL);
124
125   /* If we've opened a file before, start out by showing the files in the directory
126      in which that file resided. */
127   if (last_open_dir)
128     file_selection_set_current_folder(win, last_open_dir);
129 #ifdef _WIN32
130   else {
131         u3devicedocumentpath = getenv_utf8("U3_DEVICE_DOCUMENT_PATH");
132         if(u3devicedocumentpath != NULL)
133           file_selection_set_current_folder(win, u3devicedocumentpath);
134
135   }
136 #endif
137   return win;
138 }
139 #else
140 GtkWidget *
141 file_selection_new(const gchar *title, file_selection_action_t action _U_)
142 {
143   GtkWidget *win;
144 #ifdef _WIN32
145   char *u3devicedocumentpath;
146 #endif
147   win = gtk_file_selection_new(title);
148 #if GTK_MAJOR_VERSION >= 2
149   gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER_ON_PARENT);
150 #endif
151   gtk_window_set_transient_for(GTK_WINDOW(win), GTK_WINDOW(top_level));
152
153   /* XXX - why are we doing this?  We don't do it with the GtkFileChooser,
154      as it complains that the file name isn't being set to an absolute
155      path; does this provoke a similar complaint? */
156   gtk_file_selection_set_filename(GTK_FILE_SELECTION(win), "");
157
158   /* If we've opened a file before, start out by showing the files in the directory
159      in which that file resided. */
160   if (last_open_dir)
161     file_selection_set_current_folder(win, last_open_dir);
162 #ifdef _WIN32
163   else {
164         u3devicedocumentpath = getenv_utf8("U3_DEVICE_DOCUMENT_PATH");
165         if(u3devicedocumentpath != NULL)
166           file_selection_set_current_folder(win, u3devicedocumentpath);
167
168   }
169 #endif
170   return win;
171 }
172 #endif
173
174 /* Set the current folder for a file selection dialog. */
175 gboolean
176 file_selection_set_current_folder(GtkWidget *fs, const gchar *filename)
177 {
178 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
179     gboolean ret;
180     int filename_len = strlen(filename);
181     gchar *new_filename;
182
183     /* trim filename, so gtk_file_chooser_set_current_folder() likes it, see below */
184     if (filename[filename_len -1] == G_DIR_SEPARATOR 
185 #ifdef _WIN32
186         && filename_len > 3)    /* e.g. "D:\" */
187 #else
188         && filename_len > 1)    /* e.g. "/" */
189 #endif
190     {
191         new_filename = g_strdup(filename);
192         new_filename[filename_len-1] = '\0';
193     } else {
194         new_filename = g_strdup(filename);
195     }
196
197     /* this function is very pedantic about it's filename parameter */
198     /* no trailing '\' allowed, unless a win32 root dir "D:\" */
199     ret = gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fs), new_filename);
200     g_free(new_filename);
201     return ret;
202 #else
203     gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), filename);
204     return TRUE;
205 #endif
206 }
207
208 /* Set the "extra" widget for a file selection dialog, with user-supplied
209    options. */
210 void
211 file_selection_set_extra_widget(GtkWidget *fs, GtkWidget *extra)
212 {
213 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
214   gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(fs), extra);
215 #else
216   gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(fs)->action_area), extra,
217                      FALSE, FALSE, 0);
218 #endif
219 }
220
221
222 /*
223  * A generic select_file routine that is intended to be connected to
224  * a Browse button on other dialog boxes. This allows the user to browse
225  * for a file and select it. We fill in the text_entry that is given to us. 
226  *
227  * We display the window label specified in our args.
228  */
229 void
230 file_selection_browse(GtkWidget *file_bt, GtkWidget *file_te, const char *label, file_selection_action_t action)
231 {
232   GtkWidget *caller = gtk_widget_get_toplevel(file_bt);
233   GtkWidget *fs;
234 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
235   gchar     *f_name;
236 #endif
237
238   /* Has a file selection dialog box already been opened for that top-level
239      widget? */
240   fs = OBJECT_GET_DATA(caller, E_FILE_SEL_DIALOG_PTR_KEY);
241   if (fs != NULL) {
242     /* Yes.  Just re-activate that dialog box. */
243     reactivate_window(fs);
244     return;
245   }
246
247   fs = file_selection_new(label, action);
248
249   OBJECT_SET_DATA(fs, PRINT_FILE_TE_KEY, file_te);
250
251   /* Set the E_FS_CALLER_PTR_KEY for the new dialog to point to our caller. */
252   OBJECT_SET_DATA(fs, E_FS_CALLER_PTR_KEY, caller);
253
254   /* Set the E_FILE_SEL_DIALOG_PTR_KEY for the caller to point to us */
255   OBJECT_SET_DATA(caller, E_FILE_SEL_DIALOG_PTR_KEY, fs);
256
257   /* Call a handler when the file selection box is destroyed, so we can inform
258      our caller, if any, that it's been destroyed. */
259   SIGNAL_CONNECT(fs, "destroy", GTK_SIGNAL_FUNC(file_selection_browse_destroy_cb), 
260                  file_te);
261
262 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
263   if (gtk_dialog_run(GTK_DIALOG(fs)) == GTK_RESPONSE_ACCEPT)
264   {
265       f_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
266       gtk_entry_set_text(GTK_ENTRY(file_te), f_name);
267       g_free(f_name);
268   }
269   window_destroy(fs);
270 #else
271   SIGNAL_CONNECT(GTK_FILE_SELECTION(fs)->ok_button, "clicked", 
272                  file_selection_browse_ok_cb, fs);
273
274   window_set_cancel_button(fs, GTK_FILE_SELECTION(fs)->cancel_button,
275                            window_cancel_button_cb);
276
277   SIGNAL_CONNECT(fs, "delete_event", window_delete_event_cb, fs);
278
279   gtk_widget_show(fs);
280   window_present(fs);
281 #endif
282 }
283
284
285 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 4) || GTK_MAJOR_VERSION < 2
286 static void
287 file_selection_browse_ok_cb(GtkWidget *w _U_, gpointer data)
288 {
289   gchar     *f_name;
290   GtkWidget *win = data;
291
292   f_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (data)));
293
294   /* Perhaps the user specified a directory instead of a file.
295      Check whether they did. */
296   if (test_for_directory(f_name) == EISDIR) {
297         /* It's a directory - set the file selection box to display it. */
298         set_last_open_dir(f_name);
299         g_free(f_name);
300         file_selection_set_current_folder(data, last_open_dir);
301         return;
302   }
303
304   gtk_entry_set_text(GTK_ENTRY(OBJECT_GET_DATA(win, PRINT_FILE_TE_KEY)),
305                      f_name);
306   window_destroy(GTK_WIDGET(win));
307
308   g_free(f_name);
309 }
310 #endif
311
312 static void
313 file_selection_browse_destroy_cb(GtkWidget *win, GtkWidget* parent_te)
314 {
315   GtkWidget *caller;
316
317   /* Get the widget that requested that we be popped up.
318      (It should arrange to destroy us if it's destroyed, so
319      that we don't get a pointer to a non-existent window here.) */
320   caller = OBJECT_GET_DATA(win, E_FS_CALLER_PTR_KEY);
321
322   /* Tell it we no longer exist. */
323   OBJECT_SET_DATA(caller, E_FILE_SEL_DIALOG_PTR_KEY, NULL);
324
325   /* Give the focus to the file text entry widget so the user can just press
326      Return to print to the file. */
327   gtk_widget_grab_focus(parent_te);
328 }
329
330
331 void
332 set_last_open_dir(char *dirname)
333 {
334         int len;
335         gchar *new_last_open_dir;
336
337         if (dirname) {
338                 len = strlen(dirname);
339                 if (dirname[len-1] == G_DIR_SEPARATOR) {
340                         new_last_open_dir = g_strconcat(dirname, NULL);
341                 }
342                 else {
343                         new_last_open_dir = g_strconcat(dirname,
344                                 G_DIR_SEPARATOR_S, NULL);
345                 }
346
347                 if (last_open_dir == NULL ||
348                     strcmp(last_open_dir, new_last_open_dir) != 0)
349                         updated_last_open_dir = TRUE;
350         }
351         else {
352                 new_last_open_dir = NULL;
353                 if (last_open_dir != NULL)
354                         updated_last_open_dir = TRUE;
355         }
356
357         if (last_open_dir) {
358                 g_free(last_open_dir);
359         }
360         last_open_dir = new_last_open_dir;
361 }
362
363 char *
364 get_last_open_dir(void)
365 {
366     return last_open_dir;
367 }