15 # define localtime_r(t,b) *(b) = *localtime (t)
17 # define S_ISREG(m) ((m) & _S_IFREG)
21 #include "prop-editor.h"
23 static GtkWidget *preview_label;
24 static GtkWidget *preview_image;
25 static GtkFileChooserAction action;
28 print_current_folder (GtkFileChooser *chooser)
32 uri = gtk_file_chooser_get_current_folder_uri (chooser);
33 g_print ("Current folder changed :\n %s\n", uri ? uri : "(null)");
38 print_selected (GtkFileChooser *chooser)
40 GSList *uris = gtk_file_chooser_get_uris (chooser);
43 g_print ("Selection changed :\n");
44 for (tmp_list = uris; tmp_list; tmp_list = tmp_list->next)
46 gchar *uri = tmp_list->data;
47 g_print (" %s\n", uri);
55 response_cb (GtkDialog *dialog,
58 if (response_id == GTK_RESPONSE_OK)
62 list = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog));
68 g_print ("Selected files:\n");
70 for (l = list; l; l = l->next)
72 g_print ("%s\n", (char *) l->data);
79 g_print ("No selected files\n");
82 g_print ("Dialog was closed\n");
88 no_backup_files_filter (const GtkFileFilterInfo *filter_info,
91 gsize len = filter_info->display_name ? strlen (filter_info->display_name) : 0;
92 if (len > 0 && filter_info->display_name[len - 1] == '~')
99 format_time (time_t t)
103 time_t now = time (NULL);
106 if (abs (now - t) < 24*60*60)
111 localtime_r (&t, &tm_buf);
112 if (strftime (buf, sizeof (buf), format, &tm_buf) == 0)
113 return g_strdup ("<unknown>");
115 return g_strdup (buf);
119 format_size (gint64 size)
121 if (size < (gint64)1024)
122 return g_strdup_printf ("%d bytes", (gint)size);
123 else if (size < (gint64)1024*1024)
124 return g_strdup_printf ("%.1f K", size / (1024.));
125 else if (size < (gint64)1024*1024*1024)
126 return g_strdup_printf ("%.1f M", size / (1024.*1024.));
128 return g_strdup_printf ("%.1f G", size / (1024.*1024.*1024.));
136 size_prepared_cb (GdkPixbufLoader *loader,
141 int des_width = data[0];
142 int des_height = data[1];
144 if (des_height >= height && des_width >= width) {
146 } else if ((double)height * des_width > (double)width * des_height) {
147 width = 0.5 + (double)width * des_height / (double)height;
150 height = 0.5 + (double)height * des_width / (double)width;
154 gdk_pixbuf_loader_set_size (loader, width, height);
158 my_new_from_file_at_size (const char *filename,
163 GdkPixbufLoader *loader;
168 guchar buffer [4096];
172 g_return_val_if_fail (filename != NULL, NULL);
173 g_return_val_if_fail (width > 0 && height > 0, NULL);
175 if (stat (filename, &st) != 0) {
178 g_file_error_from_errno (errno),
179 _("Could not get information for file '%s': %s"),
180 filename, g_strerror (errno));
184 if (!S_ISREG (st.st_mode))
187 f = fopen (filename, "rb");
191 g_file_error_from_errno (errno),
192 _("Failed to open file '%s': %s"),
193 filename, g_strerror (errno));
197 loader = gdk_pixbuf_loader_new ();
198 #ifdef DONT_PRESERVE_ASPECT
199 gdk_pixbuf_loader_set_size (loader, width, height);
203 g_signal_connect (loader, "size-prepared", G_CALLBACK (size_prepared_cb), info);
207 length = fread (buffer, 1, sizeof (buffer), f);
209 if (!gdk_pixbuf_loader_write (loader, buffer, length, error)) {
210 gdk_pixbuf_loader_close (loader, NULL);
212 g_object_unref (G_OBJECT (loader));
219 g_assert (*error == NULL);
220 if (!gdk_pixbuf_loader_close (loader, error)) {
221 g_object_unref (G_OBJECT (loader));
225 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
228 g_object_unref (G_OBJECT (loader));
230 /* did the loader set an error? */
236 GDK_PIXBUF_ERROR_FAILED,
237 _("Failed to load image '%s': reason not known, probably a corrupt image file"),
242 g_object_ref (pixbuf);
244 g_object_unref (G_OBJECT (loader));
250 update_preview_cb (GtkFileChooser *chooser)
252 gchar *filename = gtk_file_chooser_get_preview_filename (chooser);
253 gboolean have_preview = FALSE;
258 GError *error = NULL;
260 pixbuf = my_new_from_file_at_size (filename, 128, 128, &error);
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);
272 if (stat (filename, &buf) == 0)
276 gchar *modified_time;
278 size_str = format_size (buf.st_size);
279 modified_time = format_time (buf.st_mtime);
281 preview_text = g_strdup_printf ("<i>Modified:</i>\t%s\n"
282 "<i>Size:</i>\t%s\n",
285 gtk_label_set_markup (GTK_LABEL (preview_label), preview_text);
286 g_free (modified_time);
288 g_free (preview_text);
290 gtk_widget_hide (preview_image);
291 gtk_widget_show (preview_label);
299 g_error_free (error);
302 gtk_file_chooser_set_preview_widget_active (chooser, have_preview);
306 set_current_folder (GtkFileChooser *chooser,
309 if (!gtk_file_chooser_set_current_folder (chooser, name))
313 dialog = gtk_message_dialog_new (GTK_WINDOW (chooser),
314 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
317 "Could not set the folder to %s",
319 gtk_dialog_run (GTK_DIALOG (dialog));
320 gtk_widget_destroy (dialog);
325 set_folder_nonexistent_cb (GtkButton *button,
326 GtkFileChooser *chooser)
328 set_current_folder (chooser, "/nonexistent");
332 set_folder_existing_nonexistent_cb (GtkButton *button,
333 GtkFileChooser *chooser)
335 set_current_folder (chooser, "/usr/nonexistent");
339 set_filename (GtkFileChooser *chooser,
342 if (!gtk_file_chooser_set_filename (chooser, name))
346 dialog = gtk_message_dialog_new (GTK_WINDOW (chooser),
347 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
350 "Could not select %s",
352 gtk_dialog_run (GTK_DIALOG (dialog));
353 gtk_widget_destroy (dialog);
358 set_filename_nonexistent_cb (GtkButton *button,
359 GtkFileChooser *chooser)
361 set_filename (chooser, "/nonexistent");
365 set_filename_existing_nonexistent_cb (GtkButton *button,
366 GtkFileChooser *chooser)
368 set_filename (chooser, "/usr/nonexistent");
372 kill_dependent (GtkWindow *win, GtkObject *dep)
374 gtk_object_destroy (dep);
375 g_object_unref (dep);
379 main (int argc, char **argv)
381 GtkWidget *control_window;
385 GtkWidget *prop_editor;
387 GtkFileFilter *filter;
388 GtkWidget *preview_vbox;
390 gboolean multiple = FALSE;
392 gtk_init (&argc, &argv);
394 action = GTK_FILE_CHOOSER_ACTION_OPEN;
396 /* lame-o arg parsing */
397 for (i = 1; i < argc; i++)
399 if (! strcmp ("--action=open", argv[i]))
400 action = GTK_FILE_CHOOSER_ACTION_OPEN;
401 else if (! strcmp ("--action=save", argv[i]))
402 action = GTK_FILE_CHOOSER_ACTION_SAVE;
403 else if (! strcmp ("--action=select_folder", argv[i]))
404 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
405 else if (! strcmp ("--action=create_folder", argv[i]))
406 action = GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER;
407 else if (! strcmp ("--multiple", argv[i]))
411 dialog = g_object_new (GTK_TYPE_FILE_CHOOSER_DIALOG,
413 "file-system-backend", "gtk+",
414 "select-multiple", multiple,
418 case GTK_FILE_CHOOSER_ACTION_OPEN:
419 case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
420 gtk_window_set_title (GTK_WINDOW (dialog), "Select a file");
421 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
422 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
423 GTK_STOCK_OPEN, GTK_RESPONSE_OK,
426 case GTK_FILE_CHOOSER_ACTION_SAVE:
427 case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER:
428 gtk_window_set_title (GTK_WINDOW (dialog), "Save a file");
429 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
430 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
431 GTK_STOCK_SAVE, GTK_RESPONSE_OK,
435 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
437 g_signal_connect (dialog, "selection-changed",
438 G_CALLBACK (print_selected), NULL);
439 g_signal_connect (dialog, "current-folder-changed",
440 G_CALLBACK (print_current_folder), NULL);
441 g_signal_connect (dialog, "response",
442 G_CALLBACK (response_cb), NULL);
445 filter = gtk_file_filter_new ();
446 gtk_file_filter_set_name (filter, "All Files");
447 gtk_file_filter_add_pattern (filter, "*");
448 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
450 filter = gtk_file_filter_new ();
451 gtk_file_filter_set_name (filter, "No backup files");
452 gtk_file_filter_add_custom (filter, GTK_FILE_FILTER_DISPLAY_NAME,
453 no_backup_files_filter, NULL, NULL);
454 gtk_file_filter_add_mime_type (filter, "image/png");
455 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
457 /* Make this filter the default */
458 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
460 filter = gtk_file_filter_new ();
461 gtk_file_filter_set_name (filter, "PNG and JPEG");
462 gtk_file_filter_add_mime_type (filter, "image/jpeg");
463 gtk_file_filter_add_mime_type (filter, "image/png");
464 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
467 /* THIS IS A TERRIBLE PREVIEW WIDGET, AND SHOULD NOT BE COPIED AT ALL.
469 preview_vbox = gtk_vbox_new (0, FALSE);
470 /* gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (dialog), preview_vbox);*/
472 preview_label = gtk_label_new (NULL);
473 gtk_box_pack_start (GTK_BOX (preview_vbox), preview_label, TRUE, TRUE, 0);
474 gtk_misc_set_padding (GTK_MISC (preview_label), 6, 6);
476 preview_image = gtk_image_new ();
477 gtk_box_pack_start (GTK_BOX (preview_vbox), preview_image, TRUE, TRUE, 0);
478 gtk_misc_set_padding (GTK_MISC (preview_image), 6, 6);
480 update_preview_cb (GTK_FILE_CHOOSER (dialog));
481 g_signal_connect (dialog, "update-preview",
482 G_CALLBACK (update_preview_cb), NULL);
486 extra = gtk_check_button_new_with_mnemonic ("Lar_t whoever asks about this button");
487 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (extra), TRUE);
488 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), extra);
492 gtk_file_chooser_add_shortcut_folder_uri (GTK_FILE_CHOOSER (dialog),
493 "file:///usr/share/pixmaps",
496 /* show_all() to reveal bugs in composite widget handling */
497 gtk_widget_show_all (dialog);
499 /* Extra controls for manipulating the test environment
501 prop_editor = create_prop_editor (G_OBJECT (dialog), GTK_TYPE_FILE_CHOOSER);
503 control_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
505 vbbox = gtk_vbutton_box_new ();
506 gtk_container_add (GTK_CONTAINER (control_window), vbbox);
508 button = gtk_button_new_with_mnemonic ("_Select all");
509 gtk_widget_set_sensitive (button, multiple);
510 gtk_container_add (GTK_CONTAINER (vbbox), button);
511 g_signal_connect_swapped (button, "clicked",
512 G_CALLBACK (gtk_file_chooser_select_all), dialog);
514 button = gtk_button_new_with_mnemonic ("_Unselect all");
515 gtk_container_add (GTK_CONTAINER (vbbox), button);
516 g_signal_connect_swapped (button, "clicked",
517 G_CALLBACK (gtk_file_chooser_unselect_all), dialog);
519 button = gtk_button_new_with_label ("set_current_folder (\"/nonexistent\")");
520 gtk_container_add (GTK_CONTAINER (vbbox), button);
521 g_signal_connect (button, "clicked",
522 G_CALLBACK (set_folder_nonexistent_cb), dialog);
524 button = gtk_button_new_with_label ("set_current_folder (\"/usr/nonexistent\"");
525 gtk_container_add (GTK_CONTAINER (vbbox), button);
526 g_signal_connect (button, "clicked",
527 G_CALLBACK (set_folder_existing_nonexistent_cb), dialog);
529 button = gtk_button_new_with_label ("set_filename (\"/nonexistent\"");
530 gtk_container_add (GTK_CONTAINER (vbbox), button);
531 g_signal_connect (button, "clicked",
532 G_CALLBACK (set_filename_nonexistent_cb), dialog);
534 button = gtk_button_new_with_label ("set_filename (\"/usr/nonexistent\"");
535 gtk_container_add (GTK_CONTAINER (vbbox), button);
536 g_signal_connect (button, "clicked",
537 G_CALLBACK (set_filename_existing_nonexistent_cb), dialog);
539 gtk_widget_show_all (control_window);
541 g_object_ref (control_window);
542 g_signal_connect (G_OBJECT (dialog), "destroy",
543 G_CALLBACK (kill_dependent), control_window);
545 /* We need to hold a ref until we have destroyed the widgets, just in case
546 * someone else destroys them. We explicitly destroy windows to catch leaks.
548 g_object_ref (dialog);
550 gtk_widget_destroy (dialog);
551 g_object_unref (dialog);