1 /* GTK - The GIMP Toolkit
2 * gtkfilechooserdefault.c: Default implementation of GtkFileChooser
3 * Copyright (C) 2003, Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 #include "gdk/gdkkeysyms.h"
23 #include "gtkalignment.h"
24 #include "gtkbindings.h"
25 #include "gtkbutton.h"
26 #include "gtkcelllayout.h"
27 #include "gtkcellrendererpixbuf.h"
28 #include "gtkcellrendererseptext.h"
29 #include "gtkcellrenderertext.h"
30 #include "gtkcombobox.h"
32 #include "gtkexpander.h"
33 #include "gtkfilechooserdefault.h"
34 #include "gtkfilechooserembed.h"
35 #include "gtkfilechooserentry.h"
36 #include "gtkfilechooserutils.h"
37 #include "gtkfilechooser.h"
38 #include "gtkfilesystemmodel.h"
41 #include "gtkhpaned.h"
42 #include "gtkicontheme.h"
46 #include "gtkmarshalers.h"
47 #include "gtkmenuitem.h"
48 #include "gtkmessagedialog.h"
49 #include "gtkpathbar.h"
50 #include "gtkprivate.h"
51 #include "gtkscrolledwindow.h"
52 #include "gtksizegroup.h"
55 #include "gtktreeview.h"
56 #include "gtktreemodelsort.h"
57 #include "gtktreeselection.h"
58 #include "gtktreestore.h"
59 #include "gtktypebuiltins.h"
62 #if defined (G_OS_UNIX)
63 #include "gtkfilesystemunix.h"
64 #elif defined (G_OS_WIN32)
65 #include "gtkfilesystemwin32.h"
71 typedef struct _GtkFileChooserDefaultClass GtkFileChooserDefaultClass;
73 #define GTK_FILE_CHOOSER_DEFAULT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_CHOOSER_DEFAULT, GtkFileChooserDefaultClass))
74 #define GTK_IS_FILE_CHOOSER_DEFAULT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_CHOOSER_DEFAULT))
75 #define GTK_FILE_CHOOSER_DEFAULT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_CHOOSER_DEFAULT, GtkFileChooserDefaultClass))
78 struct _GtkFileChooserDefaultClass
80 GtkVBoxClass parent_class;
83 struct _GtkFileChooserDefault
85 GtkVBox parent_instance;
87 GtkFileChooserAction action;
89 GtkFileSystem *file_system;
91 /* Save mode widgets */
92 GtkWidget *save_widgets;
94 GtkWidget *save_file_name_entry;
95 GtkWidget *save_folder_label;
96 GtkWidget *save_folder_combo;
97 GtkWidget *save_extra_align;
98 GtkWidget *save_expander;
100 /* The file browsing widgets */
101 GtkWidget *browse_widgets;
102 GtkWidget *browse_shortcuts_tree_view;
103 GtkWidget *browse_shortcuts_swin;
104 GtkWidget *browse_shortcuts_add_button;
105 GtkWidget *browse_shortcuts_remove_button;
106 GtkWidget *browse_files_tree_view;
107 GtkWidget *browse_new_folder_button;
108 GtkWidget *browse_path_bar;
109 GtkWidget *browse_extra_align;
111 GtkFileSystemModel *browse_files_model;
113 GtkWidget *filter_combo;
114 GtkWidget *preview_box;
115 GtkWidget *preview_label;
116 GtkWidget *preview_widget;
117 GtkWidget *extra_widget;
119 GtkListStore *shortcuts_model;
120 GtkTreeModel *shortcuts_filter_model;
122 GtkTreeModelSort *sort_model;
124 GtkFileFilter *current_filter;
128 gboolean has_desktop;
134 guint volumes_changed_id;
135 guint bookmarks_changed_id;
137 GtkFilePath *current_volume_path;
138 GtkFilePath *current_folder;
139 GtkFilePath *preview_path;
140 char *preview_display_name;
142 GtkTreeViewColumn *list_name_column;
143 GtkCellRenderer *list_name_renderer;
147 guint local_only : 1;
148 guint preview_widget_active : 1;
149 guint use_preview_label : 1;
150 guint select_multiple : 1;
151 guint show_hidden : 1;
152 guint list_sort_ascending : 1;
153 guint changing_folder : 1;
154 guint shortcuts_current_folder_active : 1;
155 guint shortcuts_current_folder_is_volume : 1;
166 static guint signals[LAST_SIGNAL] = { 0 };
168 /* Column numbers for the shortcuts tree. Keep these in sync with shortcuts_model_create() */
170 SHORTCUTS_COL_PIXBUF,
173 SHORTCUTS_COL_REMOVABLE,
174 SHORTCUTS_COL_PIXBUF_VISIBLE,
175 SHORTCUTS_COL_NUM_COLUMNS
178 /* Column numbers for the file list */
183 FILE_LIST_COL_NUM_COLUMNS
186 /* Identifiers for target types */
191 /* Target types for DnD in the shortcuts list */
192 static GtkTargetEntry shortcuts_targets[] = {
193 { "text/uri-list", 0, TEXT_URI_LIST }
196 static const int num_shortcuts_targets = sizeof (shortcuts_targets) / sizeof (shortcuts_targets[0]);
198 /* Interesting places in the shortcuts bar */
204 SHORTCUTS_BOOKMARKS_SEPARATOR,
206 SHORTCUTS_CURRENT_FOLDER_SEPARATOR,
207 SHORTCUTS_CURRENT_FOLDER
210 /* Standard icon size */
211 /* FIXME: maybe this should correspond to the font size in the tree views... */
213 #define PREVIEW_HBOX_SPACING 12
217 static void gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class);
218 static void gtk_file_chooser_default_iface_init (GtkFileChooserIface *iface);
219 static void gtk_file_chooser_embed_default_iface_init (GtkFileChooserEmbedIface *iface);
220 static void gtk_file_chooser_default_init (GtkFileChooserDefault *impl);
222 static GObject* gtk_file_chooser_default_constructor (GType type,
223 guint n_construct_properties,
224 GObjectConstructParam *construct_params);
225 static void gtk_file_chooser_default_finalize (GObject *object);
226 static void gtk_file_chooser_default_set_property (GObject *object,
230 static void gtk_file_chooser_default_get_property (GObject *object,
234 static void gtk_file_chooser_default_dispose (GObject *object);
235 static void gtk_file_chooser_default_show_all (GtkWidget *widget);
236 static void gtk_file_chooser_default_style_set (GtkWidget *widget,
237 GtkStyle *previous_style);
238 static void gtk_file_chooser_default_screen_changed (GtkWidget *widget,
239 GdkScreen *previous_screen);
241 static gboolean gtk_file_chooser_default_set_current_folder (GtkFileChooser *chooser,
242 const GtkFilePath *path,
244 static GtkFilePath * gtk_file_chooser_default_get_current_folder (GtkFileChooser *chooser);
245 static void gtk_file_chooser_default_set_current_name (GtkFileChooser *chooser,
247 static gboolean gtk_file_chooser_default_select_path (GtkFileChooser *chooser,
248 const GtkFilePath *path,
250 static void gtk_file_chooser_default_unselect_path (GtkFileChooser *chooser,
251 const GtkFilePath *path);
252 static void gtk_file_chooser_default_select_all (GtkFileChooser *chooser);
253 static void gtk_file_chooser_default_unselect_all (GtkFileChooser *chooser);
254 static GSList * gtk_file_chooser_default_get_paths (GtkFileChooser *chooser);
255 static GtkFilePath * gtk_file_chooser_default_get_preview_path (GtkFileChooser *chooser);
256 static GtkFileSystem *gtk_file_chooser_default_get_file_system (GtkFileChooser *chooser);
257 static void gtk_file_chooser_default_add_filter (GtkFileChooser *chooser,
258 GtkFileFilter *filter);
259 static void gtk_file_chooser_default_remove_filter (GtkFileChooser *chooser,
260 GtkFileFilter *filter);
261 static GSList * gtk_file_chooser_default_list_filters (GtkFileChooser *chooser);
262 static gboolean gtk_file_chooser_default_add_shortcut_folder (GtkFileChooser *chooser,
263 const GtkFilePath *path,
265 static gboolean gtk_file_chooser_default_remove_shortcut_folder (GtkFileChooser *chooser,
266 const GtkFilePath *path,
268 static GSList * gtk_file_chooser_default_list_shortcut_folders (GtkFileChooser *chooser);
270 static void gtk_file_chooser_default_get_default_size (GtkFileChooserEmbed *chooser_embed,
272 gint *default_height);
273 static void gtk_file_chooser_default_get_resizable_hints (GtkFileChooserEmbed *chooser_embed,
274 gboolean *resize_horizontally,
275 gboolean *resize_vertically);
276 static gboolean gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed);
278 static void location_popup_handler (GtkFileChooserDefault *impl);
279 static void up_folder_handler (GtkFileChooserDefault *impl);
280 static void home_folder_handler (GtkFileChooserDefault *impl);
281 static void update_appearance (GtkFileChooserDefault *impl);
283 static void set_current_filter (GtkFileChooserDefault *impl,
284 GtkFileFilter *filter);
285 static void check_preview_change (GtkFileChooserDefault *impl);
287 static void filter_combo_changed (GtkComboBox *combo_box,
288 GtkFileChooserDefault *impl);
289 static void shortcuts_row_activated_cb (GtkTreeView *tree_view,
291 GtkTreeViewColumn *column,
292 GtkFileChooserDefault *impl);
293 static gboolean shortcuts_select_func (GtkTreeSelection *selection,
296 gboolean path_currently_selected,
298 static void shortcuts_activate_item (GtkFileChooserDefault *impl,
300 static int shortcuts_get_index (GtkFileChooserDefault *impl,
301 ShortcutsIndex where);
302 static int shortcut_find_position (GtkFileChooserDefault *impl,
303 const GtkFilePath *path);
305 static void list_selection_changed (GtkTreeSelection *tree_selection,
306 GtkFileChooserDefault *impl);
307 static void list_row_activated (GtkTreeView *tree_view,
309 GtkTreeViewColumn *column,
310 GtkFileChooserDefault *impl);
312 static void path_bar_clicked (GtkPathBar *path_bar,
313 GtkFilePath *file_path,
314 GtkFileChooserDefault *impl);
316 static void add_bookmark_button_clicked_cb (GtkButton *button,
317 GtkFileChooserDefault *impl);
318 static void remove_bookmark_button_clicked_cb (GtkButton *button,
319 GtkFileChooserDefault *impl);
321 static void list_icon_data_func (GtkTreeViewColumn *tree_column,
322 GtkCellRenderer *cell,
323 GtkTreeModel *tree_model,
326 static void list_name_data_func (GtkTreeViewColumn *tree_column,
327 GtkCellRenderer *cell,
328 GtkTreeModel *tree_model,
332 static void list_size_data_func (GtkTreeViewColumn *tree_column,
333 GtkCellRenderer *cell,
334 GtkTreeModel *tree_model,
338 static void list_mtime_data_func (GtkTreeViewColumn *tree_column,
339 GtkCellRenderer *cell,
340 GtkTreeModel *tree_model,
344 static GObjectClass *parent_class;
347 _gtk_file_chooser_default_get_type (void)
349 static GType file_chooser_default_type = 0;
351 if (!file_chooser_default_type)
353 static const GTypeInfo file_chooser_default_info =
355 sizeof (GtkFileChooserDefaultClass),
356 NULL, /* base_init */
357 NULL, /* base_finalize */
358 (GClassInitFunc) gtk_file_chooser_default_class_init,
359 NULL, /* class_finalize */
360 NULL, /* class_data */
361 sizeof (GtkFileChooserDefault),
363 (GInstanceInitFunc) gtk_file_chooser_default_init,
366 static const GInterfaceInfo file_chooser_info =
368 (GInterfaceInitFunc) gtk_file_chooser_default_iface_init, /* interface_init */
369 NULL, /* interface_finalize */
370 NULL /* interface_data */
373 static const GInterfaceInfo file_chooser_embed_info =
375 (GInterfaceInitFunc) gtk_file_chooser_embed_default_iface_init, /* interface_init */
376 NULL, /* interface_finalize */
377 NULL /* interface_data */
380 file_chooser_default_type = g_type_register_static (GTK_TYPE_VBOX, "GtkFileChooserDefault",
381 &file_chooser_default_info, 0);
383 g_type_add_interface_static (file_chooser_default_type,
384 GTK_TYPE_FILE_CHOOSER,
386 g_type_add_interface_static (file_chooser_default_type,
387 GTK_TYPE_FILE_CHOOSER_EMBED,
388 &file_chooser_embed_info);
391 return file_chooser_default_type;
395 gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
397 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
398 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
399 GtkBindingSet *binding_set;
401 parent_class = g_type_class_peek_parent (class);
403 gobject_class->finalize = gtk_file_chooser_default_finalize;
404 gobject_class->constructor = gtk_file_chooser_default_constructor;
405 gobject_class->set_property = gtk_file_chooser_default_set_property;
406 gobject_class->get_property = gtk_file_chooser_default_get_property;
407 gobject_class->dispose = gtk_file_chooser_default_dispose;
409 widget_class->show_all = gtk_file_chooser_default_show_all;
410 widget_class->style_set = gtk_file_chooser_default_style_set;
411 widget_class->screen_changed = gtk_file_chooser_default_screen_changed;
413 signals[LOCATION_POPUP] =
414 _gtk_binding_signal_new ("location-popup",
415 G_OBJECT_CLASS_TYPE (class),
416 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
417 G_CALLBACK (location_popup_handler),
419 _gtk_marshal_VOID__VOID,
422 _gtk_binding_signal_new ("up-folder",
423 G_OBJECT_CLASS_TYPE (class),
424 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
425 G_CALLBACK (up_folder_handler),
427 _gtk_marshal_VOID__VOID,
429 signals[HOME_FOLDER] =
430 _gtk_binding_signal_new ("home-folder",
431 G_OBJECT_CLASS_TYPE (class),
432 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
433 G_CALLBACK (home_folder_handler),
435 _gtk_marshal_VOID__VOID,
438 binding_set = gtk_binding_set_by_class (class);
440 gtk_binding_entry_add_signal (binding_set,
441 GDK_l, GDK_CONTROL_MASK,
445 gtk_binding_entry_add_signal (binding_set,
446 GDK_Up, GDK_MOD1_MASK,
449 gtk_binding_entry_add_signal (binding_set,
450 GDK_KP_Up, GDK_MOD1_MASK,
454 gtk_binding_entry_add_signal (binding_set,
455 GDK_Home, GDK_MOD1_MASK,
458 gtk_binding_entry_add_signal (binding_set,
459 GDK_KP_Home, GDK_MOD1_MASK,
463 _gtk_file_chooser_install_properties (gobject_class);
465 gtk_settings_install_property (g_param_spec_string ("gtk-file-chooser-backend",
466 P_("Default file chooser backend"),
467 P_("Name of the GtkFileChooser backend to use by default"),
473 gtk_file_chooser_default_iface_init (GtkFileChooserIface *iface)
475 iface->select_path = gtk_file_chooser_default_select_path;
476 iface->unselect_path = gtk_file_chooser_default_unselect_path;
477 iface->select_all = gtk_file_chooser_default_select_all;
478 iface->unselect_all = gtk_file_chooser_default_unselect_all;
479 iface->get_paths = gtk_file_chooser_default_get_paths;
480 iface->get_preview_path = gtk_file_chooser_default_get_preview_path;
481 iface->get_file_system = gtk_file_chooser_default_get_file_system;
482 iface->set_current_folder = gtk_file_chooser_default_set_current_folder;
483 iface->get_current_folder = gtk_file_chooser_default_get_current_folder;
484 iface->set_current_name = gtk_file_chooser_default_set_current_name;
485 iface->add_filter = gtk_file_chooser_default_add_filter;
486 iface->remove_filter = gtk_file_chooser_default_remove_filter;
487 iface->list_filters = gtk_file_chooser_default_list_filters;
488 iface->add_shortcut_folder = gtk_file_chooser_default_add_shortcut_folder;
489 iface->remove_shortcut_folder = gtk_file_chooser_default_remove_shortcut_folder;
490 iface->list_shortcut_folders = gtk_file_chooser_default_list_shortcut_folders;
494 gtk_file_chooser_embed_default_iface_init (GtkFileChooserEmbedIface *iface)
496 iface->get_default_size = gtk_file_chooser_default_get_default_size;
497 iface->get_resizable_hints = gtk_file_chooser_default_get_resizable_hints;
498 iface->should_respond = gtk_file_chooser_default_should_respond;
501 gtk_file_chooser_default_init (GtkFileChooserDefault *impl)
503 impl->local_only = TRUE;
504 impl->preview_widget_active = TRUE;
505 impl->use_preview_label = TRUE;
506 impl->select_multiple = FALSE;
507 impl->show_hidden = FALSE;
509 gtk_widget_set_redraw_on_allocate (GTK_WIDGET (impl), TRUE);
510 gtk_box_set_spacing (GTK_BOX (impl), 12);
514 gtk_file_chooser_default_finalize (GObject *object)
516 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object);
519 g_signal_handler_disconnect (impl->file_system, impl->volumes_changed_id);
520 impl->volumes_changed_id = 0;
521 g_signal_handler_disconnect (impl->file_system, impl->bookmarks_changed_id);
522 impl->bookmarks_changed_id = 0;
523 g_object_unref (impl->file_system);
525 for (l = impl->filters; l; l = l->next)
527 GtkFileFilter *filter;
529 filter = GTK_FILE_FILTER (l->data);
530 g_object_unref (filter);
532 g_slist_free (impl->filters);
534 if (impl->current_filter)
535 g_object_unref (impl->current_filter);
537 if (impl->current_volume_path)
538 gtk_file_path_free (impl->current_volume_path);
540 if (impl->current_folder)
541 gtk_file_path_free (impl->current_folder);
543 if (impl->preview_path)
544 gtk_file_path_free (impl->preview_path);
546 /* Free all the Models we have */
547 if (impl->browse_files_model)
548 g_object_unref (impl->browse_files_model);
550 if (impl->shortcuts_model)
551 g_object_unref (impl->shortcuts_model);
553 if (impl->shortcuts_filter_model)
554 g_object_unref (impl->shortcuts_filter_model);
556 if (impl->sort_model)
557 g_object_unref (impl->sort_model);
559 g_free (impl->preview_display_name);
561 G_OBJECT_CLASS (parent_class)->finalize (object);
564 /* Shows an error dialog set as transient for the specified window */
566 error_message_with_parent (GtkWindow *parent,
571 dialog = gtk_message_dialog_new (parent,
572 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
577 gtk_dialog_run (GTK_DIALOG (dialog));
578 gtk_widget_destroy (dialog);
581 /* Shows an error dialog for the file chooser */
583 error_message (GtkFileChooserDefault *impl,
588 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (impl));
589 if (!GTK_WIDGET_TOPLEVEL (toplevel))
592 error_message_with_parent (toplevel ? GTK_WINDOW (toplevel) : NULL,
596 /* Shows a simple error dialog relative to a path. Frees the GError as well. */
598 error_dialog (GtkFileChooserDefault *impl,
600 const GtkFilePath *path,
605 text = g_strdup_printf (msg,
606 gtk_file_path_get_string (path),
608 error_message (impl, text);
610 g_error_free (error);
613 /* Displays an error message about not being able to get information for a file.
614 * Frees the GError as well.
617 error_getting_info_dialog (GtkFileChooserDefault *impl,
618 const GtkFilePath *path,
622 _("Could not retrieve information about %s:\n%s"),
626 /* Shows an error dialog about not being able to add a bookmark */
628 error_could_not_add_bookmark_dialog (GtkFileChooserDefault *impl,
629 const GtkFilePath *path,
633 _("Could not add a bookmark for %s:\n%s"),
637 /* Shows an error dialog about not being able to compose a filename */
639 error_building_filename_dialog (GtkFileChooserDefault *impl,
640 const GtkFilePath *base_path,
641 const char *file_part,
646 msg = g_strdup_printf (_("Could not build file name from '%s' and '%s':\n%s"),
647 gtk_file_path_get_string (base_path),
650 error_message (impl, msg);
652 g_error_free (error);
655 /* Shows an error dialog when we cannot switch to a folder */
657 error_changing_folder_dialog (GtkFileChooserDefault *impl,
658 const GtkFilePath *path,
662 _("Could not change the current folder to %s:\n%s"),
667 /* Changes folders, displaying an error dialog if this fails */
669 change_folder_and_display_error (GtkFileChooserDefault *impl,
670 const GtkFilePath *path)
676 result = _gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (impl), path, &error);
679 error_changing_folder_dialog (impl, path, error);
685 update_preview_widget_visibility (GtkFileChooserDefault *impl)
687 if (impl->use_preview_label)
689 if (!impl->preview_label)
691 impl->preview_label = gtk_label_new (impl->preview_display_name);
692 gtk_box_pack_start (GTK_BOX (impl->preview_box), impl->preview_label, FALSE, FALSE, 0);
693 gtk_box_reorder_child (GTK_BOX (impl->preview_box), impl->preview_label, 0);
694 gtk_widget_show (impl->preview_label);
699 if (impl->preview_label)
701 gtk_widget_destroy (impl->preview_label);
702 impl->preview_label = NULL;
706 if (impl->preview_widget_active && impl->preview_widget)
707 gtk_widget_show (impl->preview_box);
709 gtk_widget_hide (impl->preview_box);
711 g_signal_emit_by_name (impl, "default-size-changed");
715 set_preview_widget (GtkFileChooserDefault *impl,
716 GtkWidget *preview_widget)
718 if (preview_widget == impl->preview_widget)
721 if (impl->preview_widget)
722 gtk_container_remove (GTK_CONTAINER (impl->preview_box),
723 impl->preview_widget);
725 impl->preview_widget = preview_widget;
726 if (impl->preview_widget)
728 gtk_widget_show (impl->preview_widget);
729 gtk_box_pack_start (GTK_BOX (impl->preview_box), impl->preview_widget, TRUE, TRUE, 0);
730 gtk_box_reorder_child (GTK_BOX (impl->preview_box),
731 impl->preview_widget,
732 (impl->use_preview_label && impl->preview_label) ? 1 : 0);
735 update_preview_widget_visibility (impl);
738 /* Clears the selection in the shortcuts tree */
740 shortcuts_unselect_all (GtkFileChooserDefault *impl)
742 GtkTreeSelection *selection;
744 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
745 gtk_tree_selection_unselect_all (selection);
748 /* Convenience function to get the display name and icon info for a path */
750 get_file_info (GtkFileSystem *file_system, const GtkFilePath *path, GError **error)
752 GtkFilePath *parent_path;
753 GtkFileFolder *parent_folder;
756 if (!gtk_file_system_get_parent (file_system, path, &parent_path, error))
759 parent_folder = gtk_file_system_get_folder (file_system, parent_path,
760 GTK_FILE_INFO_DISPLAY_NAME
764 | GTK_FILE_INFO_IS_FOLDER,
766 gtk_file_path_free (parent_path);
771 info = gtk_file_folder_get_info (parent_folder, path, error);
772 g_object_unref (parent_folder);
777 /* Inserts a path in the shortcuts tree, making a copy of it; alternatively,
778 * inserts a volume. A position of -1 indicates the end of the tree.
781 shortcuts_insert_path (GtkFileChooserDefault *impl,
784 GtkFileSystemVolume *volume,
785 const GtkFilePath *path,
798 label_copy = gtk_file_system_volume_get_display_name (impl->file_system, volume);
799 pixbuf = gtk_file_system_volume_render_icon (impl->file_system,
809 info = get_file_info (impl->file_system, path, error);
813 data = gtk_file_path_copy (path);
816 label_copy = g_strdup (label);
818 label_copy = g_strdup (gtk_file_info_get_display_name (info));
820 pixbuf = gtk_file_system_render_icon (impl->file_system, path, GTK_WIDGET (impl), ICON_SIZE, NULL);
822 gtk_file_info_free (info);
826 gtk_list_store_append (impl->shortcuts_model, &iter);
828 gtk_list_store_insert (impl->shortcuts_model, &iter, pos);
830 gtk_list_store_set (impl->shortcuts_model, &iter,
831 SHORTCUTS_COL_PIXBUF, pixbuf,
832 SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
833 SHORTCUTS_COL_NAME, label_copy,
834 SHORTCUTS_COL_PATH, data,
835 SHORTCUTS_COL_REMOVABLE, removable,
841 g_object_unref (pixbuf);
846 /* Appends an item for the user's home directory to the shortcuts model */
848 shortcuts_append_home (GtkFileChooserDefault *impl)
851 GtkFilePath *home_path;
854 home = g_get_home_dir ();
855 home_path = gtk_file_system_filename_to_path (impl->file_system, home);
858 impl->has_home = shortcuts_insert_path (impl, -1, FALSE, NULL, home_path, _("Home"), FALSE, &error);
860 error_getting_info_dialog (impl, home_path, error);
862 gtk_file_path_free (home_path);
865 /* Appends the ~/Desktop directory to the shortcuts model */
867 shortcuts_append_desktop (GtkFileChooserDefault *impl)
872 name = g_build_filename (g_get_home_dir (), "Desktop", NULL);
873 path = gtk_file_system_filename_to_path (impl->file_system, name);
876 impl->has_desktop = shortcuts_insert_path (impl, -1, FALSE, NULL, path, _("Desktop"), FALSE, NULL);
877 /* We do not actually pop up an error dialog if there is no desktop directory
878 * because some people may really not want to have one.
881 gtk_file_path_free (path);
884 /* Appends a list of GtkFilePath to the shortcuts model; returns how many were inserted */
886 shortcuts_append_paths (GtkFileChooserDefault *impl,
892 /* As there is no separator now, we want to start there.
894 start_row = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR);
897 for (; paths; paths = paths->next)
905 /* NULL GError, but we don't really want to show error boxes here */
906 if (shortcuts_insert_path (impl, start_row + num_inserted, FALSE, NULL, path, NULL, TRUE, NULL))
913 /* Returns the index for the corresponding item in the shortcuts bar */
915 shortcuts_get_index (GtkFileChooserDefault *impl,
916 ShortcutsIndex where)
922 if (where == SHORTCUTS_HOME)
925 n += impl->has_home ? 1 : 0;
927 if (where == SHORTCUTS_DESKTOP)
930 n += impl->has_desktop ? 1 : 0;
932 if (where == SHORTCUTS_VOLUMES)
935 n += impl->num_volumes;
937 if (where == SHORTCUTS_SHORTCUTS)
940 n += impl->num_shortcuts;
942 if (where == SHORTCUTS_BOOKMARKS_SEPARATOR)
945 /* If there are no bookmarks there won't be a separator */
946 n += (impl->num_bookmarks > 0) ? 1 : 0;
948 if (where == SHORTCUTS_BOOKMARKS)
951 n += impl->num_bookmarks;
953 if (where == SHORTCUTS_CURRENT_FOLDER_SEPARATOR)
958 if (where == SHORTCUTS_CURRENT_FOLDER)
961 g_assert_not_reached ();
968 typedef void (* RemoveFunc) (GtkFileChooserDefault *impl, gpointer data);
970 /* Removes the specified number of rows from the shortcuts list */
972 shortcuts_remove_rows (GtkFileChooserDefault *impl,
975 RemoveFunc remove_fn)
979 path = gtk_tree_path_new_from_indices (start_row, -1);
981 for (; n_rows; n_rows--)
986 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path))
987 g_assert_not_reached ();
991 gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter, SHORTCUTS_COL_PATH, &data, -1);
992 (* remove_fn) (impl, data);
995 gtk_list_store_remove (impl->shortcuts_model, &iter);
998 gtk_tree_path_free (path);
1001 /* Used from shortcuts_remove_rows() in shortcuts_add_volumes() */
1003 volume_remove_cb (GtkFileChooserDefault *impl, gpointer data)
1005 GtkFileSystemVolume *volume;
1008 gtk_file_system_volume_free (impl->file_system, volume);
1011 /* Adds all the file system volumes to the shortcuts model */
1013 shortcuts_add_volumes (GtkFileChooserDefault *impl)
1019 start_row = shortcuts_get_index (impl, SHORTCUTS_VOLUMES);
1020 shortcuts_remove_rows (impl, start_row, impl->num_volumes, volume_remove_cb);
1021 impl->num_volumes = 0;
1023 list = gtk_file_system_list_volumes (impl->file_system);
1027 for (l = list; l; l = l->next)
1029 GtkFileSystemVolume *volume;
1032 shortcuts_insert_path (impl, start_row + n, TRUE, volume, NULL, NULL, FALSE, NULL);
1036 impl->num_volumes = n;
1037 g_slist_free (list);
1039 if (impl->shortcuts_filter_model)
1040 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
1043 /* Used from shortcuts_remove_rows() */
1045 remove_bookmark_cb (GtkFileChooserDefault *impl, gpointer data)
1050 gtk_file_path_free (path);
1053 /* Inserts a separator node in the shortcuts list */
1055 shortcuts_insert_separator (GtkFileChooserDefault *impl,
1056 ShortcutsIndex where)
1060 g_assert (where == SHORTCUTS_BOOKMARKS_SEPARATOR || where == SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
1062 gtk_list_store_insert (impl->shortcuts_model, &iter,
1063 shortcuts_get_index (impl, where));
1064 gtk_list_store_set (impl->shortcuts_model, &iter,
1065 SHORTCUTS_COL_PIXBUF, NULL,
1066 SHORTCUTS_COL_PIXBUF_VISIBLE, FALSE,
1067 SHORTCUTS_COL_NAME, NULL,
1068 SHORTCUTS_COL_PATH, NULL,
1072 /* Updates the list of bookmarks */
1074 shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
1078 if (impl->num_bookmarks > 0)
1080 shortcuts_remove_rows (impl,
1081 shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR),
1082 impl->num_bookmarks + 1,
1083 remove_bookmark_cb);
1087 bookmarks = gtk_file_system_list_bookmarks (impl->file_system);
1088 impl->num_bookmarks = shortcuts_append_paths (impl, bookmarks);
1089 gtk_file_paths_free (bookmarks);
1091 if (impl->num_bookmarks > 0)
1093 shortcuts_insert_separator (impl, SHORTCUTS_BOOKMARKS_SEPARATOR);
1095 if (impl->shortcuts_filter_model)
1096 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
1099 /* Appends a separator and a row to the shortcuts list for the current folder */
1101 shortcuts_add_current_folder (GtkFileChooserDefault *impl)
1106 g_assert (!impl->shortcuts_current_folder_active);
1110 pos = shortcut_find_position (impl, impl->current_folder);
1113 GtkFileSystemVolume *volume;
1114 GtkFilePath *base_path;
1118 shortcuts_insert_separator (impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
1122 pos = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER);
1124 volume = gtk_file_system_get_volume_for_path (impl->file_system, impl->current_folder);
1126 base_path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
1131 strcmp (gtk_file_path_get_string (base_path), gtk_file_path_get_string (impl->current_folder)) == 0)
1133 success = shortcuts_insert_path (impl, pos, TRUE, volume, NULL, NULL, FALSE, NULL);
1134 impl->shortcuts_current_folder_is_volume = TRUE;
1138 success = shortcuts_insert_path (impl, pos, FALSE, NULL, impl->current_folder, NULL, FALSE, NULL);
1139 impl->shortcuts_current_folder_is_volume = FALSE;
1143 gtk_file_system_volume_free (impl->file_system, volume);
1144 gtk_file_path_free (base_path);
1147 shortcuts_remove_rows (impl, pos - 1, 1, NULL); /* remove the separator */
1149 impl->shortcuts_current_folder_active = success;
1153 gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), pos);
1156 /* Used from shortcuts_remove_rows() in shortcuts_update_current_folder() */
1158 remove_current_folder_cb (GtkFileChooserDefault *impl,
1161 if (impl->shortcuts_current_folder_is_volume)
1162 gtk_file_system_volume_free (impl->file_system, data);
1164 gtk_file_path_free (data);
1167 /* Updates the current folder row in the shortcuts model */
1169 shortcuts_update_current_folder (GtkFileChooserDefault *impl)
1173 pos = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
1175 if (impl->shortcuts_current_folder_active)
1177 shortcuts_remove_rows (impl, pos, 2, remove_current_folder_cb);
1178 impl->shortcuts_current_folder_active = FALSE;
1181 shortcuts_add_current_folder (impl);
1184 /* Filter function used for the shortcuts filter model */
1186 shortcuts_filter_cb (GtkTreeModel *model,
1190 GtkFileChooserDefault *impl;
1194 impl = GTK_FILE_CHOOSER_DEFAULT (data);
1196 path = gtk_tree_model_get_path (model, iter);
1200 pos = *gtk_tree_path_get_indices (path);
1201 gtk_tree_path_free (path);
1203 return (pos < shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR));
1206 /* Creates the list model for shortcuts */
1208 shortcuts_model_create (GtkFileChooserDefault *impl)
1210 /* Keep this order in sync with the SHORCUTS_COL_* enum values */
1211 impl->shortcuts_model = gtk_list_store_new (SHORTCUTS_COL_NUM_COLUMNS,
1212 GDK_TYPE_PIXBUF, /* pixbuf */
1213 G_TYPE_STRING, /* name */
1214 G_TYPE_POINTER, /* path or volume */
1215 G_TYPE_BOOLEAN, /* removable */
1216 G_TYPE_BOOLEAN); /* pixbuf cell visibility */
1218 if (impl->file_system)
1220 shortcuts_append_home (impl);
1221 shortcuts_append_desktop (impl);
1222 shortcuts_add_volumes (impl);
1223 shortcuts_add_bookmarks (impl);
1226 impl->shortcuts_filter_model = gtk_tree_model_filter_new (GTK_TREE_MODEL (impl->shortcuts_model), NULL);
1227 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model),
1228 shortcuts_filter_cb,
1233 /* Callback used when the "New Folder" toolbar button is clicked */
1235 new_folder_button_clicked (GtkButton *button,
1236 GtkFileChooserDefault *impl)
1241 /* FIXME: this doesn't work for folder mode, just for file mode */
1243 _gtk_file_system_model_add_editable (impl->browse_files_model, &iter);
1245 path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->browse_files_model), &iter);
1246 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (impl->browse_files_tree_view),
1247 path, impl->list_name_column,
1250 g_object_set (impl->list_name_renderer, "editable", TRUE, NULL);
1251 gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view),
1253 impl->list_name_column,
1257 /* Callback used from the text cell renderer when the new folder is named */
1259 renderer_edited_cb (GtkCellRendererText *cell_renderer_text,
1261 const gchar *new_text,
1262 GtkFileChooserDefault *impl)
1265 GtkFilePath *file_path;
1267 _gtk_file_system_model_remove_editable (impl->browse_files_model);
1268 g_object_set (impl->list_name_renderer, "editable", FALSE, NULL);
1271 file_path = gtk_file_system_make_path (impl->file_system, impl->current_folder, new_text, &error);
1274 error_building_filename_dialog (impl, impl->current_folder, new_text, error);
1279 if (!gtk_file_system_create_folder (impl->file_system, file_path, &error))
1281 _("Could not create folder %s:\n%s"),
1284 gtk_file_path_free (file_path);
1286 /* FIXME: scroll to the new folder and select it */
1289 /* Callback used from the text cell renderer when the new folder edition gets
1293 renderer_editing_canceled_cb (GtkCellRendererText *cell_renderer_text,
1294 GtkFileChooserDefault *impl)
1296 _gtk_file_system_model_remove_editable (impl->browse_files_model);
1297 g_object_set (impl->list_name_renderer, "editable", FALSE, NULL);
1300 /* Creates the widgets for the filter combo box */
1302 filter_create (GtkFileChooserDefault *impl)
1304 impl->filter_combo = gtk_combo_box_new_text ();
1305 g_signal_connect (impl->filter_combo, "changed",
1306 G_CALLBACK (filter_combo_changed), impl);
1308 return impl->filter_combo;
1312 button_new (GtkFileChooserDefault *impl,
1314 const char *stock_id,
1324 button = gtk_button_new ();
1325 hbox = gtk_hbox_new (FALSE, 2);
1326 align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1328 gtk_container_add (GTK_CONTAINER (button), align);
1329 gtk_container_add (GTK_CONTAINER (align), hbox);
1330 widget = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
1332 gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
1334 widget = gtk_label_new_with_mnemonic (text);
1335 gtk_label_set_mnemonic_widget (GTK_LABEL (widget), GTK_WIDGET (button));
1336 gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
1338 gtk_widget_set_sensitive (button, sensitive);
1339 g_signal_connect (button, "clicked", callback, impl);
1341 gtk_widget_show_all (align);
1344 gtk_widget_show (button);
1349 /* Looks for a path among the shortcuts; returns its index or -1 if it doesn't exist */
1351 shortcut_find_position (GtkFileChooserDefault *impl,
1352 const GtkFilePath *path)
1356 int bookmarks_separator_idx;
1357 int current_folder_separator_idx;
1360 if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
1363 bookmarks_separator_idx = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR);
1364 current_folder_separator_idx = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
1365 volumes_idx = shortcuts_get_index (impl, SHORTCUTS_VOLUMES);
1369 for (i = 0; i < current_folder_separator_idx; i++)
1373 if (i == bookmarks_separator_idx)
1376 gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter, SHORTCUTS_COL_PATH, &data, -1);
1378 if (i >= volumes_idx && i < volumes_idx + impl->num_volumes)
1380 GtkFileSystemVolume *volume;
1381 GtkFilePath *base_path;
1385 base_path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
1387 exists = strcmp (gtk_file_path_get_string (path),
1388 gtk_file_path_get_string (base_path)) == 0;
1396 GtkFilePath *model_path;
1400 if (model_path && gtk_file_path_compare (model_path, path) == 0)
1405 gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
1411 /* Tries to add a bookmark from a path name */
1413 shortcuts_add_bookmark_from_path (GtkFileChooserDefault *impl,
1414 const GtkFilePath *path)
1419 if (shortcut_find_position (impl, path) != -1)
1423 info = get_file_info (impl->file_system, path, &error);
1426 error_getting_info_dialog (impl, path, error);
1427 else if (!gtk_file_info_get_is_folder (info))
1431 msg = g_strdup_printf (_("Could not add bookmark for %s because it is not a folder."),
1432 gtk_file_path_get_string (path));
1433 error_message (impl, msg);
1439 if (!gtk_file_system_insert_bookmark (impl->file_system, path, -1, &error))
1440 error_could_not_add_bookmark_dialog (impl, path, error);
1445 add_bookmark_foreach_cb (GtkTreeModel *model,
1450 GtkFileChooserDefault *impl;
1451 GtkFileSystemModel *fs_model;
1452 GtkTreeIter child_iter;
1453 const GtkFilePath *file_path;
1455 impl = (GtkFileChooserDefault *) data;
1457 fs_model = impl->browse_files_model;
1458 gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, iter);
1460 file_path = _gtk_file_system_model_get_path (GTK_FILE_SYSTEM_MODEL (fs_model), &child_iter);
1461 shortcuts_add_bookmark_from_path (impl, file_path);
1464 /* Callback used when the "Add bookmark" button is clicked */
1466 add_bookmark_button_clicked_cb (GtkButton *button,
1467 GtkFileChooserDefault *impl)
1469 GtkTreeSelection *selection;
1471 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
1473 if (gtk_tree_selection_count_selected_rows (selection) == 0)
1474 shortcuts_add_bookmark_from_path (impl, impl->current_folder);
1476 gtk_tree_selection_selected_foreach (selection,
1477 add_bookmark_foreach_cb,
1481 /* Callback used when the "Remove bookmark" button is clicked */
1483 remove_bookmark_button_clicked_cb (GtkButton *button,
1484 GtkFileChooserDefault *impl)
1486 GtkTreeSelection *selection;
1492 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
1494 if (gtk_tree_selection_get_selected (selection, NULL, &iter))
1496 gtk_tree_model_get (impl->shortcuts_filter_model, &iter,
1497 SHORTCUTS_COL_PATH, &path,
1498 SHORTCUTS_COL_REMOVABLE, &removable, -1);
1501 g_assert_not_reached ();
1506 if (!gtk_file_system_remove_bookmark (impl->file_system, path, &error))
1508 _("Could not remove bookmark for %s:\n%s"),
1514 struct selection_check_closure {
1515 GtkFileChooserDefault *impl;
1518 gboolean all_folders;
1521 /* Used from gtk_tree_selection_selected_foreach() */
1523 selection_check_foreach_cb (GtkTreeModel *model,
1528 struct selection_check_closure *closure;
1529 GtkTreeIter child_iter;
1530 const GtkFileInfo *info;
1534 closure->empty = FALSE;
1536 gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
1538 info = _gtk_file_system_model_get_info (closure->impl->browse_files_model, &child_iter);
1539 is_folder = gtk_file_info_get_is_folder (info);
1541 closure->all_folders &= is_folder;
1542 closure->all_files &= !is_folder;
1545 /* Checks whether the selected items in the file list are all files or all folders */
1547 selection_check (GtkFileChooserDefault *impl,
1549 gboolean *all_files,
1550 gboolean *all_folders)
1552 struct selection_check_closure closure;
1553 GtkTreeSelection *selection;
1555 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
1557 if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
1558 || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
1560 if (gtk_tree_selection_count_selected_rows (selection) == 0)
1561 closure.empty = TRUE;
1564 closure.empty = FALSE;
1565 closure.all_files = FALSE;
1566 closure.all_folders = TRUE;
1571 g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
1572 || impl->action == GTK_FILE_CHOOSER_ACTION_SAVE);
1574 closure.impl = impl;
1575 closure.empty = TRUE;
1576 closure.all_files = TRUE;
1577 closure.all_folders = TRUE;
1579 gtk_tree_selection_selected_foreach (selection,
1580 selection_check_foreach_cb,
1584 g_assert (closure.empty || !(closure.all_files && closure.all_folders));
1587 *empty = closure.empty;
1590 *all_files = closure.all_files;
1593 *all_folders = closure.all_folders;
1596 /* Sensitize the "add bookmark" button if all the selected items are folders, or
1597 * if there are no selected items *and* the current folder is not in the
1598 * bookmarks list. De-sensitize the button otherwise.
1601 bookmarks_check_add_sensitivity (GtkFileChooserDefault *impl)
1603 GtkTreeSelection *selection;
1606 /* Check selection */
1608 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
1610 if (gtk_tree_selection_count_selected_rows (selection) == 0)
1611 active = (shortcut_find_position (impl, impl->current_folder) == -1);
1614 gboolean all_folders;
1616 selection_check (impl, NULL, NULL, &all_folders);
1617 active = (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
1618 impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER ||
1622 gtk_widget_set_sensitive (impl->browse_shortcuts_add_button, active);
1625 /* Sets the sensitivity of the "remove bookmark" button depending on whether a
1626 * bookmark row is selected in the shortcuts tree.
1629 bookmarks_check_remove_sensitivity (GtkFileChooserDefault *impl)
1631 GtkTreeSelection *selection;
1633 gboolean removable = FALSE;
1635 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
1637 if (gtk_tree_selection_get_selected (selection, NULL, &iter))
1638 gtk_tree_model_get (impl->shortcuts_filter_model, &iter,
1639 SHORTCUTS_COL_REMOVABLE, &removable,
1642 gtk_widget_set_sensitive (impl->browse_shortcuts_remove_button, removable);
1645 /* Converts raw selection data from text/uri-list to a list of strings */
1647 split_uris (const char *data)
1650 const char *p, *start;
1656 for (p = start; *p != 0; p++)
1657 if (*p == '\r' && *(p + 1) == '\n')
1661 name = g_strndup (start, p - start);
1662 uris = g_slist_prepend (uris, name);
1668 uris = g_slist_reverse (uris);
1672 /* Callback used when we get the drag data for the bookmarks list. We add the
1673 * received URIs as bookmarks if they are folders.
1676 shortcuts_drag_data_received_cb (GtkWidget *widget,
1677 GdkDragContext *context,
1680 GtkSelectionData *selection_data,
1685 GtkFileChooserDefault *impl;
1688 impl = GTK_FILE_CHOOSER_DEFAULT (data);
1690 uris = split_uris (selection_data->data);
1692 for (l = uris; l; l = l->next)
1698 path = gtk_file_system_uri_to_path (impl->file_system, uri);
1702 shortcuts_add_bookmark_from_path (impl, path);
1703 gtk_file_path_free (path);
1709 msg = g_strdup_printf (_("Could not add a bookmark for %s because it is an invalid path name."),
1711 error_message (impl, msg);
1718 g_slist_free (uris);
1721 /* Callback used when the selection in the shortcuts tree changes */
1723 shortcuts_selection_changed_cb (GtkTreeSelection *selection,
1724 GtkFileChooserDefault *impl)
1726 bookmarks_check_remove_sensitivity (impl);
1729 /* Creates the widgets for the shortcuts and bookmarks tree */
1731 shortcuts_list_create (GtkFileChooserDefault *impl)
1733 GtkTreeSelection *selection;
1734 GtkTreeViewColumn *column;
1735 GtkCellRenderer *renderer;
1737 /* Scrolled window */
1739 impl->browse_shortcuts_swin = gtk_scrolled_window_new (NULL, NULL);
1740 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (impl->browse_shortcuts_swin),
1741 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1742 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (impl->browse_shortcuts_swin),
1744 gtk_widget_show (impl->browse_shortcuts_swin);
1748 impl->browse_shortcuts_tree_view = gtk_tree_view_new ();
1749 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), FALSE);
1751 gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), impl->shortcuts_filter_model);
1753 gtk_drag_dest_set (impl->browse_shortcuts_tree_view,
1754 GTK_DEST_DEFAULT_ALL,
1756 num_shortcuts_targets,
1759 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
1760 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1761 gtk_tree_selection_set_select_function (selection,
1762 shortcuts_select_func,
1765 g_signal_connect (selection, "changed",
1766 G_CALLBACK (shortcuts_selection_changed_cb), impl);
1768 g_signal_connect (impl->browse_shortcuts_tree_view, "row-activated",
1769 G_CALLBACK (shortcuts_row_activated_cb), impl);
1771 g_signal_connect (impl->browse_shortcuts_tree_view, "drag-data-received",
1772 G_CALLBACK (shortcuts_drag_data_received_cb), impl);
1774 gtk_container_add (GTK_CONTAINER (impl->browse_shortcuts_swin), impl->browse_shortcuts_tree_view);
1775 gtk_widget_show (impl->browse_shortcuts_tree_view);
1779 column = gtk_tree_view_column_new ();
1780 gtk_tree_view_column_set_title (column, _("Folder"));
1782 renderer = gtk_cell_renderer_pixbuf_new ();
1783 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1784 gtk_tree_view_column_set_attributes (column, renderer,
1785 "pixbuf", SHORTCUTS_COL_PIXBUF,
1786 "visible", SHORTCUTS_COL_PIXBUF_VISIBLE,
1789 renderer = _gtk_cell_renderer_sep_text_new ();
1790 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1791 gtk_tree_view_column_set_attributes (column, renderer,
1792 "text", SHORTCUTS_COL_NAME,
1795 gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), column);
1797 return impl->browse_shortcuts_swin;
1800 /* Creates the widgets for the shortcuts/bookmarks pane */
1802 shortcuts_pane_create (GtkFileChooserDefault *impl,
1803 GtkSizeGroup *size_group)
1809 vbox = gtk_vbox_new (FALSE, 6);
1810 gtk_widget_show (vbox);
1812 /* Shortcuts tree */
1814 widget = shortcuts_list_create (impl);
1815 gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
1817 /* Box for buttons */
1819 hbox = gtk_hbox_new (TRUE, 6);
1820 gtk_size_group_add_widget (size_group, hbox);
1821 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1822 gtk_widget_show (hbox);
1824 /* Add bookmark button */
1826 impl->browse_shortcuts_add_button = button_new (impl,
1831 G_CALLBACK (add_bookmark_button_clicked_cb));
1832 gtk_box_pack_start (GTK_BOX (hbox), impl->browse_shortcuts_add_button, TRUE, TRUE, 0);
1834 /* Remove bookmark button */
1836 impl->browse_shortcuts_remove_button = button_new (impl,
1841 G_CALLBACK (remove_bookmark_button_clicked_cb));
1842 gtk_box_pack_start (GTK_BOX (hbox), impl->browse_shortcuts_remove_button, TRUE, TRUE, 0);
1848 trap_activate_cb (GtkWidget *widget,
1852 GtkFileChooserDefault *impl;
1854 impl = (GtkFileChooserDefault *) data;
1856 if (event->keyval == GDK_Return
1857 || event->keyval == GDK_ISO_Enter
1858 || event->keyval == GDK_KP_Enter
1859 || event->keyval == GDK_space)
1861 GtkWidget *toplevel;
1863 toplevel = gtk_widget_get_toplevel (widget);
1864 if (GTK_IS_WINDOW (toplevel))
1868 window = GTK_WINDOW (toplevel);
1871 widget != window->default_widget &&
1872 !(widget == window->focus_widget &&
1873 (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget))))
1874 gtk_window_activate_default (window);
1882 /* Creates the widgets for the file list */
1884 create_file_list (GtkFileChooserDefault *impl)
1887 GtkTreeSelection *selection;
1888 GtkTreeViewColumn *column;
1889 GtkCellRenderer *renderer;
1891 /* Scrolled window */
1893 swin = gtk_scrolled_window_new (NULL, NULL);
1894 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
1895 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1896 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
1899 /* Tree/list view */
1901 impl->browse_files_tree_view = gtk_tree_view_new ();
1902 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (impl->browse_files_tree_view), TRUE);
1903 gtk_container_add (GTK_CONTAINER (swin), impl->browse_files_tree_view);
1904 g_signal_connect (impl->browse_files_tree_view, "row-activated",
1905 G_CALLBACK (list_row_activated), impl);
1906 g_signal_connect (impl->browse_files_tree_view, "key-press-event",
1907 G_CALLBACK (trap_activate_cb), impl);
1909 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
1910 gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (impl->browse_files_tree_view),
1913 num_shortcuts_targets,
1916 g_signal_connect (selection, "changed",
1917 G_CALLBACK (list_selection_changed), impl);
1919 /* Filename column */
1921 impl->list_name_column = gtk_tree_view_column_new ();
1922 gtk_tree_view_column_set_expand (impl->list_name_column, TRUE);
1923 gtk_tree_view_column_set_title (impl->list_name_column, _("Name"));
1924 gtk_tree_view_column_set_sort_column_id (impl->list_name_column, FILE_LIST_COL_NAME);
1926 renderer = gtk_cell_renderer_pixbuf_new ();
1927 gtk_tree_view_column_pack_start (impl->list_name_column, renderer, FALSE);
1928 gtk_tree_view_column_set_cell_data_func (impl->list_name_column, renderer,
1929 list_icon_data_func, impl, NULL);
1931 impl->list_name_renderer = gtk_cell_renderer_text_new ();
1932 g_signal_connect (impl->list_name_renderer, "edited",
1933 G_CALLBACK (renderer_edited_cb), impl);
1934 g_signal_connect (impl->list_name_renderer, "editing-canceled",
1935 G_CALLBACK (renderer_editing_canceled_cb), impl);
1936 gtk_tree_view_column_pack_start (impl->list_name_column, impl->list_name_renderer, TRUE);
1937 gtk_tree_view_column_set_cell_data_func (impl->list_name_column, impl->list_name_renderer,
1938 list_name_data_func, impl, NULL);
1940 gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), impl->list_name_column);
1944 column = gtk_tree_view_column_new ();
1945 gtk_tree_view_column_set_title (column, _("Size"));
1947 renderer = gtk_cell_renderer_text_new ();
1948 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1949 gtk_tree_view_column_set_cell_data_func (column, renderer,
1950 list_size_data_func, impl, NULL);
1951 gtk_tree_view_column_set_sort_column_id (column, FILE_LIST_COL_SIZE);
1952 gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), column);
1954 /* Modification time column */
1956 column = gtk_tree_view_column_new ();
1957 gtk_tree_view_column_set_title (column, _("Modified"));
1959 renderer = gtk_cell_renderer_text_new ();
1960 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1961 gtk_tree_view_column_set_cell_data_func (column, renderer,
1962 list_mtime_data_func, impl, NULL);
1963 gtk_tree_view_column_set_sort_column_id (column, FILE_LIST_COL_MTIME);
1964 gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), column);
1965 gtk_widget_show_all (swin);
1971 create_filename_entry_and_filter_combo (GtkFileChooserDefault *impl)
1976 hbox = gtk_hbox_new (FALSE, 12);
1977 gtk_widget_show (hbox);
1981 widget = filter_create (impl);
1982 gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
1987 /* Creates the widgets for the files/folders pane */
1989 file_pane_create (GtkFileChooserDefault *impl,
1990 GtkSizeGroup *size_group)
1996 vbox = gtk_vbox_new (FALSE, 6);
1997 gtk_widget_show (vbox);
1999 /* The path bar and 'Create Folder' button */
2000 hbox = gtk_hbox_new (FALSE, 12);
2001 gtk_widget_show (hbox);
2002 impl->browse_path_bar = g_object_new (GTK_TYPE_PATH_BAR, NULL);
2003 g_signal_connect (impl->browse_path_bar, "path-clicked", G_CALLBACK (path_bar_clicked), impl);
2004 gtk_widget_show_all (impl->browse_path_bar);
2005 gtk_box_pack_start (GTK_BOX (hbox), impl->browse_path_bar, TRUE, TRUE, 0);
2008 impl->browse_new_folder_button = gtk_button_new_with_mnemonic (_("Create _Folder"));
2009 g_signal_connect (impl->browse_new_folder_button, "clicked",
2010 G_CALLBACK (new_folder_button_clicked), impl);
2011 gtk_box_pack_end (GTK_BOX (hbox), impl->browse_new_folder_button, FALSE, FALSE, 0);
2012 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
2014 /* Box for lists and preview */
2016 hbox = gtk_hbox_new (FALSE, PREVIEW_HBOX_SPACING);
2017 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
2018 gtk_widget_show (hbox);
2022 widget = create_file_list (impl);
2023 gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
2027 impl->preview_box = gtk_vbox_new (FALSE, 12);
2028 gtk_box_pack_start (GTK_BOX (hbox), impl->preview_box, FALSE, FALSE, 0);
2029 /* Don't show preview box initially */
2031 /* Filename entry and filter combo */
2032 hbox = gtk_hbox_new (FALSE, 0);
2033 gtk_size_group_add_widget (size_group, hbox);
2034 widget = create_filename_entry_and_filter_combo (impl);
2035 gtk_box_pack_end (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
2036 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
2037 gtk_widget_show (hbox);
2041 /* Callback used when the "Browse for more folders" expander is toggled */
2043 expander_changed_cb (GtkExpander *expander,
2045 GtkFileChooserDefault *impl)
2047 update_appearance (impl);
2050 /* Callback used when the selection changes in the save folder combo box */
2052 save_folder_combo_changed_cb (GtkComboBox *combo,
2053 GtkFileChooserDefault *impl)
2057 if (impl->changing_folder)
2060 active = gtk_combo_box_get_active (combo);
2064 shortcuts_activate_item (impl, active);
2067 /* Creates the combo box with the save folders */
2069 save_folder_combo_create (GtkFileChooserDefault *impl)
2072 GtkCellRenderer *cell;
2074 combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (impl->shortcuts_model));
2075 gtk_widget_show (combo);
2077 cell = gtk_cell_renderer_pixbuf_new ();
2078 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, FALSE);
2079 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
2080 "pixbuf", SHORTCUTS_COL_PIXBUF,
2081 "visible", SHORTCUTS_COL_PIXBUF_VISIBLE,
2084 cell = _gtk_cell_renderer_sep_text_new ();
2085 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
2086 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
2087 "text", SHORTCUTS_COL_NAME,
2090 g_signal_connect (combo, "changed",
2091 G_CALLBACK (save_folder_combo_changed_cb), impl);
2096 /* Creates the widgets specific to Save mode */
2098 save_widgets_create (GtkFileChooserDefault *impl)
2103 GtkWidget *alignment;
2105 vbox = gtk_vbox_new (FALSE, 12);
2107 table = gtk_table_new (2, 2, FALSE);
2108 gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
2109 gtk_widget_show (table);
2110 gtk_table_set_row_spacings (GTK_TABLE (table), 12);
2111 gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2115 widget = gtk_label_new_with_mnemonic (_("_Name:"));
2116 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
2117 gtk_table_attach (GTK_TABLE (table), widget,
2121 gtk_widget_show (widget);
2123 impl->save_file_name_entry = gtk_entry_new ();
2124 gtk_entry_set_width_chars (GTK_ENTRY (impl->save_file_name_entry), 45);
2125 gtk_entry_set_activates_default (GTK_ENTRY (impl->save_file_name_entry), TRUE);
2126 gtk_table_attach (GTK_TABLE (table), impl->save_file_name_entry,
2128 GTK_EXPAND | GTK_FILL, 0,
2130 gtk_widget_show (impl->save_file_name_entry);
2131 gtk_label_set_mnemonic_widget (GTK_LABEL (widget), impl->save_file_name_entry);
2134 impl->save_folder_label = gtk_label_new_with_mnemonic (_("Save in _Folder:"));
2135 gtk_misc_set_alignment (GTK_MISC (impl->save_folder_label), 0.0, 0.5);
2136 gtk_table_attach (GTK_TABLE (table), impl->save_folder_label,
2140 gtk_widget_show (impl->save_folder_label);
2142 impl->save_folder_combo = save_folder_combo_create (impl);
2143 gtk_table_attach (GTK_TABLE (table), impl->save_folder_combo,
2145 GTK_EXPAND | GTK_FILL, GTK_FILL,
2147 gtk_label_set_mnemonic_widget (GTK_LABEL (impl->save_folder_label), impl->save_folder_combo);
2150 impl->save_extra_align = gtk_alignment_new (0.0, 0.5, 1.0, 1.0);
2151 gtk_box_pack_start (GTK_BOX (vbox), impl->save_extra_align, FALSE, FALSE, 0);
2154 alignment = gtk_alignment_new (0.0, 0.5, 1.0, 1.0);
2155 gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
2157 impl->save_expander = gtk_expander_new_with_mnemonic (_("_Browse for other folders"));
2158 gtk_container_add (GTK_CONTAINER (alignment), impl->save_expander);
2159 g_signal_connect (impl->save_expander, "notify::expanded",
2160 G_CALLBACK (expander_changed_cb),
2162 gtk_widget_show_all (alignment);
2167 /* Creates the main hpaned with the widgets shared by Open and Save mode */
2169 browse_widgets_create (GtkFileChooserDefault *impl)
2174 GtkSizeGroup *size_group;
2176 /* size group is used by the [+][-] buttons and the filter combo */
2177 size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
2178 vbox = gtk_vbox_new (FALSE, 12);
2181 hpaned = gtk_hpaned_new ();
2182 gtk_widget_show (hpaned);
2183 gtk_paned_set_position (GTK_PANED (hpaned), 200); /* FIXME: this sucks */
2184 gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0);
2186 widget = shortcuts_pane_create (impl, size_group);
2187 gtk_paned_pack1 (GTK_PANED (hpaned), widget, FALSE, FALSE);
2188 widget = file_pane_create (impl, size_group);
2189 gtk_paned_pack2 (GTK_PANED (hpaned), widget, TRUE, FALSE);
2191 /* Alignment to hold custom widget */
2192 impl->browse_extra_align = gtk_alignment_new (0.0, .5, 1.0, 1.0);
2193 gtk_box_pack_start (GTK_BOX (vbox), impl->browse_extra_align, FALSE, FALSE, 0);
2199 gtk_file_chooser_default_constructor (GType type,
2200 guint n_construct_properties,
2201 GObjectConstructParam *construct_params)
2203 GtkFileChooserDefault *impl;
2206 object = parent_class->constructor (type,
2207 n_construct_properties,
2209 impl = GTK_FILE_CHOOSER_DEFAULT (object);
2211 g_assert (impl->file_system);
2213 gtk_widget_push_composite_child ();
2215 /* Shortcuts model */
2217 shortcuts_model_create (impl);
2219 /* Widgets for Save mode */
2220 impl->save_widgets = save_widgets_create (impl);
2221 gtk_box_pack_start (GTK_BOX (impl), impl->save_widgets, FALSE, FALSE, 0);
2223 /* The browse widgets */
2224 impl->browse_widgets = browse_widgets_create (impl);
2225 gtk_box_pack_start (GTK_BOX (impl), impl->browse_widgets, TRUE, TRUE, 0);
2227 gtk_widget_pop_composite_child ();
2228 update_appearance (impl);
2233 /* Sets the extra_widget by packing it in the appropriate place */
2235 set_extra_widget (GtkFileChooserDefault *impl,
2236 GtkWidget *extra_widget)
2240 g_object_ref (extra_widget);
2241 /* FIXME: is this right ? */
2242 gtk_widget_show (extra_widget);
2245 if (impl->extra_widget)
2246 g_object_unref (impl->extra_widget);
2248 impl->extra_widget = extra_widget;
2252 volumes_changed_cb (GtkFileSystem *file_system,
2253 GtkFileChooserDefault *impl)
2255 shortcuts_add_volumes (impl);
2258 /* Callback used when the set of bookmarks changes in the file system */
2260 bookmarks_changed_cb (GtkFileSystem *file_system,
2261 GtkFileChooserDefault *impl)
2263 shortcuts_add_bookmarks (impl);
2265 bookmarks_check_add_sensitivity (impl);
2266 bookmarks_check_remove_sensitivity (impl);
2269 /* Sets the file chooser to multiple selection mode */
2271 set_select_multiple (GtkFileChooserDefault *impl,
2272 gboolean select_multiple,
2273 gboolean property_notify)
2275 GtkTreeSelection *selection;
2276 GtkSelectionMode mode;
2278 if (select_multiple == impl->select_multiple)
2281 mode = select_multiple ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_BROWSE;
2283 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
2284 gtk_tree_selection_set_mode (selection, mode);
2286 impl->select_multiple = select_multiple;
2287 g_object_notify (G_OBJECT (impl), "select-multiple");
2289 /* FIXME #132255: See note in check_preview_change() */
2290 check_preview_change (impl);
2294 set_file_system_backend (GtkFileChooserDefault *impl,
2295 const char *backend)
2297 if (impl->file_system)
2299 g_signal_handler_disconnect (impl->file_system, impl->volumes_changed_id);
2300 impl->volumes_changed_id = 0;
2301 g_signal_handler_disconnect (impl->file_system, impl->bookmarks_changed_id);
2302 impl->bookmarks_changed_id = 0;
2303 g_object_unref (impl->file_system);
2306 impl->file_system = NULL;
2308 impl->file_system = _gtk_file_system_create (backend);
2311 GtkSettings *settings = gtk_settings_get_default ();
2312 gchar *default_backend = NULL;
2314 g_object_get (settings, "gtk-file-chooser-backend", &default_backend, NULL);
2315 if (default_backend)
2317 impl->file_system = _gtk_file_system_create (default_backend);
2318 g_free (default_backend);
2322 if (!impl->file_system)
2324 #if defined (G_OS_UNIX)
2325 impl->file_system = gtk_file_system_unix_new ();
2326 #elif defined (G_OS_WIN32)
2327 impl->file_system = gtk_file_system_win32_new ();
2329 #error "No default filesystem implementation on the platform"
2333 if (impl->file_system)
2335 impl->volumes_changed_id = g_signal_connect (impl->file_system, "volumes-changed",
2336 G_CALLBACK (volumes_changed_cb),
2338 impl->bookmarks_changed_id = g_signal_connect (impl->file_system, "bookmarks-changed",
2339 G_CALLBACK (bookmarks_changed_cb),
2344 /* This function is basically a do_all function.
2346 * It sets the visibility on all the widgets based on the current state, and
2347 * moves the custom_widget if needed.
2350 update_appearance (GtkFileChooserDefault *impl)
2354 if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
2355 impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
2357 gtk_widget_show (impl->save_widgets);
2359 if (gtk_expander_get_expanded (GTK_EXPANDER (impl->save_expander)))
2361 gtk_widget_set_sensitive (impl->save_folder_label, FALSE);
2362 gtk_widget_set_sensitive (impl->save_folder_combo, FALSE);
2363 gtk_widget_show (impl->browse_widgets);
2367 gtk_widget_set_sensitive (impl->save_folder_label, TRUE);
2368 gtk_widget_set_sensitive (impl->save_folder_combo, TRUE);
2369 gtk_widget_hide (impl->browse_widgets);
2372 gtk_widget_show (impl->browse_new_folder_button);
2374 if (impl->select_multiple)
2376 g_warning ("Save mode cannot be set in conjunction with multiple selection mode. "
2377 "Re-setting to single selection mode.");
2378 set_select_multiple (impl, FALSE, TRUE);
2381 else if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
2382 impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
2384 gtk_widget_hide (impl->save_widgets);
2385 gtk_widget_show (impl->browse_widgets);
2388 if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
2389 impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
2391 if (impl->browse_files_model)
2392 _gtk_file_system_model_set_show_files (impl->browse_files_model, FALSE);
2396 if (impl->browse_files_model)
2397 _gtk_file_system_model_set_show_files (impl->browse_files_model, TRUE);
2400 if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
2401 gtk_widget_hide (impl->browse_new_folder_button);
2403 gtk_widget_show (impl->browse_new_folder_button);
2405 if (impl->extra_widget)
2408 GtkWidget *unused_align;
2410 if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
2412 align = impl->save_extra_align;
2413 unused_align = impl->browse_extra_align;
2417 align = impl->browse_extra_align;
2418 unused_align = impl->save_extra_align;
2421 /* We own a ref on extra_widget, so it's safe to do this */
2422 child = GTK_BIN (unused_align)->child;
2424 gtk_container_remove (GTK_CONTAINER (unused_align), child);
2426 child = GTK_BIN (align)->child;
2427 if (child && child != impl->extra_widget)
2429 gtk_container_remove (GTK_CONTAINER (align), child);
2430 gtk_container_add (GTK_CONTAINER (align), impl->extra_widget);
2432 else if (child == NULL)
2434 gtk_container_add (GTK_CONTAINER (align), impl->extra_widget);
2437 gtk_widget_show (align);
2438 gtk_widget_hide (unused_align);
2442 child = GTK_BIN (impl->browse_extra_align)->child;
2444 gtk_container_remove (GTK_CONTAINER (impl->browse_extra_align), child);
2446 child = GTK_BIN (impl->save_extra_align)->child;
2448 gtk_container_remove (GTK_CONTAINER (impl->save_extra_align), child);
2450 gtk_widget_hide (impl->save_extra_align);
2451 gtk_widget_hide (impl->browse_extra_align);
2454 g_signal_emit_by_name (impl, "default-size-changed");
2458 gtk_file_chooser_default_set_property (GObject *object,
2460 const GValue *value,
2464 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object);
2468 case GTK_FILE_CHOOSER_PROP_ACTION:
2470 GtkFileChooserAction action = g_value_get_enum (value);
2472 if (action != impl->action)
2474 if (action == GTK_FILE_CHOOSER_ACTION_SAVE && impl->select_multiple)
2476 g_warning ("Multiple selection mode is not allowed in Save mode");
2477 set_select_multiple (impl, FALSE, TRUE);
2479 impl->action = action;
2480 update_appearance (impl);
2484 case GTK_FILE_CHOOSER_PROP_FILE_SYSTEM_BACKEND:
2485 set_file_system_backend (impl, g_value_get_string (value));
2487 case GTK_FILE_CHOOSER_PROP_FILTER:
2488 set_current_filter (impl, g_value_get_object (value));
2490 case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
2491 impl->local_only = g_value_get_boolean (value);
2493 case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
2494 set_preview_widget (impl, g_value_get_object (value));
2496 case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE:
2497 impl->preview_widget_active = g_value_get_boolean (value);
2498 update_preview_widget_visibility (impl);
2500 case GTK_FILE_CHOOSER_PROP_USE_PREVIEW_LABEL:
2501 impl->use_preview_label = g_value_get_boolean (value);
2502 update_preview_widget_visibility (impl);
2504 case GTK_FILE_CHOOSER_PROP_EXTRA_WIDGET:
2505 set_extra_widget (impl, g_value_get_object (value));
2506 update_appearance (impl);
2508 case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
2510 gboolean select_multiple = g_value_get_boolean (value);
2511 if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE && select_multiple)
2513 g_warning ("Multiple selection mode is not allowed in Save mode");
2517 set_select_multiple (impl, select_multiple, FALSE);
2520 case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
2522 gboolean show_hidden = g_value_get_boolean (value);
2523 if (show_hidden != impl->show_hidden)
2525 impl->show_hidden = show_hidden;
2526 _gtk_file_system_model_set_show_hidden (GTK_FILE_SYSTEM_MODEL (impl->browse_files_model),
2532 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2538 gtk_file_chooser_default_get_property (GObject *object,
2543 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object);
2547 case GTK_FILE_CHOOSER_PROP_ACTION:
2548 g_value_set_enum (value, impl->action);
2550 case GTK_FILE_CHOOSER_PROP_FILTER:
2551 g_value_set_object (value, impl->current_filter);
2553 case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
2554 g_value_set_boolean (value, impl->local_only);
2556 case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
2557 g_value_set_object (value, impl->preview_widget);
2559 case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE:
2560 g_value_set_boolean (value, impl->preview_widget_active);
2562 case GTK_FILE_CHOOSER_PROP_USE_PREVIEW_LABEL:
2563 g_value_set_boolean (value, impl->use_preview_label);
2565 case GTK_FILE_CHOOSER_PROP_EXTRA_WIDGET:
2566 g_value_set_object (value, impl->extra_widget);
2568 case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
2569 g_value_set_boolean (value, impl->select_multiple);
2571 case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
2572 g_value_set_boolean (value, impl->show_hidden);
2575 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2582 gtk_file_chooser_default_dispose (GObject *object)
2584 GtkFileChooserDefault *impl = (GtkFileChooserDefault *) object;
2586 if (impl->extra_widget)
2588 g_object_unref (impl->extra_widget);
2589 impl->extra_widget = NULL;
2591 G_OBJECT_CLASS (parent_class)->dispose (object);
2594 /* We override show-all since we have internal widgets that
2595 * shouldn't be shown when you call show_all(), like the filter
2599 gtk_file_chooser_default_show_all (GtkWidget *widget)
2601 GtkFileChooserDefault *impl = (GtkFileChooserDefault *) widget;
2603 gtk_widget_show (widget);
2605 if (impl->extra_widget)
2606 gtk_widget_show_all (impl->extra_widget);
2610 gtk_file_chooser_default_style_set (GtkWidget *widget,
2611 GtkStyle *previous_style)
2613 if (GTK_WIDGET_CLASS (parent_class)->style_set)
2614 GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);
2616 g_signal_emit_by_name (widget, "default-size-changed");
2620 gtk_file_chooser_default_screen_changed (GtkWidget *widget,
2621 GdkScreen *previous_screen)
2623 if (GTK_WIDGET_CLASS (parent_class)->screen_changed)
2624 GTK_WIDGET_CLASS (parent_class)->screen_changed (widget, previous_screen);
2626 g_signal_emit_by_name (widget, "default-size-changed");
2630 list_model_filter_func (GtkFileSystemModel *model,
2632 const GtkFileInfo *file_info,
2635 GtkFileChooserDefault *impl = user_data;
2636 GtkFileFilterInfo filter_info;
2637 GtkFileFilterFlags needed;
2640 if (!impl->current_filter)
2643 if (gtk_file_info_get_is_folder (file_info))
2646 filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE;
2648 needed = gtk_file_filter_get_needed (impl->current_filter);
2650 filter_info.display_name = gtk_file_info_get_display_name (file_info);
2651 filter_info.mime_type = gtk_file_info_get_mime_type (file_info);
2653 if (needed & GTK_FILE_FILTER_FILENAME)
2655 filter_info.filename = gtk_file_system_path_to_filename (impl->file_system, path);
2656 if (filter_info.filename)
2657 filter_info.contains |= GTK_FILE_FILTER_FILENAME;
2660 filter_info.filename = NULL;
2662 if (needed & GTK_FILE_FILTER_URI)
2664 filter_info.uri = gtk_file_system_path_to_uri (impl->file_system, path);
2665 if (filter_info.uri)
2666 filter_info.contains |= GTK_FILE_FILTER_URI;
2669 filter_info.uri = NULL;
2671 result = gtk_file_filter_filter (impl->current_filter, &filter_info);
2673 if (filter_info.filename)
2674 g_free ((gchar *)filter_info.filename);
2675 if (filter_info.uri)
2676 g_free ((gchar *)filter_info.uri);
2682 install_list_model_filter (GtkFileChooserDefault *impl)
2684 if (impl->current_filter)
2685 _gtk_file_system_model_set_filter (impl->browse_files_model,
2686 list_model_filter_func,
2690 #define COMPARE_DIRECTORIES \
2691 GtkFileChooserDefault *impl = user_data; \
2692 const GtkFileInfo *info_a = _gtk_file_system_model_get_info (impl->browse_files_model, a); \
2693 const GtkFileInfo *info_b = _gtk_file_system_model_get_info (impl->browse_files_model, b); \
2694 gboolean dir_a, dir_b; \
2697 dir_a = gtk_file_info_get_is_folder (info_a); \
2699 return impl->list_sort_ascending ? -1 : 1; \
2702 dir_b = gtk_file_info_get_is_folder (info_b); \
2704 return impl->list_sort_ascending ? 1 : -1; \
2706 if (dir_a != dir_b) \
2707 return impl->list_sort_ascending ? (dir_a ? -1 : 1) : (dir_a ? 1 : -1) /* Directories *always* go first */
2709 /* Sort callback for the filename column */
2711 name_sort_func (GtkTreeModel *model,
2716 COMPARE_DIRECTORIES;
2718 return strcmp (gtk_file_info_get_display_key (info_a), gtk_file_info_get_display_key (info_b));
2721 /* Sort callback for the size column */
2723 size_sort_func (GtkTreeModel *model,
2728 COMPARE_DIRECTORIES;
2731 gint64 size_a = gtk_file_info_get_size (info_a);
2732 gint64 size_b = gtk_file_info_get_size (info_b);
2734 return size_a > size_b ? -1 : (size_a == size_b ? 0 : 1);
2738 /* Sort callback for the mtime column */
2740 mtime_sort_func (GtkTreeModel *model,
2745 COMPARE_DIRECTORIES;
2748 GtkFileTime ta = gtk_file_info_get_modification_time (info_a);
2749 GtkFileTime tb = gtk_file_info_get_modification_time (info_b);
2751 return ta > tb ? -1 : (ta == tb ? 0 : 1);
2755 /* Callback used when the sort column changes. We cache the sort order for use
2756 * in name_sort_func().
2759 list_sort_column_changed_cb (GtkTreeSortable *sortable,
2760 GtkFileChooserDefault *impl)
2762 GtkSortType sort_type;
2764 if (gtk_tree_sortable_get_sort_column_id (sortable, NULL, &sort_type))
2765 impl->list_sort_ascending = (sort_type == GTK_SORT_ASCENDING);
2768 /* Gets rid of the old list model and creates a new one for the current folder */
2770 set_list_model (GtkFileChooserDefault *impl)
2772 if (impl->browse_files_model)
2774 g_object_unref (impl->browse_files_model);
2775 g_object_unref (impl->sort_model);
2778 impl->browse_files_model = _gtk_file_system_model_new (impl->file_system,
2779 impl->current_folder, 0,
2781 _gtk_file_system_model_set_show_hidden (impl->browse_files_model, impl->show_hidden);
2782 switch (impl->action)
2784 case GTK_FILE_CHOOSER_ACTION_OPEN:
2785 case GTK_FILE_CHOOSER_ACTION_SAVE:
2786 _gtk_file_system_model_set_show_files (impl->browse_files_model, TRUE);
2788 case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
2789 case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER:
2790 _gtk_file_system_model_set_show_files (impl->browse_files_model, FALSE);
2793 g_assert_not_reached ();
2795 install_list_model_filter (impl);
2797 impl->sort_model = (GtkTreeModelSort *)gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (impl->browse_files_model));
2798 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_NAME, name_sort_func, impl, NULL);
2799 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_SIZE, size_sort_func, impl, NULL);
2800 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_MTIME, mtime_sort_func, impl, NULL);
2801 gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (impl->sort_model), NULL, NULL, NULL);
2802 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_NAME, GTK_SORT_ASCENDING);
2803 impl->list_sort_ascending = TRUE;
2805 g_signal_connect (impl->sort_model, "sort-column-changed",
2806 G_CALLBACK (list_sort_column_changed_cb), impl);
2808 gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
2809 GTK_TREE_MODEL (impl->sort_model));
2810 gtk_tree_view_columns_autosize (GTK_TREE_VIEW (impl->browse_files_tree_view));
2811 gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->browse_files_tree_view),
2812 GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME);
2816 update_chooser_entry (GtkFileChooserDefault *impl)
2818 GtkTreeSelection *selection;
2819 const GtkFileInfo *info;
2821 GtkTreeIter child_iter;
2823 if (impl->action != GTK_FILE_CHOOSER_ACTION_SAVE)
2826 g_assert (!impl->select_multiple);
2827 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
2829 if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
2832 gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
2836 info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
2838 if (!gtk_file_info_get_is_folder (info))
2839 gtk_entry_set_text (GTK_ENTRY (impl->save_file_name_entry),
2840 gtk_file_info_get_display_name (info));
2844 gtk_file_chooser_default_set_current_folder (GtkFileChooser *chooser,
2845 const GtkFilePath *path,
2848 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
2852 if (!_gtk_path_bar_set_path (GTK_PATH_BAR (impl->browse_path_bar), path, impl->file_system, &err))
2854 g_propagate_error (error, err);
2858 if (impl->current_folder != path)
2860 if (impl->current_folder)
2861 gtk_file_path_free (impl->current_folder);
2863 impl->current_folder = gtk_file_path_copy (path);
2866 /* Update the widgets that may trigger a folder chnage themselves */
2868 if (!impl->changing_folder)
2870 impl->changing_folder = TRUE;
2872 shortcuts_update_current_folder (impl);
2874 impl->changing_folder = FALSE;
2877 /* Create a new list model */
2878 set_list_model (impl);
2880 /* Refresh controls */
2882 shortcuts_unselect_all (impl);
2884 g_signal_emit_by_name (impl, "current-folder-changed", 0);
2886 check_preview_change (impl);
2887 bookmarks_check_add_sensitivity (impl);
2889 g_signal_emit_by_name (impl, "selection-changed", 0);
2894 static GtkFilePath *
2895 gtk_file_chooser_default_get_current_folder (GtkFileChooser *chooser)
2897 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
2899 return gtk_file_path_copy (impl->current_folder);
2903 gtk_file_chooser_default_set_current_name (GtkFileChooser *chooser,
2906 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
2908 g_return_if_fail (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE);
2910 gtk_entry_set_text (GTK_ENTRY (impl->save_file_name_entry), name);
2914 select_func (GtkFileSystemModel *model,
2919 GtkFileChooserDefault *impl = user_data;
2920 GtkTreeView *tree_view = GTK_TREE_VIEW (impl->browse_files_tree_view);
2921 GtkTreePath *sorted_path;
2923 sorted_path = gtk_tree_model_sort_convert_child_path_to_path (impl->sort_model, path);
2924 gtk_tree_view_set_cursor (tree_view, sorted_path, NULL, FALSE);
2925 gtk_tree_path_free (sorted_path);
2929 gtk_file_chooser_default_select_path (GtkFileChooser *chooser,
2930 const GtkFilePath *path,
2933 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
2934 GtkFilePath *parent_path;
2936 if (!gtk_file_system_get_parent (impl->file_system, path, &parent_path, error))
2940 return _gtk_file_chooser_set_current_folder_path (chooser, path, error);
2945 result = _gtk_file_chooser_set_current_folder_path (chooser, parent_path, error);
2946 gtk_file_path_free (parent_path);
2947 _gtk_file_system_model_path_do (impl->browse_files_model, path,
2953 g_assert_not_reached ();
2957 unselect_func (GtkFileSystemModel *model,
2962 GtkFileChooserDefault *impl = user_data;
2963 GtkTreeView *tree_view = GTK_TREE_VIEW (impl->browse_files_tree_view);
2964 GtkTreePath *sorted_path;
2966 sorted_path = gtk_tree_model_sort_convert_child_path_to_path (impl->sort_model,
2968 gtk_tree_selection_unselect_path (gtk_tree_view_get_selection (tree_view),
2970 gtk_tree_path_free (sorted_path);
2974 gtk_file_chooser_default_unselect_path (GtkFileChooser *chooser,
2975 const GtkFilePath *path)
2977 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
2979 _gtk_file_system_model_path_do (impl->browse_files_model, path,
2980 unselect_func, impl);
2984 gtk_file_chooser_default_select_all (GtkFileChooser *chooser)
2986 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
2987 if (impl->select_multiple)
2989 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
2990 gtk_tree_selection_select_all (selection);
2995 gtk_file_chooser_default_unselect_all (GtkFileChooser *chooser)
2997 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
2998 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
3000 gtk_tree_selection_unselect_all (selection);
3003 /* Checks whether the filename entry for the Save modes contains a valid filename */
3004 static GtkFilePath *
3005 check_save_entry (GtkFileChooserDefault *impl,
3009 const char *filename;
3013 g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
3014 || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
3016 filename = gtk_entry_get_text (GTK_ENTRY (impl->save_file_name_entry));
3018 if (!filename || filename[0] == '\0')
3028 path = gtk_file_system_make_path (impl->file_system, impl->current_folder, filename, &error);
3032 error_building_filename_dialog (impl, impl->current_folder, filename, error);
3041 struct get_paths_closure {
3042 GtkFileChooserDefault *impl;
3044 GtkFilePath *path_from_entry;
3048 get_paths_foreach (GtkTreeModel *model,
3053 struct get_paths_closure *info;
3054 const GtkFilePath *file_path;
3055 GtkFileSystemModel *fs_model;
3056 GtkTreeIter sel_iter;
3059 fs_model = info->impl->browse_files_model;
3060 gtk_tree_model_sort_convert_iter_to_child_iter (info->impl->sort_model, &sel_iter, iter);
3062 file_path = _gtk_file_system_model_get_path (GTK_FILE_SYSTEM_MODEL (fs_model), &sel_iter);
3064 if (!info->path_from_entry
3065 || gtk_file_path_compare (info->path_from_entry, file_path) != 0)
3066 info->result = g_slist_prepend (info->result, gtk_file_path_copy (file_path));
3070 gtk_file_chooser_default_get_paths (GtkFileChooser *chooser)
3072 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
3073 struct get_paths_closure info;
3077 info.path_from_entry = NULL;
3079 if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
3080 || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
3082 gboolean is_valid, is_empty;
3084 info.path_from_entry = check_save_entry (impl, &is_valid, &is_empty);
3085 if (!is_valid && !is_empty)
3089 if (!info.path_from_entry || impl->select_multiple)
3091 GtkTreeSelection *selection;
3093 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
3094 gtk_tree_selection_selected_foreach (selection, get_paths_foreach, &info);
3097 if (info.path_from_entry)
3098 info.result = g_slist_prepend (info.result, info.path_from_entry);
3100 /* If there's no folder selected, and we're in SELECT_FOLDER mode, then we
3101 * fall back to the current directory */
3102 if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER &&
3103 info.result == NULL)
3105 info.result = g_slist_prepend (info.result, gtk_file_path_copy (impl->current_folder));
3108 return g_slist_reverse (info.result);
3111 static GtkFilePath *
3112 gtk_file_chooser_default_get_preview_path (GtkFileChooser *chooser)
3114 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
3116 if (impl->preview_path)
3117 return gtk_file_path_copy (impl->preview_path);
3122 static GtkFileSystem *
3123 gtk_file_chooser_default_get_file_system (GtkFileChooser *chooser)
3125 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
3127 return impl->file_system;
3130 /* Shows or hides the filter widgets */
3132 toolbar_show_filters (GtkFileChooserDefault *impl,
3136 gtk_widget_show (impl->filter_combo);
3138 gtk_widget_hide (impl->filter_combo);
3142 gtk_file_chooser_default_add_filter (GtkFileChooser *chooser,
3143 GtkFileFilter *filter)
3145 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
3148 if (g_slist_find (impl->filters, filter))
3150 g_warning ("gtk_file_chooser_add_filter() called on filter already in list\n");
3154 g_object_ref (filter);
3155 gtk_object_sink (GTK_OBJECT (filter));
3156 impl->filters = g_slist_append (impl->filters, filter);
3158 name = gtk_file_filter_get_name (filter);
3160 name = "Untitled filter"; /* Place-holder, doesn't need to be marked for translation */
3162 gtk_combo_box_append_text (GTK_COMBO_BOX (impl->filter_combo), name);
3164 if (!g_slist_find (impl->filters, impl->current_filter))
3165 set_current_filter (impl, filter);
3167 toolbar_show_filters (impl, TRUE);
3171 gtk_file_chooser_default_remove_filter (GtkFileChooser *chooser,
3172 GtkFileFilter *filter)
3174 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
3175 GtkTreeModel *model;
3179 filter_index = g_slist_index (impl->filters, filter);
3181 if (filter_index < 0)
3183 g_warning ("gtk_file_chooser_remove_filter() called on filter not in list\n");
3187 impl->filters = g_slist_remove (impl->filters, filter);
3189 if (filter == impl->current_filter)
3192 set_current_filter (impl, impl->filters->data);
3194 set_current_filter (impl, NULL);
3197 /* Remove row from the combo box */
3198 model = gtk_combo_box_get_model (GTK_COMBO_BOX (impl->filter_combo));
3199 gtk_tree_model_iter_nth_child (model, &iter, NULL, filter_index);
3200 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
3202 g_object_unref (filter);
3205 toolbar_show_filters (impl, FALSE);
3209 gtk_file_chooser_default_list_filters (GtkFileChooser *chooser)
3211 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
3213 return g_slist_copy (impl->filters);
3216 /* Returns the position in the shortcuts tree where the nth specified shortcut would appear */
3218 shortcuts_get_pos_for_shortcut_folder (GtkFileChooserDefault *impl,
3221 return pos + shortcuts_get_index (impl, SHORTCUTS_SHORTCUTS);
3225 gtk_file_chooser_default_add_shortcut_folder (GtkFileChooser *chooser,
3226 const GtkFilePath *path,
3229 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
3233 pos = shortcuts_get_pos_for_shortcut_folder (impl, impl->num_shortcuts);
3235 result = shortcuts_insert_path (impl, pos, FALSE, NULL, path, NULL, FALSE, error);
3238 impl->num_shortcuts++;
3240 if (impl->shortcuts_filter_model)
3241 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
3247 gtk_file_chooser_default_remove_shortcut_folder (GtkFileChooser *chooser,
3248 const GtkFilePath *path,
3251 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
3256 if (impl->num_shortcuts == 0)
3259 pos = shortcuts_get_pos_for_shortcut_folder (impl, 0);
3260 if (!gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (impl->shortcuts_model), &iter, NULL, pos))
3261 g_assert_not_reached ();
3263 for (i = 0; i < impl->num_shortcuts; i++)
3265 GtkFilePath *shortcut;
3267 gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter, SHORTCUTS_COL_PATH, &shortcut, -1);
3268 g_assert (shortcut != NULL);
3270 if (gtk_file_path_compare (shortcut, path) == 0)
3272 /* The other columns are freed by the GtkTreeStore */
3273 gtk_file_path_free (shortcut);
3274 gtk_list_store_remove (impl->shortcuts_model, &iter);
3275 impl->num_shortcuts--;
3279 if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
3280 g_assert_not_reached ();
3286 GTK_FILE_CHOOSER_ERROR,
3287 GTK_FILE_CHOOSER_ERROR_NONEXISTENT,
3288 _("shortcut %s does not exist"),
3289 gtk_file_path_get_string (path));
3295 gtk_file_chooser_default_list_shortcut_folders (GtkFileChooser *chooser)
3297 GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
3303 if (impl->num_shortcuts == 0)
3306 pos = shortcuts_get_pos_for_shortcut_folder (impl, 0);
3307 if (!gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (impl->shortcuts_model), &iter, NULL, pos))
3308 g_assert_not_reached ();
3312 for (i = 0; i < impl->num_shortcuts; i++)
3314 GtkFilePath *shortcut;
3316 gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter, SHORTCUTS_COL_PATH, &shortcut, -1);
3317 g_assert (shortcut != NULL);
3319 list = g_slist_prepend (list, gtk_file_path_copy (shortcut));
3321 if (i != impl->num_shortcuts - 1)
3323 if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
3324 g_assert_not_reached ();
3328 return g_slist_reverse (list);
3331 /* Guesses a size based upon font sizes */
3333 find_good_size_from_style (GtkWidget *widget,
3337 GtkFileChooserDefault *impl;
3338 gint default_width, default_height;
3341 GtkRequisition preview_req;
3343 g_assert (widget->style != NULL);
3344 impl = GTK_FILE_CHOOSER_DEFAULT (widget);
3346 font_size = pango_font_description_get_size (widget->style->font_desc);
3347 font_size = PANGO_PIXELS (font_size);
3349 default_width = font_size * NUM_CHARS;
3350 default_height = font_size * NUM_LINES;
3352 /* Use at least the requisition size not including the preview widget */
3353 gtk_widget_size_request (widget, &req);
3355 if (impl->preview_widget_active && impl->preview_widget)
3356 gtk_widget_size_request (impl->preview_box, &preview_req);
3358 preview_req.width = 0;
3360 default_width = MAX (default_width, (req.width - (preview_req.width + PREVIEW_HBOX_SPACING)));
3361 default_height = MAX (default_height, req.height);
3363 *width = default_width;
3364 *height = default_height;
3368 gtk_file_chooser_default_get_default_size (GtkFileChooserEmbed *chooser_embed,
3369 gint *default_width,
3370 gint *default_height)
3372 GtkFileChooserDefault *impl;
3374 impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
3376 find_good_size_from_style (GTK_WIDGET (chooser_embed), default_width, default_height);
3378 if (impl->preview_widget_active && impl->preview_widget)
3379 *default_width += impl->preview_box->requisition.width + PREVIEW_HBOX_SPACING;
3383 gtk_file_chooser_default_get_resizable_hints (GtkFileChooserEmbed *chooser_embed,
3384 gboolean *resize_horizontally,
3385 gboolean *resize_vertically)
3387 GtkFileChooserDefault *impl;
3389 g_return_if_fail (resize_horizontally != NULL);
3390 g_return_if_fail (resize_vertically != NULL);
3392 impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
3394 *resize_horizontally = TRUE;
3395 *resize_vertically = TRUE;
3397 if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
3398 impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
3400 if (! gtk_expander_get_expanded (GTK_EXPANDER (impl->save_expander)))
3402 *resize_horizontally = FALSE;
3403 *resize_vertically = FALSE;
3408 struct switch_folder_closure {
3409 GtkFileChooserDefault *impl;
3410 const GtkFilePath *path;
3414 /* Used from gtk_tree_selection_selected_foreach() in switch_to_selected_folder() */
3416 switch_folder_foreach_cb (GtkTreeModel *model,
3421 struct switch_folder_closure *closure;
3422 GtkTreeIter child_iter;
3426 gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
3428 closure->path = _gtk_file_system_model_get_path (closure->impl->browse_files_model, &child_iter);
3429 closure->num_selected++;
3432 /* Changes to the selected folder in the list view */
3434 switch_to_selected_folder (GtkFileChooserDefault *impl)
3436 GtkTreeSelection *selection;
3437 struct switch_folder_closure closure;
3439 g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
3440 || impl->action == GTK_FILE_CHOOSER_ACTION_SAVE);
3442 /* We do this with foreach() rather than get_selected() as we may be in
3443 * multiple selection mode
3446 closure.impl = impl;
3447 closure.path = NULL;
3448 closure.num_selected = 0;
3450 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
3451 gtk_tree_selection_selected_foreach (selection, switch_folder_foreach_cb, &closure);
3453 g_assert (closure.path && closure.num_selected == 1);
3455 change_folder_and_display_error (impl, closure.path);
3458 /* Implementation for GtkFileChooserEmbed::should_respond() */
3460 gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
3462 GtkFileChooserDefault *impl;
3463 GtkTreeSelection *selection;
3466 impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
3468 /* First, check the save entry. If it has a valid name, we are done */
3470 if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
3471 || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
3474 gboolean is_valid, is_empty;
3476 path = check_save_entry (impl, &is_valid, &is_empty);
3480 gtk_file_path_free (path);
3487 /* Second, do we have an empty selection */
3488 if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
3489 || impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
3491 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
3492 num_selected = gtk_tree_selection_count_selected_rows (selection);
3493 if (num_selected == 0)
3497 /* Third, should we return file names or folder names? */
3499 if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
3500 || impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
3502 gboolean all_files, all_folders;
3504 selection_check (impl, NULL, &all_files, &all_folders);
3506 if (num_selected == 1)
3510 switch_to_selected_folder (impl);
3519 else if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
3520 || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
3521 /* There can be no files selected in folder mode since we don't show them,
3526 g_assert_not_reached ();
3531 set_current_filter (GtkFileChooserDefault *impl,
3532 GtkFileFilter *filter)
3534 if (impl->current_filter != filter)
3538 /* If we have filters, new filter must be one of them
3540 filter_index = g_slist_index (impl->filters, filter);
3541 if (impl->filters && filter_index < 0)
3544 if (impl->current_filter)
3545 g_object_unref (impl->current_filter);
3546 impl->current_filter = filter;
3547 if (impl->current_filter)
3549 g_object_ref (impl->current_filter);
3550 gtk_object_sink (GTK_OBJECT (filter));
3554 gtk_combo_box_set_active (GTK_COMBO_BOX (impl->filter_combo),
3557 install_list_model_filter (impl);
3559 g_object_notify (G_OBJECT (impl), "filter");
3564 filter_combo_changed (GtkComboBox *combo_box,
3565 GtkFileChooserDefault *impl)
3567 gint new_index = gtk_combo_box_get_active (combo_box);
3568 GtkFileFilter *new_filter = g_slist_nth_data (impl->filters, new_index);
3570 set_current_filter (impl, new_filter);
3574 check_preview_change (GtkFileChooserDefault *impl)
3576 const GtkFilePath *new_path = NULL;
3577 const GtkFileInfo *new_info = NULL;
3579 /* FIXME #132255: Fixing preview for multiple selection involves getting the
3580 * full selection and diffing to find out what the most recently selected file
3581 * is; there is logic in GtkFileSelection that probably can be
3584 if (impl->sort_model && !impl->select_multiple)
3586 GtkTreeSelection *selection;
3589 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
3590 if (gtk_tree_selection_get_selected (selection, NULL, &iter))
3592 GtkTreeIter child_iter;
3594 gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
3595 &child_iter, &iter);
3597 new_path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
3598 new_info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
3602 if (new_path != impl->preview_path &&
3603 !(new_path && impl->preview_path &&
3604 gtk_file_path_compare (new_path, impl->preview_path) == 0))
3606 if (impl->preview_path)
3608 gtk_file_path_free (impl->preview_path);
3609 g_free (impl->preview_display_name);
3614 impl->preview_path = gtk_file_path_copy (new_path);
3615 impl->preview_display_name = g_strdup (gtk_file_info_get_display_name (new_info));
3619 impl->preview_path = NULL;
3620 impl->preview_display_name = NULL;
3623 if (impl->use_preview_label && impl->preview_label)
3624 gtk_label_set_text (GTK_LABEL (impl->preview_label), impl->preview_display_name);
3626 g_signal_emit_by_name (impl, "update-preview");
3630 /* Activates a volume by mounting it if necessary and then switching to its
3634 shortcuts_activate_volume (GtkFileChooserDefault *impl,
3635 GtkFileSystemVolume *volume)
3639 if (!gtk_file_system_volume_get_is_mounted (impl->file_system, volume))
3644 if (!gtk_file_system_volume_mount (impl->file_system, volume, &error))
3648 msg = g_strdup_printf ("Could not mount %s:\n%s",
3649 gtk_file_system_volume_get_display_name (impl->file_system, volume),
3651 error_message (impl, msg);
3653 g_error_free (error);
3659 path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
3660 change_folder_and_display_error (impl, path);
3661 gtk_file_path_free (path);
3664 /* Opens the folder or volume at the specified index in the shortcuts list */
3666 shortcuts_activate_item (GtkFileChooserDefault *impl,
3675 if (item_num == shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR)
3676 || item_num == shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR))
3679 path = gtk_tree_path_new_from_indices (item_num, -1);
3680 result = gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path);
3681 gtk_tree_path_free (path);
3686 gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter, SHORTCUTS_COL_PATH, &data, -1);
3688 start_row = shortcuts_get_index (impl, SHORTCUTS_VOLUMES);
3689 if ((item_num >= start_row && item_num < start_row + impl->num_volumes)
3690 || (item_num == shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER) && impl->shortcuts_current_folder_is_volume))
3692 GtkFileSystemVolume *volume;
3695 shortcuts_activate_volume (impl, volume);
3699 const GtkFilePath *file_path;
3702 change_folder_and_display_error (impl, file_path);
3706 /* Callback used when a row in the shortcuts list is activated */
3708 shortcuts_row_activated_cb (GtkTreeView *tree_view,
3710 GtkTreeViewColumn *column,
3711 GtkFileChooserDefault *impl)
3715 GtkTreeIter child_iter;
3716 GtkTreePath *child_path;
3718 if (!gtk_tree_model_get_iter (impl->shortcuts_filter_model, &iter, path))
3721 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model),
3724 child_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &child_iter);
3728 selected = *gtk_tree_path_get_indices (child_path);
3729 gtk_tree_path_free (child_path);
3731 shortcuts_activate_item (impl, selected);
3735 shortcuts_select_func (GtkTreeSelection *selection,
3736 GtkTreeModel *model,
3738 gboolean path_currently_selected,
3741 GtkFileChooserDefault *impl = data;
3743 return (*gtk_tree_path_get_indices (path) != shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR));
3747 list_selection_changed (GtkTreeSelection *selection,
3748 GtkFileChooserDefault *impl)
3750 /* See if we are in the new folder editable row for Save mode */
3751 if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
3753 GtkTreeSelection *selection;
3754 GtkTreeIter iter, child_iter;
3755 const GtkFileInfo *info;
3757 g_assert (!impl->select_multiple);
3758 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
3759 if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
3762 gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
3766 info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
3768 return; /* We are on the editable row for New Folder */
3771 update_chooser_entry (impl);
3772 check_preview_change (impl);
3773 bookmarks_check_add_sensitivity (impl);
3775 g_signal_emit_by_name (impl, "selection-changed", 0);
3778 /* Callback used when a row in the file list is activated */
3780 list_row_activated (GtkTreeView *tree_view,
3782 GtkTreeViewColumn *column,
3783 GtkFileChooserDefault *impl)
3785 GtkTreeIter iter, child_iter;
3786 const GtkFileInfo *info;
3788 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, path))
3791 gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
3793 info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
3795 if (gtk_file_info_get_is_folder (info))
3797 const GtkFilePath *file_path;
3799 file_path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
3800 change_folder_and_display_error (impl, file_path);
3805 g_signal_emit_by_name (impl, "file-activated");
3809 path_bar_clicked (GtkPathBar *path_bar,
3810 GtkFilePath *file_path,
3811 GtkFileChooserDefault *impl)
3813 change_folder_and_display_error (impl, file_path);
3816 static const GtkFileInfo *
3817 get_list_file_info (GtkFileChooserDefault *impl,
3820 GtkTreeIter child_iter;
3822 gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
3826 return _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
3830 list_icon_data_func (GtkTreeViewColumn *tree_column,
3831 GtkCellRenderer *cell,
3832 GtkTreeModel *tree_model,
3836 GtkFileChooserDefault *impl = data;
3837 GtkTreeIter child_iter;
3838 const GtkFilePath *path;
3841 gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
3844 path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
3848 /* FIXME: NULL GError */
3849 pixbuf = gtk_file_system_render_icon (impl->file_system, path, GTK_WIDGET (impl), ICON_SIZE, NULL);
3855 g_object_unref (pixbuf);
3859 list_name_data_func (GtkTreeViewColumn *tree_column,
3860 GtkCellRenderer *cell,
3861 GtkTreeModel *tree_model,
3865 GtkFileChooserDefault *impl = data;
3866 const GtkFileInfo *info = get_list_file_info (impl, iter);
3871 "text", _("Type name of new folder"),
3877 "text", gtk_file_info_get_display_name (info),
3883 list_size_data_func (GtkTreeViewColumn *tree_column,
3884 GtkCellRenderer *cell,
3885 GtkTreeModel *tree_model,
3889 GtkFileChooserDefault *impl = data;
3890 const GtkFileInfo *info = get_list_file_info (impl, iter);
3894 if (!info || gtk_file_info_get_is_folder (info))
3897 size = gtk_file_info_get_size (info);
3899 if (size < (gint64)1024)
3900 str = g_strdup_printf (ngettext ("%d byte", "%d bytes", (gint)size), (gint)size);
3901 else if (size < (gint64)1024*1024)
3902 str = g_strdup_printf (_("%.1f K"), size / (1024.));
3903 else if (size < (gint64)1024*1024*1024)
3904 str = g_strdup_printf (_("%.1f M"), size / (1024.*1024.));
3906 str = g_strdup_printf (_("%.1f G"), size / (1024.*1024.*1024.));
3916 /* Tree column data callback for the file list; fetches the mtime of a file */
3918 list_mtime_data_func (GtkTreeViewColumn *tree_column,
3919 GtkCellRenderer *cell,
3920 GtkTreeModel *tree_model,
3924 GtkFileChooserDefault *impl;
3925 const GtkFileInfo *info;
3926 GtkFileTime time_mtime, time_now;
3933 info = get_list_file_info (impl, iter);
3942 time_mtime = gtk_file_info_get_modification_time (info);
3943 g_date_set_time (&mtime, (GTime) time_mtime);
3945 time_now = (GTime ) time (NULL);
3946 g_date_set_time (&now, (GTime) time_now);
3948 days_diff = g_date_get_julian (&now) - g_date_get_julian (&mtime);
3951 strcpy (buf, _("Today"));
3952 else if (days_diff == 1)
3953 strcpy (buf, _("Yesterday"));
3958 if (days_diff > 1 && days_diff < 7)
3959 format = "%A"; /* Days from last week */
3961 /* FIXME: Get the right format for the locale */
3962 format = _("%d/%b/%Y"); /* Any other date */
3964 if (g_date_strftime (buf, sizeof (buf), format, &mtime) == 0)
3965 strcpy (buf, _("Unknown"));
3974 _gtk_file_chooser_default_new (const char *file_system)
3976 return g_object_new (GTK_TYPE_FILE_CHOOSER_DEFAULT,
3977 "file-system-backend", file_system,
3982 location_entry_create (GtkFileChooserDefault *impl)
3986 entry = _gtk_file_chooser_entry_new ();
3987 /* Pick a good width for the entry */
3988 gtk_entry_set_width_chars (GTK_ENTRY (entry), 25);
3989 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
3990 _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (entry), impl->file_system);
3991 _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (entry), impl->current_folder);
3993 return GTK_WIDGET (entry);
3997 update_from_entry (GtkFileChooserDefault *impl,
3999 GtkFileChooserEntry *chooser_entry)
4001 const GtkFilePath *folder_path;
4002 const char *file_part;
4004 folder_path = _gtk_file_chooser_entry_get_current_folder (chooser_entry);
4005 file_part = _gtk_file_chooser_entry_get_file_part (chooser_entry);
4007 if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN && !folder_path)
4009 error_message_with_parent (parent,
4010 _("Cannot change to the folder you specified as it is an invalid path."));
4014 if (file_part[0] == '\0')
4016 change_folder_and_display_error (impl, folder_path);
4021 GtkFileFolder *folder = NULL;
4022 GtkFilePath *subfolder_path = NULL;
4023 GtkFileInfo *info = NULL;
4026 /* If the file part is non-empty, we need to figure out if it refers to a
4027 * folder within folder. We could optimize the case here where the folder
4028 * is already loaded for one of our tree models.
4032 folder = gtk_file_system_get_folder (impl->file_system, folder_path, GTK_FILE_INFO_IS_FOLDER, &error);
4036 error_getting_info_dialog (impl, folder_path, error);
4041 subfolder_path = gtk_file_system_make_path (impl->file_system, folder_path, file_part, &error);
4043 if (!subfolder_path)
4047 msg = g_strdup_printf (_("Could not build file name from '%s' and '%s':\n%s"),
4048 gtk_file_path_get_string (folder_path),
4051 error_message (impl, msg);
4053 g_object_unref (folder);
4058 info = gtk_file_folder_get_info (folder, subfolder_path, &error);
4063 if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
4065 g_object_unref (folder);
4066 gtk_file_path_free (subfolder_path);
4070 error_getting_info_dialog (impl, subfolder_path, error);
4071 g_object_unref (folder);
4072 gtk_file_path_free (subfolder_path);
4076 if (gtk_file_info_get_is_folder (info))
4077 change_folder_and_display_error (impl, subfolder_path);
4083 if (!_gtk_file_chooser_select_path (GTK_FILE_CHOOSER (impl), subfolder_path, &error))
4085 _("Could not select %s:\n%s"),
4090 g_object_unref (folder);
4091 gtk_file_path_free (subfolder_path);
4092 gtk_file_info_free (info);
4097 location_popup_handler (GtkFileChooserDefault *impl)
4100 GtkWidget *toplevel;
4107 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (impl));
4108 if (!GTK_WIDGET_TOPLEVEL (toplevel))
4111 dialog = gtk_dialog_new_with_buttons (_("Open Location"),
4112 GTK_WINDOW (toplevel),
4113 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
4114 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
4115 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
4117 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, -1);
4118 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
4119 gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 2);
4120 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
4122 hbox = gtk_hbox_new (FALSE, 12);
4123 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, FALSE, FALSE, 0);
4124 gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
4126 label = gtk_label_new_with_mnemonic (_("_Location:"));
4127 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
4129 entry = location_entry_create (impl);
4130 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
4131 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
4135 gtk_widget_show_all (dialog);
4136 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
4137 update_from_entry (impl, GTK_WINDOW (dialog), GTK_FILE_CHOOSER_ENTRY (entry));
4139 gtk_widget_destroy (dialog);
4142 /* Handler for the "up-folder" keybinding signal */
4144 up_folder_handler (GtkFileChooserDefault *impl)
4146 GtkFilePath *parent_path;
4150 if (gtk_file_system_get_parent (impl->file_system, impl->current_folder, &parent_path, &error))
4152 if (parent_path) /* If we were on a root, parent_path will be NULL */
4154 change_folder_and_display_error (impl, parent_path);
4155 gtk_file_path_free (parent_path);
4160 _("Could not go to the parent folder of %s:\n%s"),
4161 impl->current_folder,
4165 /* Handler for the "home-folder" keybinding signal */
4167 home_folder_handler (GtkFileChooserDefault *impl)
4173 if (!impl->has_home)
4174 return; /* Should we put up an error dialog? */
4176 pos = shortcuts_get_index (impl, SHORTCUTS_HOME);
4177 if (!gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (impl->shortcuts_model), &iter, NULL, pos))
4178 g_assert_not_reached ();
4180 gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter, SHORTCUTS_COL_PATH, &path, -1);
4181 g_assert (path != NULL);
4183 change_folder_and_display_error (impl, path);