]> Pileus Git - ~andy/gtk/blob - tests/testfilechooser.c
new GTK_STOCK_NETWORK ... gtk/gtkstock.[hc] : ... define ...
[~andy/gtk] / tests / testfilechooser.c
1 #include "config.h"
2
3 #include <string.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <stdlib.h>
7 #include <time.h>
8 #ifdef HAVE_UNISTD_H
9 #include <unistd.h>
10 #endif
11 #include <gtk/gtk.h>
12
13 #ifdef G_OS_WIN32
14 #  define WIN32_MEAN_AND_LEAN
15 #  include <windows.h> /* ExtractAssociatedIcon */
16 #  include <io.h>
17 #  define localtime_r(t,b) localtime(t)
18 #  ifndef S_ISREG
19 #    define S_ISREG(m) ((m) & _S_IFREG)
20 #  endif
21 #  include <gdk/win32/gdkwin32.h> /* gdk_win32_hdc_get */
22 #endif
23
24 #include "prop-editor.h"
25
26 static GtkWidget *preview_label;
27 static GtkWidget *preview_image;
28
29 static void
30 print_current_folder (GtkFileChooser *chooser)
31 {
32   gchar *uri;
33
34   uri = gtk_file_chooser_get_current_folder_uri (chooser);
35   g_print ("Current folder changed :\n  %s\n", uri ? uri : "(null)");
36   g_free (uri);
37 }
38
39 static void
40 print_selected (GtkFileChooser *chooser)
41 {
42   GSList *uris = gtk_file_chooser_get_uris (chooser);
43   GSList *tmp_list;
44
45   g_print ("Selection changed :\n");
46   for (tmp_list = uris; tmp_list; tmp_list = tmp_list->next)
47     {
48       gchar *uri = tmp_list->data;
49       g_print ("  %s\n", uri);
50       g_free (uri);
51     }
52   g_print ("\n");
53   g_slist_free (uris);
54 }
55
56 static void
57 response_cb (GtkDialog *dialog,
58              gint       response_id)
59 {
60   if (response_id == GTK_RESPONSE_OK)
61     {
62       GSList *list;
63
64       list = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
65
66       if (list)
67         {
68           GSList *l;
69
70           g_print ("Selected files:\n");
71
72           for (l = list; l; l = l->next)
73             {
74               g_print ("%s\n", (char *) l->data);
75               g_free (l->data);
76             }
77
78           g_slist_free (list);
79         }
80       else
81         g_print ("No selected files\n");
82     }
83   else
84     g_print ("Dialog was closed\n");
85   
86   gtk_main_quit ();
87 }
88
89 static gboolean
90 no_backup_files_filter (const GtkFileFilterInfo *filter_info,
91                         gpointer                 data)
92 {
93   gsize len = filter_info->display_name ? strlen (filter_info->display_name) : 0;
94   if (len > 0 && filter_info->display_name[len - 1] == '~')
95     return 0;
96   else
97     return 1;
98 }
99
100 static char *
101 format_time (time_t t)
102 {
103   gchar buf[128];
104   struct tm tm_buf;
105   time_t now = time (NULL);
106   const char *format;
107
108   if (abs (now - t) < 24*60*60)
109     format = "%X";
110   else
111     format = "%x";
112
113   localtime_r (&t, &tm_buf);
114   if (strftime (buf, sizeof (buf), format, &tm_buf) == 0)
115     return g_strdup ("<unknown>");
116   else
117     return g_strdup (buf);
118 }
119
120 static char *
121 format_size (gint64 size)
122 {
123   if (size < (gint64)1024)
124     return g_strdup_printf ("%d bytes", (gint)size);
125   else if (size < (gint64)1024*1024)
126     return g_strdup_printf ("%.1f K", size / (1024.));
127   else if (size < (gint64)1024*1024*1024)
128     return g_strdup_printf ("%.1f M", size / (1024.*1024.));
129   else
130     return g_strdup_printf ("%.1f G", size / (1024.*1024.*1024.));
131 }
132
133 #include <stdio.h>
134 #include <errno.h>
135 #define _(s) (s)
136
137 static void
138 size_prepared_cb (GdkPixbufLoader *loader, 
139                   int              width,
140                   int              height,
141                   gpointer         data)
142 {
143         struct {
144                 int width;
145                 int height;
146         } *info = data;
147
148         if ((double)height * (double)info->width >
149             (double)width * (double)info->height) {
150                 width = 0.5 + (double)width * (double)info->height / (double)height;
151                 height = info->height;
152         } else {
153                 height = 0.5 + (double)height * (double)info->width / (double)width;
154                 width = info->width;
155         }
156
157         gdk_pixbuf_loader_set_size (loader, width, height);
158 }
159
160 GdkPixbuf *
161 my_new_from_file_at_size (const char *filename,
162                           int         width, 
163                           int         height,
164                           GError    **error)
165 {
166         GdkPixbufLoader *loader;
167         GdkPixbuf       *pixbuf;
168         struct {
169                 int width;
170                 int height;
171         } info;
172         struct stat st;
173
174         guchar buffer [4096];
175         int length;
176         FILE *f;
177
178         g_return_val_if_fail (filename != NULL, NULL);
179         g_return_val_if_fail (width > 0 && height > 0, NULL);
180
181         if (stat (filename, &st) != 0) {
182                 g_set_error (error,
183                              G_FILE_ERROR,
184                              g_file_error_from_errno (errno),
185                              _("Could not get information for file '%s': %s"),
186                              filename, g_strerror (errno));
187                 return NULL;
188         }
189
190         if (!S_ISREG (st.st_mode))
191                 return NULL;
192
193         f = fopen (filename, "rb");
194         if (!f) {
195                 g_set_error (error,
196                              G_FILE_ERROR,
197                              g_file_error_from_errno (errno),
198                              _("Failed to open file '%s': %s"),
199                              filename, g_strerror (errno));
200                 return NULL;
201         }
202         
203         loader = gdk_pixbuf_loader_new ();
204 #ifdef DONT_PRESERVE_ASPECT
205         gdk_pixbuf_loader_set_size (loader, width, height);
206 #else
207         info.width = width;
208         info.height = height;
209         g_signal_connect (loader, "size-prepared", G_CALLBACK (&size_prepared_cb), &info);
210 #endif  
211
212         while (!feof (f)) {
213                 length = fread (buffer, 1, sizeof (buffer), f);
214                 if (length > 0)
215                         if (!gdk_pixbuf_loader_write (loader, buffer, length, error)) {
216                                 gdk_pixbuf_loader_close (loader, NULL);
217                                 fclose (f);
218                                 g_object_unref (G_OBJECT (loader));
219                                 return NULL;
220                         }
221         }
222
223         fclose (f);
224
225         if (!gdk_pixbuf_loader_close (loader, error)) {
226                 g_object_unref (G_OBJECT (loader));
227                 return NULL;
228         }
229
230         pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
231
232         if (!pixbuf) {
233                 g_object_unref (G_OBJECT (loader));
234                 g_set_error (error,
235                              GDK_PIXBUF_ERROR,
236                              GDK_PIXBUF_ERROR_FAILED,
237                              _("Failed to load image '%s': reason not known, probably a corrupt image file"),
238                              filename);
239                 return NULL;
240         }
241
242         g_object_ref (pixbuf);
243
244         g_object_unref (G_OBJECT (loader));
245
246         return pixbuf;
247 }
248
249 static void
250 update_preview_cb (GtkFileChooser *chooser)
251 {
252   gchar *filename = gtk_file_chooser_get_preview_filename (chooser);
253   gboolean have_preview = FALSE;
254   
255   if (filename)
256     {
257       GdkPixbuf *pixbuf;
258       GError *error = NULL;
259
260       pixbuf = my_new_from_file_at_size (filename, 128, 128, &error);
261       if (pixbuf)
262         {
263           gtk_image_set_from_pixbuf (GTK_IMAGE (preview_image), pixbuf);
264           g_object_unref (pixbuf);
265           gtk_widget_show (preview_image);
266           gtk_widget_hide (preview_label);
267           have_preview = TRUE;
268         }
269       else
270         {
271           struct stat buf;
272           if (stat (filename, &buf) == 0)
273             {
274               gchar *preview_text;
275               gchar *size_str;
276               gchar *modified_time;
277               
278               size_str = format_size (buf.st_size);
279               modified_time = format_time (buf.st_mtime);
280               
281               preview_text = g_strdup_printf ("<i>Modified:</i>\t%s\n"
282                                               "<i>Size:</i>\t%s\n",
283                                               modified_time,
284                                               size_str);
285               gtk_label_set_markup (GTK_LABEL (preview_label), preview_text);
286               g_free (modified_time);
287               g_free (size_str);
288               g_free (preview_text);
289               
290               gtk_widget_hide (preview_image);
291               gtk_widget_show (preview_label);
292               have_preview = TRUE;
293             }
294         }
295       
296       g_free (filename);
297     }
298
299   gtk_file_chooser_set_preview_widget_active (chooser, have_preview);
300 }
301
302 int
303 main (int argc, char **argv)
304 {
305   GtkWidget *control_window;
306   GtkWidget *vbbox;
307   GtkWidget *button;
308   GtkWidget *dialog;
309   GtkWidget *prop_editor;
310   GtkFileFilter *filter;
311   GtkWidget *preview_vbox;
312   GtkWidget *extra;
313   
314   gtk_init (&argc, &argv);
315
316   dialog = g_object_new (GTK_TYPE_FILE_CHOOSER_DIALOG,
317                          "action", GTK_FILE_CHOOSER_ACTION_OPEN,
318                          "title", "Select a file",
319                          NULL);
320                          
321   gtk_dialog_add_buttons (GTK_DIALOG (dialog),
322                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
323                           GTK_STOCK_OPEN, GTK_RESPONSE_OK,
324                           NULL);
325   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
326   
327   g_signal_connect (dialog, "selection-changed",
328                     G_CALLBACK (print_selected), NULL);
329   g_signal_connect (dialog, "current-folder-changed",
330                     G_CALLBACK (print_current_folder), NULL);
331   g_signal_connect (dialog, "response",
332                     G_CALLBACK (response_cb), NULL);
333
334   /* Filters */
335   filter = gtk_file_filter_new ();
336   gtk_file_filter_set_name (filter, "All Files");
337   gtk_file_filter_add_pattern (filter, "*");
338   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
339   
340   filter = gtk_file_filter_new ();
341   gtk_file_filter_set_name (filter, "No backup files");
342   gtk_file_filter_add_custom (filter, GTK_FILE_FILTER_DISPLAY_NAME,
343                               no_backup_files_filter, NULL, NULL);
344   gtk_file_filter_add_mime_type (filter, "image/png");
345   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
346
347   /* Make this filter the default */
348   gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
349   
350   filter = gtk_file_filter_new ();
351   gtk_file_filter_set_name (filter, "PNG and JPEG");
352   gtk_file_filter_add_mime_type (filter, "image/jpeg");
353   gtk_file_filter_add_mime_type (filter, "image/png");
354   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
355
356   /* Preview widget */
357   preview_vbox = gtk_vbox_new (0, FALSE);
358   gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (dialog), preview_vbox);
359   
360   preview_label = gtk_label_new (NULL);
361   gtk_box_pack_start (GTK_BOX (preview_vbox), preview_label, TRUE, TRUE, 0);
362   gtk_misc_set_padding (GTK_MISC (preview_label), 6, 6);
363   
364   preview_image = gtk_image_new ();
365   gtk_box_pack_start (GTK_BOX (preview_vbox), preview_image, TRUE, TRUE, 0);
366   gtk_misc_set_padding (GTK_MISC (preview_image), 6, 6);
367   
368   update_preview_cb (GTK_FILE_CHOOSER (dialog));
369   g_signal_connect (dialog, "update-preview",
370                     G_CALLBACK (update_preview_cb), NULL);
371
372   /* Extra widget */
373   extra = gtk_check_button_new_with_mnemonic ("Lar_t whoever asks about this button");
374   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (extra), TRUE);
375   gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), extra);
376
377   /* Shortcuts */
378
379   gtk_file_chooser_add_shortcut_folder_uri (GTK_FILE_CHOOSER (dialog),
380                                             "file:///usr/share/pixmaps",
381                                             NULL);
382
383   /* Done with the dialog */
384   gtk_window_set_default_size (GTK_WINDOW (dialog), 600, 400);
385   /* show_all() to reveal bugs in composite widget handling */
386   gtk_widget_show_all (dialog);
387
388   /* Extra controls for manipulating the test environment
389    */
390   prop_editor = create_prop_editor (G_OBJECT (dialog), GTK_TYPE_FILE_CHOOSER);
391
392   control_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
393   
394   vbbox = gtk_vbutton_box_new ();
395   gtk_container_add (GTK_CONTAINER (control_window), vbbox);
396
397   button = gtk_button_new_with_mnemonic ("_Select all");
398   gtk_container_add (GTK_CONTAINER (vbbox), button);
399   g_signal_connect_swapped (button, "clicked",
400                             G_CALLBACK (gtk_file_chooser_select_all), dialog);
401   
402   button = gtk_button_new_with_mnemonic ("_Unselect all");
403   gtk_container_add (GTK_CONTAINER (vbbox), button);
404   g_signal_connect_swapped (button, "clicked",
405                             G_CALLBACK (gtk_file_chooser_unselect_all), dialog);
406
407   gtk_widget_show_all (control_window);
408   
409   gtk_main ();
410
411   return 0;
412 }