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 filter_changed (GtkFileChooserDialog *dialog,
102 g_print ("file filter changed\n");
106 format_time (time_t t)
110 time_t now = time (NULL);
113 if (abs (now - t) < 24*60*60)
118 localtime_r (&t, &tm_buf);
119 if (strftime (buf, sizeof (buf), format, &tm_buf) == 0)
120 return g_strdup ("<unknown>");
122 return g_strdup (buf);
126 format_size (gint64 size)
128 if (size < (gint64)1024)
129 return g_strdup_printf ("%d bytes", (gint)size);
130 else if (size < (gint64)1024*1024)
131 return g_strdup_printf ("%.1f K", size / (1024.));
132 else if (size < (gint64)1024*1024*1024)
133 return g_strdup_printf ("%.1f M", size / (1024.*1024.));
135 return g_strdup_printf ("%.1f G", size / (1024.*1024.*1024.));
143 size_prepared_cb (GdkPixbufLoader *loader,
148 int des_width = data[0];
149 int des_height = data[1];
151 if (des_height >= height && des_width >= width) {
153 } else if ((double)height * des_width > (double)width * des_height) {
154 width = 0.5 + (double)width * des_height / (double)height;
157 height = 0.5 + (double)height * des_width / (double)width;
161 gdk_pixbuf_loader_set_size (loader, width, height);
165 my_new_from_file_at_size (const char *filename,
170 GdkPixbufLoader *loader;
175 guchar buffer [4096];
179 g_return_val_if_fail (filename != NULL, NULL);
180 g_return_val_if_fail (width > 0 && height > 0, NULL);
182 if (stat (filename, &st) != 0) {
185 g_file_error_from_errno (errno),
186 _("Could not get information for file '%s': %s"),
187 filename, g_strerror (errno));
191 if (!S_ISREG (st.st_mode))
194 f = fopen (filename, "rb");
198 g_file_error_from_errno (errno),
199 _("Failed to open file '%s': %s"),
200 filename, g_strerror (errno));
204 loader = gdk_pixbuf_loader_new ();
205 #ifdef DONT_PRESERVE_ASPECT
206 gdk_pixbuf_loader_set_size (loader, width, height);
210 g_signal_connect (loader, "size-prepared", G_CALLBACK (size_prepared_cb), info);
214 length = fread (buffer, 1, sizeof (buffer), f);
216 if (!gdk_pixbuf_loader_write (loader, buffer, length, error)) {
217 gdk_pixbuf_loader_close (loader, NULL);
219 g_object_unref (G_OBJECT (loader));
226 g_assert (*error == NULL);
227 if (!gdk_pixbuf_loader_close (loader, error)) {
228 g_object_unref (G_OBJECT (loader));
232 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
235 g_object_unref (G_OBJECT (loader));
237 /* did the loader set an error? */
243 GDK_PIXBUF_ERROR_FAILED,
244 _("Failed to load image '%s': reason not known, probably a corrupt image file"),
249 g_object_ref (pixbuf);
251 g_object_unref (G_OBJECT (loader));
257 update_preview_cb (GtkFileChooser *chooser)
259 gchar *filename = gtk_file_chooser_get_preview_filename (chooser);
260 gboolean have_preview = FALSE;
265 GError *error = NULL;
267 pixbuf = my_new_from_file_at_size (filename, 128, 128, &error);
270 gtk_image_set_from_pixbuf (GTK_IMAGE (preview_image), pixbuf);
271 g_object_unref (pixbuf);
272 gtk_widget_show (preview_image);
273 gtk_widget_hide (preview_label);
279 if (stat (filename, &buf) == 0)
283 gchar *modified_time;
285 size_str = format_size (buf.st_size);
286 modified_time = format_time (buf.st_mtime);
288 preview_text = g_strdup_printf ("<i>Modified:</i>\t%s\n"
289 "<i>Size:</i>\t%s\n",
292 gtk_label_set_markup (GTK_LABEL (preview_label), preview_text);
293 g_free (modified_time);
295 g_free (preview_text);
297 gtk_widget_hide (preview_image);
298 gtk_widget_show (preview_label);
306 g_error_free (error);
309 gtk_file_chooser_set_preview_widget_active (chooser, have_preview);
313 set_current_folder (GtkFileChooser *chooser,
316 if (!gtk_file_chooser_set_current_folder (chooser, name))
320 dialog = gtk_message_dialog_new (GTK_WINDOW (chooser),
321 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
324 "Could not set the folder to %s",
326 gtk_dialog_run (GTK_DIALOG (dialog));
327 gtk_widget_destroy (dialog);
332 set_folder_nonexistent_cb (GtkButton *button,
333 GtkFileChooser *chooser)
335 set_current_folder (chooser, "/nonexistent");
339 set_folder_existing_nonexistent_cb (GtkButton *button,
340 GtkFileChooser *chooser)
342 set_current_folder (chooser, "/usr/nonexistent");
346 set_filename (GtkFileChooser *chooser,
349 if (!gtk_file_chooser_set_filename (chooser, name))
353 dialog = gtk_message_dialog_new (GTK_WINDOW (chooser),
354 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
357 "Could not select %s",
359 gtk_dialog_run (GTK_DIALOG (dialog));
360 gtk_widget_destroy (dialog);
365 set_filename_nonexistent_cb (GtkButton *button,
366 GtkFileChooser *chooser)
368 set_filename (chooser, "/nonexistent");
372 set_filename_existing_nonexistent_cb (GtkButton *button,
373 GtkFileChooser *chooser)
375 set_filename (chooser, "/usr/nonexistent");
379 kill_dependent (GtkWindow *win, GtkObject *dep)
381 gtk_object_destroy (dep);
382 g_object_unref (dep);
386 notify_multiple_cb (GtkWidget *dialog,
392 multiple = gtk_file_chooser_get_select_multiple (GTK_FILE_CHOOSER (dialog));
394 gtk_widget_set_sensitive (button, multiple);
398 main (int argc, char **argv)
400 GtkWidget *control_window;
404 GtkWidget *prop_editor;
406 GtkFileFilter *filter;
407 GtkWidget *preview_vbox;
409 gboolean multiple = FALSE;
411 gtk_init (&argc, &argv);
413 /* to test rtl layout, set RTL=1 in the environment */
414 if (g_getenv ("RTL"))
415 gtk_widget_set_default_direction (GTK_TEXT_DIR_RTL);
417 action = GTK_FILE_CHOOSER_ACTION_OPEN;
419 /* lame-o arg parsing */
420 for (i = 1; i < argc; i++)
422 if (! strcmp ("--action=open", argv[i]))
423 action = GTK_FILE_CHOOSER_ACTION_OPEN;
424 else if (! strcmp ("--action=save", argv[i]))
425 action = GTK_FILE_CHOOSER_ACTION_SAVE;
426 else if (! strcmp ("--action=select_folder", argv[i]))
427 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
428 else if (! strcmp ("--action=create_folder", argv[i]))
429 action = GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER;
430 else if (! strcmp ("--multiple", argv[i]))
434 dialog = g_object_new (GTK_TYPE_FILE_CHOOSER_DIALOG,
436 "file-system-backend", "gtk+",
437 "select-multiple", multiple,
441 case GTK_FILE_CHOOSER_ACTION_OPEN:
442 case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
443 gtk_window_set_title (GTK_WINDOW (dialog), "Select a file");
444 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
445 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
446 GTK_STOCK_OPEN, GTK_RESPONSE_OK,
449 case GTK_FILE_CHOOSER_ACTION_SAVE:
450 case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER:
451 gtk_window_set_title (GTK_WINDOW (dialog), "Save a file");
452 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
453 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
454 GTK_STOCK_SAVE, GTK_RESPONSE_OK,
458 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
460 g_signal_connect (dialog, "selection-changed",
461 G_CALLBACK (print_selected), NULL);
462 g_signal_connect (dialog, "current-folder-changed",
463 G_CALLBACK (print_current_folder), NULL);
464 g_signal_connect (dialog, "response",
465 G_CALLBACK (response_cb), NULL);
468 filter = gtk_file_filter_new ();
469 gtk_file_filter_set_name (filter, "All Files");
470 gtk_file_filter_add_pattern (filter, "*");
471 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
473 filter = gtk_file_filter_new ();
474 gtk_file_filter_set_name (filter, "No backup files");
475 gtk_file_filter_add_custom (filter, GTK_FILE_FILTER_DISPLAY_NAME,
476 no_backup_files_filter, NULL, NULL);
477 gtk_file_filter_add_mime_type (filter, "image/png");
478 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
480 g_signal_connect (dialog, "notify::filter",
481 G_CALLBACK (filter_changed), NULL);
483 /* Make this filter the default */
484 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
486 filter = gtk_file_filter_new ();
487 gtk_file_filter_set_name (filter, "PNG and JPEG");
488 gtk_file_filter_add_mime_type (filter, "image/jpeg");
489 gtk_file_filter_add_mime_type (filter, "image/png");
490 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
492 filter = gtk_file_filter_new ();
493 gtk_file_filter_set_name (filter, "Images");
494 gtk_file_filter_add_pixbuf_formats (filter);
495 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
498 /* THIS IS A TERRIBLE PREVIEW WIDGET, AND SHOULD NOT BE COPIED AT ALL.
500 preview_vbox = gtk_vbox_new (0, FALSE);
501 /*gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (dialog), preview_vbox);*/
503 preview_label = gtk_label_new (NULL);
504 gtk_box_pack_start (GTK_BOX (preview_vbox), preview_label, TRUE, TRUE, 0);
505 gtk_misc_set_padding (GTK_MISC (preview_label), 6, 6);
507 preview_image = gtk_image_new ();
508 gtk_box_pack_start (GTK_BOX (preview_vbox), preview_image, TRUE, TRUE, 0);
509 gtk_misc_set_padding (GTK_MISC (preview_image), 6, 6);
511 update_preview_cb (GTK_FILE_CHOOSER (dialog));
512 g_signal_connect (dialog, "update-preview",
513 G_CALLBACK (update_preview_cb), NULL);
517 extra = gtk_check_button_new_with_mnemonic ("Lar_t whoever asks about this button");
518 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (extra), TRUE);
519 gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), extra);
523 gtk_file_chooser_add_shortcut_folder_uri (GTK_FILE_CHOOSER (dialog),
524 "file:///usr/share/pixmaps",
527 /* show_all() to reveal bugs in composite widget handling */
528 gtk_widget_show_all (dialog);
530 /* Extra controls for manipulating the test environment
532 prop_editor = create_prop_editor (G_OBJECT (dialog), GTK_TYPE_FILE_CHOOSER);
534 control_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
536 vbbox = gtk_vbutton_box_new ();
537 gtk_container_add (GTK_CONTAINER (control_window), vbbox);
539 button = gtk_button_new_with_mnemonic ("_Select all");
540 gtk_widget_set_sensitive (button, multiple);
541 gtk_container_add (GTK_CONTAINER (vbbox), button);
542 g_signal_connect_swapped (button, "clicked",
543 G_CALLBACK (gtk_file_chooser_select_all), dialog);
544 g_signal_connect (dialog, "notify::select-multiple",
545 G_CALLBACK (notify_multiple_cb), button);
547 button = gtk_button_new_with_mnemonic ("_Unselect all");
548 gtk_container_add (GTK_CONTAINER (vbbox), button);
549 g_signal_connect_swapped (button, "clicked",
550 G_CALLBACK (gtk_file_chooser_unselect_all), dialog);
552 button = gtk_button_new_with_label ("set_current_folder (\"/nonexistent\")");
553 gtk_container_add (GTK_CONTAINER (vbbox), button);
554 g_signal_connect (button, "clicked",
555 G_CALLBACK (set_folder_nonexistent_cb), dialog);
557 button = gtk_button_new_with_label ("set_current_folder (\"/usr/nonexistent\")");
558 gtk_container_add (GTK_CONTAINER (vbbox), button);
559 g_signal_connect (button, "clicked",
560 G_CALLBACK (set_folder_existing_nonexistent_cb), dialog);
562 button = gtk_button_new_with_label ("set_filename (\"/nonexistent\")");
563 gtk_container_add (GTK_CONTAINER (vbbox), button);
564 g_signal_connect (button, "clicked",
565 G_CALLBACK (set_filename_nonexistent_cb), dialog);
567 button = gtk_button_new_with_label ("set_filename (\"/usr/nonexistent\")");
568 gtk_container_add (GTK_CONTAINER (vbbox), button);
569 g_signal_connect (button, "clicked",
570 G_CALLBACK (set_filename_existing_nonexistent_cb), dialog);
572 gtk_widget_show_all (control_window);
574 g_object_ref (control_window);
575 g_signal_connect (G_OBJECT (dialog), "destroy",
576 G_CALLBACK (kill_dependent), control_window);
578 /* We need to hold a ref until we have destroyed the widgets, just in case
579 * someone else destroys them. We explicitly destroy windows to catch leaks.
581 g_object_ref (dialog);
583 gtk_widget_destroy (dialog);
584 g_object_unref (dialog);