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