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