"main_menu.[ch]" -> "menus.[ch]"; it handles not only the main menu, but
[obnox/wireshark/wip.git] / gtk / fileset_dlg.c
1 /* fileset_dlg.c
2  * Routines for the file set dialog
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 <string.h>
30
31 #ifdef HAVE_FCNTL_H
32 #include <fcntl.h>
33 #endif
34
35 #include <gtk/gtk.h>
36
37 #include <epan/filesystem.h>
38
39 #include "../globals.h"
40 #include "../simple_dialog.h"
41 #include "../fileset.h"
42
43 #include "gtk/gui_utils.h"
44 #include "gtk/dlg_utils.h"
45 #include "gtk/main.h"
46 #include "gtk/menus.h"
47 #include "gtk/help_dlg.h"
48 #include "gtk/fileset_dlg.h"
49
50
51
52 /*
53  * Keep a static pointer to the current "File Set" window, if
54  * any, so that if somebody tries to do "File Set" while there's
55  * already a "File Set" window up, we just pop up the existing
56  * one, rather than creating a new one.
57  */
58 static GtkWidget *fs_w;
59
60
61
62 /* various widget related global data */
63 int           row;
64 GtkWidget     *fs_tb;
65 GtkWidget     *fs_sw;
66 GtkTooltips   *tooltips;
67 GtkWidget     *fs_dir_lb;
68 GtkWidget     *fs_first_rb;
69 GtkWidget     *fs_tb_vb;
70
71
72
73 /* open the file corresponding to the given fileset entry */
74 static void
75 fs_open_entry(fileset_entry *entry)
76 {
77     char            *fname;
78     int             err;
79
80
81     /* make a copy of the filename (cf_close will indirectly destroy it right now) */
82     fname = g_strdup(entry->fullname);
83
84     /* close the old and open the new file */
85     cf_close(&cfile);
86     if (cf_open(&cfile, fname, FALSE, &err) == CF_OK) {
87         cf_read(&cfile);
88     }
89
90     g_free(fname);
91 }
92
93
94 /* radio button was pressed/released */
95 static void
96 fs_rb_cb(GtkWidget *open_bt, gpointer fs_data)
97 {
98     fileset_entry   *entry = fs_data;
99
100     /* button release should have no effect */
101     if(!gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(open_bt) )) {
102         return;
103     }
104
105     fs_open_entry(entry);
106 }
107
108
109 /* the window was closed, cleanup things */
110 static void
111 fs_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
112 {
113     /* Note that we no longer have a "File Set" dialog box. */
114     fs_w = NULL;
115 }
116
117
118 /* get creation date (converted from filename) */
119 /* */
120 static char *
121 fileset_dlg_name2date_dup(const char * name) {
122     char        *pfx;
123     char        *filename;
124     size_t       pos;
125
126
127     /* just to be sure ... */
128         if(!fileset_filename_match_pattern(name)) {
129                 return NULL;
130         }
131
132     /* find char position behind the last underscore */
133     pfx = strrchr(name, '_');
134     pfx++;
135     pos = pfx - name;
136
137     /* start conversion behind that underscore */
138     filename = g_strdup_printf("%c%c%c%c.%c%c.%c%c %c%c:%c%c:%c%c",
139         /* year  */  name[pos]  ,  name[pos+1], name[pos+2], name[pos+3],
140         /* month */  name[pos+4],  name[pos+5],
141         /* day   */  name[pos+6],  name[pos+7],
142         /* hour */   name[pos+8],  name[pos+9],
143         /* min */    name[pos+10], name[pos+11],
144         /* second */ name[pos+12], name[pos+13]);
145
146     return filename;
147 }
148
149
150 /* this file is a part of the current file set, add it to the dialog */
151 void
152 fileset_dlg_add_file(fileset_entry *entry) {
153     char *created;
154     char *modified;
155     char *size;
156     struct tm *local;
157     GtkWidget     *fs_lb;
158     GtkWidget     *fs_rb;
159     gchar *title;
160
161
162     if (fs_w == NULL) {
163         return;
164     }
165
166     created = fileset_dlg_name2date_dup(entry->name);
167         if(!created) {
168                 /* if this file doesn't follow the file set pattern, */
169                 /* use the creation time of that file */
170                 local = localtime(&entry->ctime);
171                 created = g_strdup_printf("%04u.%02u.%02u %02u:%02u:%02u", 
172                         local->tm_year+1900, local->tm_mon+1, local->tm_mday,
173                         local->tm_hour, local->tm_min, local->tm_sec);
174         }
175
176     local = localtime(&entry->mtime);
177     modified = g_strdup_printf("%04u.%02u.%02u %02u:%02u:%02u", 
178         local->tm_year+1900, local->tm_mon+1, local->tm_mday,
179         local->tm_hour, local->tm_min, local->tm_sec);
180     size = g_strdup_printf("%" G_GINT64_MODIFIER "d Bytes", entry->size);
181
182     fs_rb = gtk_radio_button_new_with_label_from_widget(
183         fs_first_rb ? GTK_RADIO_BUTTON(fs_first_rb) : NULL, entry->name);
184     if(row == 1) {
185         fs_first_rb = fs_rb;
186     }
187     if(entry->current) {
188         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (fs_rb), entry->current);
189     }
190     gtk_tooltips_set_tip(tooltips, fs_rb, "Open this capture file", NULL);
191     gtk_table_attach_defaults(GTK_TABLE(fs_tb), fs_rb, 0, 1, row, row+1);
192     g_signal_connect(fs_rb, "toggled", G_CALLBACK(fs_rb_cb), entry);
193     gtk_widget_show(fs_rb);
194
195     fs_lb = gtk_label_new(created);
196     gtk_table_attach_defaults(GTK_TABLE(fs_tb), fs_lb, 1, 2, row, row+1);
197     gtk_widget_set_sensitive(fs_lb, entry->current);
198     gtk_widget_show(fs_lb);
199
200     fs_lb = gtk_label_new(modified);
201     gtk_table_attach_defaults(GTK_TABLE(fs_tb), fs_lb, 2, 3, row, row+1);
202     gtk_widget_set_sensitive(fs_lb, entry->current);
203     gtk_widget_show(fs_lb);
204
205     fs_lb = gtk_label_new(size);
206     gtk_table_attach_defaults(GTK_TABLE(fs_tb), fs_lb, 3, 4, row, row+1);
207     gtk_widget_set_sensitive(fs_lb, entry->current);
208     gtk_widget_show(fs_lb);
209
210     title = g_strdup_printf("Wireshark: %u File%s in Set", row, plurality(row, "", "s"));
211     gtk_window_set_title(GTK_WINDOW(fs_w), title);
212     g_free(title);
213
214     title = g_strdup_printf("... in directory: %s", fileset_get_dirname());
215      gtk_label_set_text(GTK_LABEL(fs_dir_lb), title);
216     g_free(title);
217
218     gtk_widget_show_all(fs_tb);
219
220     /* resize the table until we use 18 rows (fits well into 800*600), if it's bigger use a scrollbar */
221     /* XXX - I didn't found a way to automatically shrink the table size again */
222     if(row <= 18) {
223       GtkRequisition requisition;
224
225       gtk_widget_size_request(fs_tb, &requisition);
226       gtk_widget_set_size_request(fs_sw, -1, requisition.height);
227       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(fs_sw), GTK_POLICY_NEVER, GTK_POLICY_NEVER);
228     }
229     
230     if(row == 18) {
231       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(fs_sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
232     }
233     
234     row++;
235
236     g_free(created);
237     g_free(modified);
238     g_free(size);
239 }
240
241
242 /* init the fileset table */
243 static void
244 fileset_init_table(GtkWidget *parent)
245 {
246   GtkWidget     *fs_lb;
247
248   
249   fs_tb = gtk_table_new(6,1, FALSE);
250   gtk_table_set_row_spacings(GTK_TABLE(fs_tb), 1);
251   gtk_table_set_col_spacings(GTK_TABLE(fs_tb), 12);
252   gtk_container_add(GTK_CONTAINER(parent), fs_tb);
253
254   row = 0;
255   fs_first_rb = NULL;
256
257   fs_lb = gtk_label_new("Filename");
258   gtk_table_attach(GTK_TABLE(fs_tb), fs_lb, 0, 1, row, row+1, GTK_EXPAND|GTK_FILL, 0, 0,0);
259
260   fs_lb = gtk_label_new("Created");
261   gtk_table_attach(GTK_TABLE(fs_tb), fs_lb, 1, 2, row, row+1, GTK_EXPAND|GTK_FILL, 0, 0,0);
262
263   fs_lb = gtk_label_new("Last Modified");
264   gtk_table_attach(GTK_TABLE(fs_tb), fs_lb, 2, 3, row, row+1, GTK_EXPAND|GTK_FILL, 0, 0,0);
265
266   fs_lb = gtk_label_new("Size");
267   gtk_table_attach(GTK_TABLE(fs_tb), fs_lb, 3, 4, row, row+1, GTK_EXPAND|GTK_FILL, 0, 0,0);
268
269   gtk_widget_hide(fs_tb);
270
271   gtk_window_set_title(GTK_WINDOW(fs_w), "Wireshark: 0 Files in Set");
272
273    gtk_label_set_text(GTK_LABEL(fs_dir_lb), "No capture file loaded!");
274
275   row++;
276 }
277
278
279 /* open the fileset dialog */
280 void
281 fileset_cb(GtkWidget *w _U_, gpointer d _U_)
282 {
283   GtkWidget     *main_vb, *bbox, *close_bt, *help_bt;
284
285
286   if (fs_w != NULL) {
287     /* There's already a "File Set" dialog box; reactivate it. */
288     reactivate_window(fs_w);
289     return;
290   }
291
292   fs_w = window_new(GTK_WINDOW_TOPLEVEL, "");
293
294   tooltips = gtk_tooltips_new();
295
296   main_vb = gtk_vbox_new(FALSE, 5);
297   gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
298   gtk_container_add(GTK_CONTAINER(fs_w), main_vb);
299
300   fs_sw = gtk_scrolled_window_new(NULL, NULL);
301   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(fs_sw), GTK_POLICY_NEVER, GTK_POLICY_NEVER);
302   gtk_box_pack_start(GTK_BOX(main_vb), fs_sw, TRUE, TRUE, 0);
303
304   /* add a dummy container, so we can replace the table later */
305   fs_tb_vb = gtk_vbox_new(FALSE, 0);
306   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(fs_sw), fs_tb_vb);
307
308   fs_dir_lb = gtk_label_new("");
309   gtk_box_pack_start(GTK_BOX(main_vb), fs_dir_lb, FALSE, FALSE, 0);
310
311   fileset_init_table(fs_tb_vb);
312
313   /* Button row: close and help button */
314   bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
315   gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 5);
316
317   close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
318   window_set_cancel_button(fs_w, close_bt, window_cancel_button_cb);
319   gtk_tooltips_set_tip(tooltips, close_bt, "Close this window.", NULL);
320
321   help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
322   g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_FILESET_DIALOG);
323
324   gtk_widget_grab_default(close_bt);
325
326   g_signal_connect(fs_w, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
327   g_signal_connect(fs_w, "destroy", G_CALLBACK(fs_destroy_cb), NULL);
328
329   /* init the dialog content */
330   fileset_update_dlg();
331
332   gtk_widget_show_all(fs_w);
333   window_present(fs_w);
334 }
335
336
337 /* open the next file in the file set, or do nothing if already the last file */
338 void
339 fileset_next_cb(GtkWidget *w _U_, gpointer d _U_)
340 {
341     fileset_entry   *entry;
342
343     entry = fileset_get_next();
344
345     if(entry) {
346         fs_open_entry(entry);
347     }
348 }
349
350
351 /* open the previous file in the file set, or do nothing if already the first file */
352 void
353 fileset_previous_cb(GtkWidget *w _U_, gpointer d _U_)
354 {
355     fileset_entry   *entry;
356
357     entry = fileset_get_previous();
358
359     if(entry) {
360         fs_open_entry(entry);
361     }
362 }
363
364
365 /* a new capture file was opened, browse the dir and look for files matching the given file set */
366 void
367 fileset_file_opened(const char *fname) {
368   fileset_add_dir(fname);
369   if(fs_w) {
370     window_present(fs_w);
371   }
372
373   /* update the menu */
374   set_menus_for_file_set(TRUE /* file_set */, 
375       fileset_get_previous() != NULL, fileset_get_next() != NULL );
376 }
377
378
379 /* the capture file was closed */
380 void
381 fileset_file_closed(void)
382 {
383   if(fs_w) {
384     /* reinit the table, title and alike */
385     g_object_ref(G_OBJECT(fs_tb_vb));
386     gtk_widget_destroy(fs_tb);
387     fileset_delete();
388     fileset_init_table(fs_tb_vb);
389     window_present(fs_w);
390   } else {
391     fileset_delete();
392   }
393
394   /* update the menu */
395   set_menus_for_file_set(FALSE /* file_set */, 
396                          fileset_get_previous() != NULL,
397                          fileset_get_next() != NULL );
398 }
399