From 9ea75153131c3bedd234ea6a7c1534093d2d9f2a Mon Sep 17 00:00:00 2001 From: Tomas Frydrych Date: Fri, 4 Jan 2008 15:51:51 +0000 Subject: ported filechooser patcheas to gtk 2.12.3 git-svn-id: https://svn.o-hand.com/repos/poky/trunk@3408 311d38ba-8fff-0310-9ca6-ca027cbcb966 --- .../gtk+/gtk+-2.12.3/filechooser-default.patch | 14188 +++++++++++++++++++ .../gtk+/gtk+-2.12.3/filechooser-utils.patch | 32 + meta/packages/gtk+/gtk+-2.12.3/filechooser.patch | 25 + .../gtk+/gtk+-2.12.3/filesystem-volumes.patch | 198 + meta/packages/gtk+/gtk+_2.12.3.bb | 19 +- 5 files changed, 14455 insertions(+), 7 deletions(-) create mode 100644 meta/packages/gtk+/gtk+-2.12.3/filechooser-default.patch create mode 100644 meta/packages/gtk+/gtk+-2.12.3/filechooser-utils.patch create mode 100644 meta/packages/gtk+/gtk+-2.12.3/filechooser.patch create mode 100644 meta/packages/gtk+/gtk+-2.12.3/filesystem-volumes.patch (limited to 'meta') diff --git a/meta/packages/gtk+/gtk+-2.12.3/filechooser-default.patch b/meta/packages/gtk+/gtk+-2.12.3/filechooser-default.patch new file mode 100644 index 0000000000..17671db0d1 --- /dev/null +++ b/meta/packages/gtk+/gtk+-2.12.3/filechooser-default.patch @@ -0,0 +1,14188 @@ +Index: gtk+-2.12.3/gtk/gtkfilechooserdefault.c +=================================================================== +--- gtk+-2.12.3.orig/gtk/gtkfilechooserdefault.c 2007-12-04 16:52:08.000000000 +0000 ++++ gtk+-2.12.3/gtk/gtkfilechooserdefault.c 2008-01-04 10:11:11.000000000 +0000 +@@ -27,12 +27,12 @@ + #include "gtkcelllayout.h" + #include "gtkcellrendererpixbuf.h" + #include "gtkcellrenderertext.h" ++#include "gtkcellrenderertext.h" + #include "gtkcheckmenuitem.h" + #include "gtkclipboard.h" + #include "gtkcombobox.h" + #include "gtkentry.h" + #include "gtkeventbox.h" +-#include "gtkexpander.h" + #include "gtkfilechooserprivate.h" + #include "gtkfilechooserdefault.h" + #include "gtkfilechooserembed.h" +@@ -53,17 +53,13 @@ + #include "gtkmarshalers.h" + #include "gtkmenuitem.h" + #include "gtkmessagedialog.h" +-#include "gtkpathbar.h" + #include "gtkprivate.h" + #include "gtkradiobutton.h" +-#include "gtkrecentfilter.h" +-#include "gtkrecentmanager.h" + #include "gtkscrolledwindow.h" + #include "gtkseparatormenuitem.h" + #include "gtksizegroup.h" + #include "gtkstock.h" + #include "gtktable.h" +-#include "gtktooltip.h" + #include "gtktreednd.h" + #include "gtktreeprivate.h" + #include "gtktreeselection.h" +@@ -81,8 +77,6 @@ + #include + #include + #include +-#include +-#include + + + #ifdef HAVE_UNISTD_H +@@ -92,6 +86,8 @@ + #include + #endif + ++#define DEFAULT_SPACING 5 ++ + /* Profiling stuff */ + #undef PROFILE_FILE_CHOOSER + #ifdef PROFILE_FILE_CHOOSER +@@ -102,6 +98,7 @@ + #endif + + #define PROFILE_INDENT 4 ++ + static int profile_indent; + + static void +@@ -141,8 +138,6 @@ + #define profile_msg(x, y) + #endif + +- +- + typedef struct _GtkFileChooserDefaultClass GtkFileChooserDefaultClass; + + #define GTK_FILE_CHOOSER_DEFAULT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_CHOOSER_DEFAULT, GtkFileChooserDefaultClass)) +@@ -150,6 +145,7 @@ + #define GTK_FILE_CHOOSER_DEFAULT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_CHOOSER_DEFAULT, GtkFileChooserDefaultClass)) + + #define MAX_LOADING_TIME 500 ++#define LONG_CLICK_LENGTH 500 + + struct _GtkFileChooserDefaultClass + { +@@ -163,38 +159,12 @@ + UP_FOLDER, + DOWN_FOLDER, + HOME_FOLDER, +- DESKTOP_FOLDER, +- QUICK_BOOKMARK, +- LOCATION_TOGGLE_POPUP, + SHOW_HIDDEN, +- SEARCH_SHORTCUT, +- RECENT_SHORTCUT, +- + LAST_SIGNAL + }; + + static guint signals[LAST_SIGNAL] = { 0 }; + +-/* Column numbers for the shortcuts tree. Keep these in sync with shortcuts_model_create() */ +-enum { +- SHORTCUTS_COL_PIXBUF, +- SHORTCUTS_COL_NAME, +- SHORTCUTS_COL_DATA, +- SHORTCUTS_COL_TYPE, +- SHORTCUTS_COL_REMOVABLE, +- SHORTCUTS_COL_PIXBUF_VISIBLE, +- SHORTCUTS_COL_HANDLE, +- SHORTCUTS_COL_NUM_COLUMNS +-}; +- +-typedef enum { +- SHORTCUT_TYPE_PATH, +- SHORTCUT_TYPE_VOLUME, +- SHORTCUT_TYPE_SEPARATOR, +- SHORTCUT_TYPE_SEARCH, +- SHORTCUT_TYPE_RECENT +-} ShortcutType; +- + /* Column numbers for the file list */ + enum { + FILE_LIST_COL_NAME, +@@ -203,100 +173,10 @@ + FILE_LIST_COL_NUM_COLUMNS + }; + +-/* Column numbers for the search model. +- * Keep this in sync with search_setup_model() +- */ +-enum { +- SEARCH_MODEL_COL_PATH, +- SEARCH_MODEL_COL_DISPLAY_NAME, +- SEARCH_MODEL_COL_COLLATION_KEY, +- SEARCH_MODEL_COL_STAT, +- SEARCH_MODEL_COL_HANDLE, +- SEARCH_MODEL_COL_PIXBUF, +- SEARCH_MODEL_COL_MIME_TYPE, +- SEARCH_MODEL_COL_IS_FOLDER, +- SEARCH_MODEL_COL_NUM_COLUMNS +-}; +- +-enum { +- RECENT_MODEL_COL_PATH, +- RECENT_MODEL_COL_DISPLAY_NAME, +- RECENT_MODEL_COL_INFO, +- RECENT_MODEL_COL_IS_FOLDER, +- RECENT_MODEL_COL_HANDLE, +- RECENT_MODEL_COL_NUM_COLUMNS +-}; +- +-/* Identifiers for target types */ +-enum { +- GTK_TREE_MODEL_ROW, +- TEXT_URI_LIST +-}; +- +-/* Target types for dragging from the shortcuts list */ +-static const GtkTargetEntry shortcuts_source_targets[] = { +- { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW } +-}; +- +-static const int num_shortcuts_source_targets = G_N_ELEMENTS (shortcuts_source_targets); +- +-/* Target types for dropping into the shortcuts list */ +-static const GtkTargetEntry shortcuts_dest_targets[] = { +- { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW }, +- { "text/uri-list", 0, TEXT_URI_LIST } +-}; +- +-static const int num_shortcuts_dest_targets = G_N_ELEMENTS (shortcuts_dest_targets); +- +-/* Target types for DnD from the file list */ +-static const GtkTargetEntry file_list_source_targets[] = { +- { "text/uri-list", 0, TEXT_URI_LIST } +-}; +- +-static const int num_file_list_source_targets = G_N_ELEMENTS (file_list_source_targets); +- +-/* Target types for dropping into the file list */ +-static const GtkTargetEntry file_list_dest_targets[] = { +- { "text/uri-list", 0, TEXT_URI_LIST } +-}; +- +-static const int num_file_list_dest_targets = G_N_ELEMENTS (file_list_dest_targets); +- +-/* Target types for dragging from the recent files list */ +-static const GtkTargetEntry recent_list_source_targets[] = { +- { "text/uri-list", 0, TEXT_URI_LIST } +-}; +- +-static const int num_recent_list_source_targets = G_N_ELEMENTS (recent_list_source_targets); +- +-static gboolean +-search_is_possible (GtkFileChooserDefault *impl) +-{ +- if (impl->search_engine == NULL) +- impl->search_engine = _gtk_search_engine_new (); +- +- return impl->search_engine != NULL; +-} +- +-/* Interesting places in the shortcuts bar */ +-typedef enum { +- SHORTCUTS_SEARCH, +- SHORTCUTS_RECENT, +- SHORTCUTS_RECENT_SEPARATOR, +- SHORTCUTS_HOME, +- SHORTCUTS_DESKTOP, +- SHORTCUTS_VOLUMES, +- SHORTCUTS_SHORTCUTS, +- SHORTCUTS_BOOKMARKS_SEPARATOR, +- SHORTCUTS_BOOKMARKS, +- SHORTCUTS_CURRENT_FOLDER_SEPARATOR, +- SHORTCUTS_CURRENT_FOLDER +-} ShortcutsIndex; +- + /* Icon size for if we can't get it from the theme */ +-#define FALLBACK_ICON_SIZE 16 ++#define FALLBACK_ICON_SIZE 24 + +-#define PREVIEW_HBOX_SPACING 12 ++#define LIST_HBOX_SPACING DEFAULT_SPACING + #define NUM_LINES 45 + #define NUM_CHARS 60 + +@@ -361,7 +241,6 @@ + const GtkFilePath *path, + GError **error); + static GSList * gtk_file_chooser_default_list_shortcut_folders (GtkFileChooser *chooser); +- + static void gtk_file_chooser_default_get_default_size (GtkFileChooserEmbed *chooser_embed, + gint *default_width, + gint *default_height); +@@ -369,52 +248,17 @@ + static gboolean gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed); + static void gtk_file_chooser_default_initial_focus (GtkFileChooserEmbed *chooser_embed); + +-static void location_popup_handler (GtkFileChooserDefault *impl, +- const gchar *path); +-static void location_popup_on_paste_handler (GtkFileChooserDefault *impl); +-static void location_toggle_popup_handler (GtkFileChooserDefault *impl); +-static void up_folder_handler (GtkFileChooserDefault *impl); +-static void down_folder_handler (GtkFileChooserDefault *impl); +-static void home_folder_handler (GtkFileChooserDefault *impl); +-static void desktop_folder_handler (GtkFileChooserDefault *impl); +-static void quick_bookmark_handler (GtkFileChooserDefault *impl, +- gint bookmark_index); +-static void show_hidden_handler (GtkFileChooserDefault *impl); +-static void search_shortcut_handler (GtkFileChooserDefault *impl); +-static void recent_shortcut_handler (GtkFileChooserDefault *impl); +-static void update_appearance (GtkFileChooserDefault *impl); +- +-static void set_current_filter (GtkFileChooserDefault *impl, +- GtkFileFilter *filter); +-static void check_preview_change (GtkFileChooserDefault *impl); ++static void up_folder_handler (GtkFileChooserDefault *impl); ++static void down_folder_handler (GtkFileChooserDefault *impl); ++static void home_folder_handler (GtkFileChooserDefault *impl); ++static void show_hidden_handler (GtkFileChooserDefault *impl); ++static void update_appearance (GtkFileChooserDefault *impl); + + static void filter_combo_changed (GtkComboBox *combo_box, + GtkFileChooserDefault *impl); +-static void shortcuts_row_activated_cb (GtkTreeView *tree_view, +- GtkTreePath *path, +- GtkTreeViewColumn *column, +- GtkFileChooserDefault *impl); +- +-static gboolean shortcuts_key_press_event_cb (GtkWidget *widget, +- GdkEventKey *event, +- GtkFileChooserDefault *impl); +- +-static gboolean shortcuts_select_func (GtkTreeSelection *selection, +- GtkTreeModel *model, +- GtkTreePath *path, +- gboolean path_currently_selected, +- gpointer data); +-static gboolean shortcuts_get_selected (GtkFileChooserDefault *impl, +- GtkTreeIter *iter); +-static void shortcuts_activate_iter (GtkFileChooserDefault *impl, +- GtkTreeIter *iter); +-static int shortcuts_get_index (GtkFileChooserDefault *impl, +- ShortcutsIndex where); +-static int shortcut_find_position (GtkFileChooserDefault *impl, +- const GtkFilePath *path); +- +-static void bookmarks_check_add_sensitivity (GtkFileChooserDefault *impl); + ++static void set_current_filter (GtkFileChooserDefault *impl, ++ GtkFileFilter *filter); + static gboolean list_select_func (GtkTreeSelection *selection, + GtkTreeModel *model, + GtkTreePath *path, +@@ -433,19 +277,6 @@ + GtkTreeIter *iter, + gpointer user_data); + +-static void path_bar_clicked (GtkPathBar *path_bar, +- GtkFilePath *file_path, +- GtkFilePath *child_path, +- gboolean child_is_hidden, +- GtkFileChooserDefault *impl); +- +-static void add_bookmark_button_clicked_cb (GtkButton *button, +- GtkFileChooserDefault *impl); +-static void remove_bookmark_button_clicked_cb (GtkButton *button, +- GtkFileChooserDefault *impl); +-static void save_folder_combo_changed_cb (GtkComboBox *combo, +- GtkFileChooserDefault *impl); +- + static void list_icon_data_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *tree_model, +@@ -477,114 +308,7 @@ + + static void location_button_toggled_cb (GtkToggleButton *toggle, + GtkFileChooserDefault *impl); +-static void location_switch_to_path_bar (GtkFileChooserDefault *impl); +- +-static void search_stop_searching (GtkFileChooserDefault *impl, +- gboolean remove_query); +-static void search_clear_model (GtkFileChooserDefault *impl, +- gboolean remove_from_treeview); +-static gboolean search_should_respond (GtkFileChooserDefault *impl); +-static void search_switch_to_browse_mode (GtkFileChooserDefault *impl); +-static GSList *search_get_selected_paths (GtkFileChooserDefault *impl); +-static void search_entry_activate_cb (GtkEntry *entry, +- gpointer data); +-static void settings_load (GtkFileChooserDefault *impl); +-static void search_get_valid_child_iter (GtkFileChooserDefault *impl, +- GtkTreeIter *child_iter, +- GtkTreeIter *iter); +- +-static void recent_manager_update (GtkFileChooserDefault *impl); +-static void recent_stop_loading (GtkFileChooserDefault *impl); +-static void recent_clear_model (GtkFileChooserDefault *impl, +- gboolean remove_from_treeview); +-static gboolean recent_should_respond (GtkFileChooserDefault *impl); +-static void recent_switch_to_browse_mode (GtkFileChooserDefault *impl); +-static GSList * recent_get_selected_paths (GtkFileChooserDefault *impl); +-static void recent_get_valid_child_iter (GtkFileChooserDefault *impl, +- GtkTreeIter *child_iter, +- GtkTreeIter *iter); +- +- +- +- +-/* Drag and drop interface declarations */ +- +-typedef struct { +- GtkTreeModelFilter parent; +- +- GtkFileChooserDefault *impl; +-} ShortcutsPaneModelFilter; +- +-typedef struct { +- GtkTreeModelFilterClass parent_class; +-} ShortcutsPaneModelFilterClass; +- +-#define SHORTCUTS_PANE_MODEL_FILTER_TYPE (_shortcuts_pane_model_filter_get_type ()) +-#define SHORTCUTS_PANE_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHORTCUTS_PANE_MODEL_FILTER_TYPE, ShortcutsPaneModelFilter)) +- +-static void shortcuts_pane_model_filter_drag_source_iface_init (GtkTreeDragSourceIface *iface); +- +-G_DEFINE_TYPE_WITH_CODE (ShortcutsPaneModelFilter, +- _shortcuts_pane_model_filter, +- GTK_TYPE_TREE_MODEL_FILTER, +- G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE, +- shortcuts_pane_model_filter_drag_source_iface_init)) +- +-static GtkTreeModel *shortcuts_pane_model_filter_new (GtkFileChooserDefault *impl, +- GtkTreeModel *child_model, +- GtkTreePath *root); +- +- +-typedef struct { +- GtkTreeModelSort parent; +- +- GtkFileChooserDefault *impl; +-} RecentModelSort; +- +-typedef struct { +- GtkTreeModelSortClass parent_class; +-} RecentModelSortClass; +- +-#define RECENT_MODEL_SORT_TYPE (_recent_model_sort_get_type ()) +-#define RECENT_MODEL_SORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RECENT_MODEL_SORT_TYPE, RecentModelSort)) +- +-static void recent_model_sort_drag_source_iface_init (GtkTreeDragSourceIface *iface); +- +-G_DEFINE_TYPE_WITH_CODE (RecentModelSort, +- _recent_model_sort, +- GTK_TYPE_TREE_MODEL_SORT, +- G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE, +- recent_model_sort_drag_source_iface_init)); +- +-static GtkTreeModel *recent_model_sort_new (GtkFileChooserDefault *impl, +- GtkTreeModel *child_model); +- +- +-typedef struct { +- GtkTreeModelSort parent; +- +- GtkFileChooserDefault *impl; +-} SearchModelSort; +- +-typedef struct { +- GtkTreeModelSortClass parent_class; +-} SearchModelSortClass; +- +-#define SEARCH_MODEL_SORT_TYPE (_search_model_sort_get_type ()) +-#define SEARCH_MODEL_SORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEARCH_MODEL_SORT_TYPE, SearchModelSort)) +- +-static void search_model_sort_drag_source_iface_init (GtkTreeDragSourceIface *iface); +- +-G_DEFINE_TYPE_WITH_CODE (SearchModelSort, +- _search_model_sort, +- GTK_TYPE_TREE_MODEL_SORT, +- G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE, +- search_model_sort_drag_source_iface_init)); +- +-static GtkTreeModel *search_model_sort_new (GtkFileChooserDefault *impl, +- GtkTreeModel *child_model); +- +- ++static void settings_load (GtkFileChooserDefault *impl); + + G_DEFINE_TYPE_WITH_CODE (GtkFileChooserDefault, _gtk_file_chooser_default, GTK_TYPE_VBOX, + G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_CHOOSER, +@@ -595,13 +319,9 @@ + static void + _gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class) + { +- static const guint quick_bookmark_keyvals[10] = { +- GDK_1, GDK_2, GDK_3, GDK_4, GDK_5, GDK_6, GDK_7, GDK_8, GDK_9, GDK_0 +- }; + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + GtkBindingSet *binding_set; +- int i; + + gobject_class->finalize = gtk_file_chooser_default_finalize; + gobject_class->constructor = gtk_file_chooser_default_constructor; +@@ -621,7 +341,7 @@ + _gtk_binding_signal_new (I_("location-popup"), + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, +- G_CALLBACK (location_popup_handler), ++ NULL, + NULL, NULL, + _gtk_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); +@@ -629,15 +349,7 @@ + _gtk_binding_signal_new ("location-popup-on-paste", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, +- G_CALLBACK (location_popup_on_paste_handler), +- NULL, NULL, +- _gtk_marshal_VOID__VOID, +- G_TYPE_NONE, 0); +- signals[LOCATION_TOGGLE_POPUP] = +- _gtk_binding_signal_new (I_("location-toggle-popup"), +- G_OBJECT_CLASS_TYPE (class), +- G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, +- G_CALLBACK (location_toggle_popup_handler), ++ NULL, + NULL, NULL, + _gtk_marshal_VOID__VOID, + G_TYPE_NONE, 0); +@@ -665,22 +377,6 @@ + NULL, NULL, + _gtk_marshal_VOID__VOID, + G_TYPE_NONE, 0); +- signals[DESKTOP_FOLDER] = +- _gtk_binding_signal_new (I_("desktop-folder"), +- G_OBJECT_CLASS_TYPE (class), +- G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, +- G_CALLBACK (desktop_folder_handler), +- NULL, NULL, +- _gtk_marshal_VOID__VOID, +- G_TYPE_NONE, 0); +- signals[QUICK_BOOKMARK] = +- _gtk_binding_signal_new (I_("quick-bookmark"), +- G_OBJECT_CLASS_TYPE (class), +- G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, +- G_CALLBACK (quick_bookmark_handler), +- NULL, NULL, +- _gtk_marshal_VOID__INT, +- G_TYPE_NONE, 1, G_TYPE_INT); + signals[SHOW_HIDDEN] = + _gtk_binding_signal_new ("show-hidden", + G_OBJECT_CLASS_TYPE (class), +@@ -689,22 +385,6 @@ + NULL, NULL, + _gtk_marshal_VOID__VOID, + G_TYPE_NONE, 0); +- signals[SEARCH_SHORTCUT] = +- _gtk_binding_signal_new ("search-shortcut", +- G_OBJECT_CLASS_TYPE (class), +- G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, +- G_CALLBACK (search_shortcut_handler), +- NULL, NULL, +- _gtk_marshal_VOID__VOID, +- G_TYPE_NONE, 0); +- signals[RECENT_SHORTCUT] = +- _gtk_binding_signal_new ("recent-shortcut", +- G_OBJECT_CLASS_TYPE (class), +- G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, +- G_CALLBACK (recent_shortcut_handler), +- NULL, NULL, +- _gtk_marshal_VOID__VOID, +- G_TYPE_NONE, 0); + + binding_set = gtk_binding_set_by_class (class); + +@@ -764,29 +444,17 @@ + "home-folder", + 0); + gtk_binding_entry_add_signal (binding_set, +- GDK_d, GDK_MOD1_MASK, +- "desktop-folder", +- 0); +- gtk_binding_entry_add_signal (binding_set, + GDK_h, GDK_CONTROL_MASK, + "show-hidden", + 0); +- gtk_binding_entry_add_signal (binding_set, +- GDK_s, GDK_MOD1_MASK, +- "search-shortcut", +- 0); +- gtk_binding_entry_add_signal (binding_set, +- GDK_r, GDK_MOD1_MASK, +- "recent-shortcut", +- 0); +- +- for (i = 0; i < 10; i++) +- gtk_binding_entry_add_signal (binding_set, +- quick_bookmark_keyvals[i], GDK_MOD1_MASK, +- "quick-bookmark", +- 1, G_TYPE_INT, i); + + _gtk_file_chooser_install_properties (gobject_class); ++ ++ gtk_settings_install_property (g_param_spec_string ("gtk-file-chooser-backend", ++ P_("Default file chooser backend"), ++ P_("Name of the GtkFileChooser backend to use by default"), ++ NULL, ++ GTK_PARAM_READWRITE)); + } + + static void +@@ -797,7 +465,6 @@ + iface->select_all = gtk_file_chooser_default_select_all; + iface->unselect_all = gtk_file_chooser_default_unselect_all; + iface->get_paths = gtk_file_chooser_default_get_paths; +- iface->get_preview_path = gtk_file_chooser_default_get_preview_path; + iface->get_file_system = gtk_file_chooser_default_get_file_system; + iface->set_current_folder = gtk_file_chooser_default_set_current_folder; + iface->get_current_folder = gtk_file_chooser_default_get_current_folder; +@@ -805,9 +472,12 @@ + iface->add_filter = gtk_file_chooser_default_add_filter; + iface->remove_filter = gtk_file_chooser_default_remove_filter; + iface->list_filters = gtk_file_chooser_default_list_filters; ++ ++ /* these are only stubs */ ++ iface->get_preview_path = gtk_file_chooser_default_get_preview_path; + iface->add_shortcut_folder = gtk_file_chooser_default_add_shortcut_folder; + iface->remove_shortcut_folder = gtk_file_chooser_default_remove_shortcut_folder; +- iface->list_shortcut_folders = gtk_file_chooser_default_list_shortcut_folders; ++ + } + + static void +@@ -827,85 +497,27 @@ + access ("MARK: *** CREATE FILE CHOOSER", F_OK); + #endif + impl->local_only = TRUE; +- impl->preview_widget_active = TRUE; +- impl->use_preview_label = TRUE; + impl->select_multiple = FALSE; + impl->show_hidden = FALSE; ++ impl->show_create_folder = TRUE; + impl->icon_size = FALLBACK_ICON_SIZE; + impl->load_state = LOAD_EMPTY; + impl->reload_state = RELOAD_EMPTY; + impl->pending_select_paths = NULL; +- impl->location_mode = LOCATION_MODE_PATH_BAR; +- impl->operation_mode = OPERATION_MODE_BROWSE; ++ impl->location_mode = LOCATION_MODE_FILENAME_ENTRY; ++ impl->path_history = NULL; + +- gtk_box_set_spacing (GTK_BOX (impl), 12); ++ gtk_box_set_spacing (GTK_BOX (impl), DEFAULT_SPACING); + + impl->tooltips = gtk_tooltips_new (); + g_object_ref_sink (impl->tooltips); + +- profile_end ("end", NULL); +-} +- +-/* Frees the data columns for the specified iter in the shortcuts model*/ +-static void +-shortcuts_free_row_data (GtkFileChooserDefault *impl, +- GtkTreeIter *iter) +-{ +- gpointer col_data; +- ShortcutType shortcut_type; +- GtkFileSystemHandle *handle; +- +- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), iter, +- SHORTCUTS_COL_DATA, &col_data, +- SHORTCUTS_COL_TYPE, &shortcut_type, +- SHORTCUTS_COL_HANDLE, &handle, +- -1); +- +- if (handle) +- gtk_file_system_cancel_operation (handle); +- +- if (!(shortcut_type == SHORTCUT_TYPE_PATH || +- shortcut_type == SHORTCUT_TYPE_VOLUME) || +- !col_data) +- return; +- +- if (shortcut_type == SHORTCUT_TYPE_VOLUME) +- { +- GtkFileSystemVolume *volume; +- +- volume = col_data; +- gtk_file_system_volume_free (impl->file_system, volume); +- } +- else +- { +- GtkFilePath *path; +- +- g_assert (shortcut_type == SHORTCUT_TYPE_PATH); ++ if (!impl->root_folder) ++ impl->root_folder = g_strdup ("/"); + +- path = col_data; +- gtk_file_path_free (path); +- } ++ profile_end ("end", NULL); + } + +-/* Frees all the data columns in the shortcuts model */ +-static void +-shortcuts_free (GtkFileChooserDefault *impl) +-{ +- GtkTreeIter iter; +- +- if (!impl->shortcuts_model) +- return; +- +- if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (impl->shortcuts_model), &iter)) +- do +- { +- shortcuts_free_row_data (impl, &iter); +- } +- while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter)); +- +- g_object_unref (impl->shortcuts_model); +- impl->shortcuts_model = NULL; +-} + + static void + pending_select_paths_free (GtkFileChooserDefault *impl) +@@ -924,12 +536,12 @@ + impl->pending_select_paths = NULL; + } + ++ + static void + pending_select_paths_add (GtkFileChooserDefault *impl, + const GtkFilePath *path) + { +- impl->pending_select_paths = +- g_slist_prepend (impl->pending_select_paths, gtk_file_path_copy (path)); ++ impl->pending_select_paths = g_slist_prepend (impl->pending_select_paths, gtk_file_path_copy (path)); + } + + /* Used from gtk_tree_selection_selected_foreach() */ +@@ -964,18 +576,27 @@ + } + + static void +-gtk_file_chooser_default_finalize (GObject *object) ++path_history_free (GtkFileChooserDefault *impl) + { +- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object); + GSList *l; + +- if (impl->shortcuts_pane_filter_model) +- g_object_unref (impl->shortcuts_pane_filter_model); ++ for (l = impl->path_history; l; l = l->next) ++ { ++ GtkFilePath *path; ++ ++ path = l->data; ++ gtk_file_path_free (path); ++ } + +- if (impl->shortcuts_combo_filter_model) +- g_object_unref (impl->shortcuts_combo_filter_model); ++ g_slist_free (impl->path_history); ++ impl->path_history = NULL; ++} + +- shortcuts_free (impl); ++static void ++gtk_file_chooser_default_finalize (GObject *object) ++{ ++ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object); ++ GSList *l; + + g_object_unref (impl->file_system); + +@@ -999,8 +620,7 @@ + if (impl->current_folder) + gtk_file_path_free (impl->current_folder); + +- if (impl->preview_path) +- gtk_file_path_free (impl->preview_path); ++ path_history_free (impl); + + load_remove_timer (impl); + +@@ -1011,15 +631,18 @@ + if (impl->sort_model) + g_object_unref (impl->sort_model); + +- search_clear_model (impl, FALSE); +- recent_clear_model (impl, FALSE); +- +- g_free (impl->preview_display_name); ++ if (impl->list_press_path) ++ { ++ gtk_tree_path_free (impl->list_press_path); ++ impl->list_press_path = NULL; ++ } + + g_free (impl->edited_new_text); + + g_object_unref (impl->tooltips); + ++ g_free (impl->root_folder); ++ + G_OBJECT_CLASS (_gtk_file_chooser_default_parent_class)->finalize (object); + } + +@@ -1104,28 +727,6 @@ + path, error); + } + +-/* Shows an error dialog about not being able to add a bookmark */ +-static void +-error_adding_bookmark_dialog (GtkFileChooserDefault *impl, +- const GtkFilePath *path, +- GError *error) +-{ +- error_dialog (impl, +- _("Could not add a bookmark"), +- path, error); +-} +- +-/* Shows an error dialog about not being able to remove a bookmark */ +-static void +-error_removing_bookmark_dialog (GtkFileChooserDefault *impl, +- const GtkFilePath *path, +- GError *error) +-{ +- error_dialog (impl, +- _("Could not remove bookmark"), +- path, error); +-} +- + /* Shows an error dialog about not being able to create a folder */ + static void + error_creating_folder_dialog (GtkFileChooserDefault *impl, +@@ -1146,9 +747,9 @@ + GError *error) + { + error_dialog (impl, +- _("The folder could not be created, as a file with the same " +- "name already exists. Try using a different name for the " +- "folder, or rename the file first."), ++ _("The folder could not be created, as a file with the same name " ++ "already exists. Try using a different name for the folder, " ++ "or rename the file first."), + path, error); + } + +@@ -1175,9378 +776,3705 @@ + + /* Changes folders, displaying an error dialog if this fails */ + static gboolean +-change_folder_and_display_error (GtkFileChooserDefault *impl, +- const GtkFilePath *path, +- gboolean clear_entry) ++change_folder (GtkFileChooserDefault *impl, const GtkFilePath *path, ++ gboolean errormsg) + { + GError *error; + gboolean result; + GtkFilePath *path_copy; ++ gchar * file_name; + + g_return_val_if_fail (path != NULL, FALSE); + +- profile_start ("start", (char *) path); ++ path_copy = gtk_file_path_copy (path); ++ file_name = gtk_file_system_path_to_filename (impl->file_system, path_copy); + +- /* We copy the path because of this case: +- * +- * list_row_activated() +- * fetches path from model; path belongs to the model (*) +- * calls change_folder_and_display_error() +- * calls _gtk_file_chooser_set_current_folder_path() +- * changing folders fails, sets model to NULL, thus freeing the path in (*) +- */ ++ if (!file_name) ++ { ++ gtk_file_path_free (path_copy); ++ return 0; ++ } ++ ++ if (impl->root_folder && file_name[0] == '/' && file_name[1] == 0) ++ { ++ /* If changing to / and we have root_folder, change into it instead */ ++ gtk_file_path_free (path_copy); ++ path_copy = gtk_file_system_filename_to_path (impl->file_system, ++ impl->root_folder); ++ ++ gtk_widget_set_sensitive (impl->up_button, FALSE); ++ } ++ else if (impl->root_folder && ++ strcmp (file_name, impl->root_folder) && ++ !strncmp (file_name, impl->root_folder, strlen (file_name))) ++ { ++ /* refuse to change below the root */ ++ gtk_file_path_free (path_copy); ++ g_free (file_name); ++ return 0; ++ } ++ else if (!strcmp (file_name, impl->root_folder)) ++ { ++ gtk_widget_set_sensitive (impl->up_button, FALSE); ++ } ++ else if (impl->current_folder && !strcmp (file_name, "/media")) ++ { ++ /* Asked to changed into /media -- if we are already in a media ++ * child folder, we refuse, but if we are in the root, we permit this ++ */ ++ gchar *name = ++ gtk_file_system_path_to_filename (impl->file_system, ++ impl->current_folder); ++ ++ if (name && !strncmp (name, "/media", 6)) ++ { ++ g_free (name); ++ gtk_file_path_free (path_copy); ++ g_free (file_name); ++ return 0; ++ } ++ ++ gtk_widget_set_sensitive (impl->up_button, TRUE); ++ } ++ else if (!strncmp (file_name, "/media/", 7)) ++ { ++ /* Changing into a media child -- if it is an immediate child, disable ++ * the Up button ++ */ ++ gchar * p = file_name + 7; ++ gchar * q = strchr (p, '/'); ++ if (!q) ++ gtk_widget_set_sensitive (impl->up_button, FALSE); ++ else ++ gtk_widget_set_sensitive (impl->up_button, TRUE); ++ } ++ else ++ { ++ gtk_widget_set_sensitive (impl->up_button, TRUE); ++ } + +- path_copy = gtk_file_path_copy (path); + + error = NULL; +- result = gtk_file_chooser_default_update_current_folder (GTK_FILE_CHOOSER (impl), path_copy, TRUE, clear_entry, &error); ++ result = _gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (impl), path_copy, &error); + +- if (!result) ++ if (errormsg && !result) + error_changing_folder_dialog (impl, path_copy, error); + +- gtk_file_path_free (path_copy); ++ gtk_label_set_text (GTK_LABEL (impl->location_label), file_name); + +- profile_end ("end", (char *) path); ++ gtk_file_path_free (path_copy); ++ g_free (file_name); + + return result; + } + +-static void +-update_preview_widget_visibility (GtkFileChooserDefault *impl) ++static gboolean ++change_folder_and_display_error (GtkFileChooserDefault *impl, ++ const GtkFilePath *path) + { +- if (impl->use_preview_label) +- { +- if (!impl->preview_label) +- { +- impl->preview_label = gtk_label_new (impl->preview_display_name); +- gtk_box_pack_start (GTK_BOX (impl->preview_box), impl->preview_label, FALSE, FALSE, 0); +- gtk_box_reorder_child (GTK_BOX (impl->preview_box), impl->preview_label, 0); +- gtk_label_set_ellipsize (GTK_LABEL (impl->preview_label), PANGO_ELLIPSIZE_MIDDLE); +- gtk_widget_show (impl->preview_label); +- } +- } +- else +- { +- if (impl->preview_label) +- { +- gtk_widget_destroy (impl->preview_label); +- impl->preview_label = NULL; +- } +- } +- +- if (impl->preview_widget_active && impl->preview_widget) +- gtk_widget_show (impl->preview_box); +- else +- gtk_widget_hide (impl->preview_box); +- +- g_signal_emit_by_name (impl, "default-size-changed"); ++ return change_folder (impl, path, TRUE); + } + +-static void +-set_preview_widget (GtkFileChooserDefault *impl, +- GtkWidget *preview_widget) ++ ++/* FIXME: GtkFileSystem needs a function to split a remote path ++ * into hostname and path components, or maybe just have a ++ * gtk_file_system_path_get_display_name(). ++ * ++ * This function is also used in gtkfilechooserbutton.c ++ */ ++gchar * ++_gtk_file_chooser_label_for_uri (const gchar *uri) + { +- if (preview_widget == impl->preview_widget) +- return; ++ const gchar *path, *start, *end, *p; ++ gchar *host, *label; + +- if (impl->preview_widget) +- gtk_container_remove (GTK_CONTAINER (impl->preview_box), +- impl->preview_widget); ++ start = strstr (uri, "://"); ++ start += 3; ++ path = strchr (start, '/'); + +- impl->preview_widget = preview_widget; +- if (impl->preview_widget) ++ if (path) ++ end = path; ++ else + { +- gtk_widget_show (impl->preview_widget); +- gtk_box_pack_start (GTK_BOX (impl->preview_box), impl->preview_widget, TRUE, TRUE, 0); +- gtk_box_reorder_child (GTK_BOX (impl->preview_box), +- impl->preview_widget, +- (impl->use_preview_label && impl->preview_label) ? 1 : 0); ++ end = uri + strlen (uri); ++ path = "/"; + } + +- update_preview_widget_visibility (impl); +-} ++ /* strip username */ ++ p = strchr (start, '@'); ++ if (p && p < end) ++ { ++ start = p + 1; ++ } + +-/* Renders a "Search" icon at an appropriate size for a tree view */ +-static GdkPixbuf * +-render_search_icon (GtkFileChooserDefault *impl) +-{ +- return gtk_widget_render_icon (GTK_WIDGET (impl), GTK_STOCK_FIND, GTK_ICON_SIZE_MENU, NULL); +-} ++ p = strchr (start, ':'); ++ if (p && p < end) ++ end = p; + +-static GdkPixbuf * +-render_recent_icon (GtkFileChooserDefault *impl) +-{ +- GtkIconTheme *theme; +- GdkPixbuf *retval; ++ host = g_strndup (start, end - start); + +- if (gtk_widget_has_screen (GTK_WIDGET (impl))) +- theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl))); +- else +- theme = gtk_icon_theme_get_default (); ++ /* Translators: the first string is a path and the second string ++ * is a hostname. Nautilus and the panel contain the same string ++ * to translate. ++ */ ++ label = g_strdup_printf (_("%1$s on %2$s"), path, host); + +- retval = gtk_icon_theme_load_icon (theme, "document-open-recent", +- impl->icon_size, 0, +- NULL); +- +- /* fallback */ +- if (!retval) +- retval = gtk_widget_render_icon (GTK_WIDGET (impl), GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL); ++ g_free (host); + +- return retval; ++ return label; + } + + +-/* Re-reads all the icons for the shortcuts, used when the theme changes */ +-struct ReloadIconsData +-{ +- GtkFileChooserDefault *impl; +- GtkTreeRowReference *row_ref; +-}; +- ++/* Callback used when the "New Folder" button is clicked */ + static void +-shortcuts_reload_icons_get_info_cb (GtkFileSystemHandle *handle, +- const GtkFileInfo *info, +- const GError *error, +- gpointer user_data) ++new_folder_button_clicked (GtkButton *button, ++ GtkFileChooserDefault *impl) + { +- GdkPixbuf *pixbuf; + GtkTreeIter iter; + GtkTreePath *path; +- gboolean cancelled = handle->cancelled; +- struct ReloadIconsData *data = user_data; + +- if (!g_slist_find (data->impl->reload_icon_handles, handle)) +- goto out; ++ if (!impl->browse_files_model) ++ return; /* FIXME: this sucks. Disable the New Folder button or something. */ + +- data->impl->reload_icon_handles = g_slist_remove (data->impl->reload_icon_handles, handle); ++ /* Prevent button from being clicked twice */ ++ gtk_widget_set_sensitive (impl->browse_new_folder_button, FALSE); + +- if (cancelled || error) +- goto out; ++ _gtk_file_system_model_add_editable (impl->browse_files_model, &iter); + +- pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (data->impl), +- data->impl->icon_size, NULL); ++ path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->browse_files_model), &iter); ++ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (impl->browse_files_tree_view), ++ path, impl->list_name_column, ++ FALSE, 0.0, 0.0); ++ ++ g_object_set (impl->list_name_renderer, "editable", TRUE, NULL); ++ gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), ++ path, ++ impl->list_name_column, ++ TRUE); + +- path = gtk_tree_row_reference_get_path (data->row_ref); +- gtk_tree_model_get_iter (GTK_TREE_MODEL (data->impl->shortcuts_model), &iter, path); +- gtk_list_store_set (data->impl->shortcuts_model, &iter, +- SHORTCUTS_COL_PIXBUF, pixbuf, +- -1); + gtk_tree_path_free (path); ++} + +- if (pixbuf) +- g_object_unref (pixbuf); ++static void ++edited_idle_create_folder_cb (GtkFileSystemHandle *handle, ++ const GtkFilePath *path, ++ const GError *error, ++ gpointer data) ++{ ++ gboolean cancelled = handle->cancelled; ++ GtkFileChooserDefault *impl = data; + +-out: +- gtk_tree_row_reference_free (data->row_ref); +- g_object_unref (data->impl); +- g_free (data); ++ if (!g_slist_find (impl->pending_handles, handle)) ++ goto out; ++ ++ impl->pending_handles = g_slist_remove (impl->pending_handles, handle); ++ ++ if (cancelled) ++ goto out; ++ ++ if (!error) ++ change_folder_and_display_error (impl, path); ++ else ++ error_creating_folder_dialog (impl, path, g_error_copy (error)); + ++ out: ++ g_object_unref (impl); + g_object_unref (handle); + } + +-static void +-shortcuts_reload_icons (GtkFileChooserDefault *impl) ++/* Idle handler for creating a new folder after editing its name cell, or for ++ * canceling the editing. ++ */ ++static gboolean ++edited_idle_cb (GtkFileChooserDefault *impl) + { +- GSList *l; +- GtkTreeIter iter; ++ GDK_THREADS_ENTER (); + +- profile_start ("start", NULL); ++ g_source_destroy (impl->edited_idle); ++ impl->edited_idle = NULL; + +- if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (impl->shortcuts_model), &iter)) +- goto out; ++ _gtk_file_system_model_remove_editable (impl->browse_files_model); ++ g_object_set (impl->list_name_renderer, "editable", FALSE, NULL); + +- for (l = impl->reload_icon_handles; l; l = l->next) +- { +- GtkFileSystemHandle *handle = GTK_FILE_SYSTEM_HANDLE (l->data); +- gtk_file_system_cancel_operation (handle); +- } +- g_slist_free (impl->reload_icon_handles); +- impl->reload_icon_handles = NULL; ++ gtk_widget_set_sensitive (impl->browse_new_folder_button, TRUE); + +- do ++ if (impl->edited_new_text) /* not cancelled? */ + { +- gpointer data; +- ShortcutType shortcut_type; +- gboolean pixbuf_visible; +- GdkPixbuf *pixbuf; +- +- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter, +- SHORTCUTS_COL_DATA, &data, +- SHORTCUTS_COL_TYPE, &shortcut_type, +- SHORTCUTS_COL_PIXBUF_VISIBLE, &pixbuf_visible, +- -1); ++ GError *error; ++ GtkFilePath *file_path; + +- pixbuf = NULL; +- if (pixbuf_visible) +- { +- if (shortcut_type == SHORTCUT_TYPE_VOLUME) +- { +- GtkFileSystemVolume *volume; ++ error = NULL; ++ file_path = gtk_file_system_make_path (impl->file_system, ++ impl->current_folder, ++ impl->edited_new_text, ++ &error); ++ if (file_path) ++ { ++ GtkFileSystemHandle *handle; + +- volume = data; +- pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl), +- impl->icon_size, NULL); +- +- gtk_list_store_set (impl->shortcuts_model, &iter, +- SHORTCUTS_COL_PIXBUF, pixbuf, +- -1); ++ handle = gtk_file_system_create_folder (impl->file_system, file_path, ++ edited_idle_create_folder_cb, ++ g_object_ref (impl)); ++ impl->pending_handles = g_slist_append (impl->pending_handles, handle); + +- if (pixbuf) +- g_object_unref (pixbuf); +- } +- else if (shortcut_type == SHORTCUT_TYPE_PATH) +- { +- if (gtk_file_system_path_is_local (impl->file_system, (GtkFilePath *)data)) +- { +- const GtkFilePath *path; +- struct ReloadIconsData *info; +- GtkTreePath *tree_path; +- GtkFileSystemHandle *handle; +- +- path = data; +- +- info = g_new0 (struct ReloadIconsData, 1); +- info->impl = g_object_ref (impl); +- tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter); +- info->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), tree_path); +- gtk_tree_path_free (tree_path); +- +- handle = gtk_file_system_get_info (impl->file_system, path, +- GTK_FILE_INFO_ICON, +- shortcuts_reload_icons_get_info_cb, +- info); +- impl->reload_icon_handles = g_slist_append (impl->reload_icon_handles, handle); +- } +- else +- { +- GtkIconTheme *icon_theme; +- +- /* Don't call get_info for remote paths to avoid latency and +- * auth dialogs. +- * If we switch to a better bookmarks file format (XBEL), we +- * should use mime info to get a better icon. +- */ +- icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl))); +- pixbuf = gtk_icon_theme_load_icon (icon_theme, "gnome-fs-share", +- impl->icon_size, 0, NULL); +- +- gtk_list_store_set (impl->shortcuts_model, &iter, +- SHORTCUTS_COL_PIXBUF, pixbuf, +- -1); +- +- if (pixbuf) +- g_object_unref (pixbuf); +- } +- } +- else if (shortcut_type == SHORTCUT_TYPE_SEARCH) +- { +- pixbuf = render_search_icon (impl); +- } +- else if (shortcut_type == SHORTCUT_TYPE_RECENT) +- { +- pixbuf = render_recent_icon (impl); +- } ++ gtk_file_path_free (file_path); + } ++ else ++ error_creating_folder_dialog (impl, file_path, error); ++ ++ g_free (impl->edited_new_text); ++ impl->edited_new_text = NULL; + } +- while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model),&iter)); + +- out: ++ GDK_THREADS_LEAVE (); + +- profile_end ("end", NULL); ++ return FALSE; + } + +-static void +-shortcuts_find_folder (GtkFileChooserDefault *impl, +- GtkFilePath *folder) ++static void ++queue_edited_idle (GtkFileChooserDefault *impl, ++ const gchar *new_text) + { +- GtkTreeSelection *selection; +- int pos; +- GtkTreePath *path; +- +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view)); ++ /* We create the folder in an idle handler so that we don't modify the tree ++ * just now. ++ */ + +- g_assert (folder != NULL); +- pos = shortcut_find_position (impl, folder); +- if (pos == -1) ++ if (!impl->edited_idle) + { +- gtk_tree_selection_unselect_all (selection); +- return; ++ impl->edited_idle = g_idle_source_new (); ++ g_source_set_closure (impl->edited_idle, ++ g_cclosure_new_object (G_CALLBACK (edited_idle_cb), ++ G_OBJECT (impl))); ++ g_source_attach (impl->edited_idle, NULL); + } + +- path = gtk_tree_path_new_from_indices (pos, -1); +- gtk_tree_selection_select_path (selection, path); +- gtk_tree_path_free (path); ++ g_free (impl->edited_new_text); ++ impl->edited_new_text = g_strdup (new_text); + } + +-/* If a shortcut corresponds to the current folder, selects it */ ++/* Callback used from the text cell renderer when the new folder is named */ + static void +-shortcuts_find_current_folder (GtkFileChooserDefault *impl) ++renderer_edited_cb (GtkCellRendererText *cell_renderer_text, ++ const gchar *path, ++ const gchar *new_text, ++ GtkFileChooserDefault *impl) + { +- shortcuts_find_folder (impl, impl->current_folder); ++ /* work around bug #154921 */ ++ g_object_set (cell_renderer_text, ++ "mode", GTK_CELL_RENDERER_MODE_INERT, NULL); ++ queue_edited_idle (impl, new_text); + } + +-/* Removes the specified number of rows from the shortcuts list */ ++/* Callback used from the text cell renderer when the new folder edition gets ++ * canceled. ++ */ + static void +-shortcuts_remove_rows (GtkFileChooserDefault *impl, +- int start_row, +- int n_rows) ++renderer_editing_canceled_cb (GtkCellRendererText *cell_renderer_text, ++ GtkFileChooserDefault *impl) + { +- GtkTreePath *path; +- +- path = gtk_tree_path_new_from_indices (start_row, -1); +- +- for (; n_rows; n_rows--) +- { +- GtkTreeIter iter; +- +- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path)) +- g_assert_not_reached (); ++ /* work around bug #154921 */ ++ g_object_set (cell_renderer_text, ++ "mode", GTK_CELL_RENDERER_MODE_INERT, NULL); ++ queue_edited_idle (impl, NULL); ++} + +- shortcuts_free_row_data (impl, &iter); +- gtk_list_store_remove (impl->shortcuts_model, &iter); +- } ++/* Creates the widgets for the filter combo box */ ++static GtkWidget * ++filter_create (GtkFileChooserDefault *impl) ++{ ++ impl->filter_combo = gtk_combo_box_new_text (); ++ gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (impl->filter_combo), FALSE); + +- gtk_tree_path_free (path); +-} ++ g_signal_connect (impl->filter_combo, "changed", ++ G_CALLBACK (filter_combo_changed), impl); + +-static void +-shortcuts_update_count (GtkFileChooserDefault *impl, +- ShortcutsIndex type, +- gint value) +-{ +- switch (type) +- { +- case SHORTCUTS_HOME: +- if (value < 0) +- impl->has_home = FALSE; +- else +- impl->has_home = TRUE; +- break; +- +- case SHORTCUTS_DESKTOP: +- if (value < 0) +- impl->has_desktop = FALSE; +- else +- impl->has_desktop = TRUE; +- break; +- +- case SHORTCUTS_VOLUMES: +- impl->num_volumes += value; +- break; +- +- case SHORTCUTS_SHORTCUTS: +- impl->num_shortcuts += value; +- break; +- +- case SHORTCUTS_BOOKMARKS: +- impl->num_bookmarks += value; +- break; +- +- case SHORTCUTS_CURRENT_FOLDER: +- if (value < 0) +- impl->shortcuts_current_folder_active = FALSE; +- else +- impl->shortcuts_current_folder_active = TRUE; +- break; +- +- default: +- /* nothing */ +- break; +- } ++ return impl->filter_combo; + } + +-struct ShortcutsInsertRequest +-{ ++struct selection_check_closure { + GtkFileChooserDefault *impl; +- GtkFilePath *parent_path; +- GtkFilePath *path; +- int pos; +- char *label_copy; +- GtkTreeRowReference *row_ref; +- ShortcutsIndex type; +- gboolean name_only; +- gboolean removable; ++ int num_selected; ++ gboolean all_files; ++ gboolean all_folders; + }; + ++/* Used from gtk_tree_selection_selected_foreach() */ + static void +-get_file_info_finished (GtkFileSystemHandle *handle, +- const GtkFileInfo *info, +- const GError *error, +- gpointer data) ++selection_check_foreach_cb (GtkTreeModel *model, ++ GtkTreePath *path, ++ GtkTreeIter *iter, ++ gpointer data) + { +- gint pos = -1; +- gboolean cancelled = handle->cancelled; +- GdkPixbuf *pixbuf; +- GtkTreePath *path; +- GtkTreeIter iter; +- GtkFileSystemHandle *model_handle; +- struct ShortcutsInsertRequest *request = data; +- +- path = gtk_tree_row_reference_get_path (request->row_ref); +- if (!path) +- /* Handle doesn't exist anymore in the model */ +- goto out; +- +- pos = gtk_tree_path_get_indices (path)[0]; +- gtk_tree_model_get_iter (GTK_TREE_MODEL (request->impl->shortcuts_model), +- &iter, path); +- gtk_tree_path_free (path); +- +- /* validate handle, else goto out */ +- gtk_tree_model_get (GTK_TREE_MODEL (request->impl->shortcuts_model), &iter, +- SHORTCUTS_COL_HANDLE, &model_handle, +- -1); +- if (handle != model_handle) +- goto out; ++ struct selection_check_closure *closure; ++ GtkTreeIter child_iter; ++ const GtkFileInfo *info; ++ gboolean is_folder; + +- /* set the handle to NULL in the model (we unref later on) */ +- gtk_list_store_set (request->impl->shortcuts_model, &iter, +- SHORTCUTS_COL_HANDLE, NULL, +- -1); ++ closure = data; ++ closure->num_selected++; + +- if (cancelled) +- goto out; ++ gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter); + +- if (!info) +- { +- gtk_list_store_remove (request->impl->shortcuts_model, &iter); +- shortcuts_update_count (request->impl, request->type, -1); ++ info = _gtk_file_system_model_get_info (closure->impl->browse_files_model, &child_iter); ++ is_folder = info ? gtk_file_info_get_is_folder (info) : FALSE; + +- if (request->type == SHORTCUTS_HOME) +- { +- const char *home = g_get_home_dir (); +- GtkFilePath *home_path; ++ closure->all_folders = closure->all_folders && is_folder; ++ closure->all_files = closure->all_files && !is_folder; ++} + +- home_path = gtk_file_system_filename_to_path (request->impl->file_system, home); +- error_getting_info_dialog (request->impl, home_path, g_error_copy (error)); +- gtk_file_path_free (home_path); +- } +- else if (request->type == SHORTCUTS_CURRENT_FOLDER) +- { +- /* Remove the current folder separator */ +- gint separator_pos = shortcuts_get_index (request->impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR); +- shortcuts_remove_rows (request->impl, separator_pos, 1); +- } ++/* Checks whether the selected items in the file list are all files or all folders */ ++static void ++selection_check (GtkFileChooserDefault *impl, ++ gint *num_selected, ++ gboolean *all_files, ++ gboolean *all_folders) ++{ ++ struct selection_check_closure closure; ++ GtkTreeSelection *selection; + +- goto out; +- } +- +- if (!request->label_copy) +- request->label_copy = g_strdup (gtk_file_info_get_display_name (info)); +- pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (request->impl), +- request->impl->icon_size, NULL); +- +- gtk_list_store_set (request->impl->shortcuts_model, &iter, +- SHORTCUTS_COL_PIXBUF, pixbuf, +- SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE, +- SHORTCUTS_COL_NAME, request->label_copy, +- SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_PATH, +- SHORTCUTS_COL_REMOVABLE, request->removable, +- -1); +- +- if (request->impl->shortcuts_pane_filter_model) +- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (request->impl->shortcuts_pane_filter_model)); +- +- if (request->impl->shortcuts_combo_filter_model) +- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (request->impl->shortcuts_combo_filter_model)); +- +- if (request->type == SHORTCUTS_CURRENT_FOLDER && +- request->impl->save_folder_combo != NULL) +- { +- /* The current folder is updated via _activate_iter(), don't +- * have save_folder_combo_changed_cb() call _activate_iter() +- * again. +- */ +- g_signal_handlers_block_by_func (request->impl->save_folder_combo, +- G_CALLBACK (save_folder_combo_changed_cb), +- request->impl); +- +- if (request->impl->has_search) +- pos -= 1; ++ closure.impl = impl; ++ closure.num_selected = 0; ++ closure.all_files = TRUE; ++ closure.all_folders = TRUE; + +- if (request->impl->has_recent) +- pos -= 2; ++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); ++ gtk_tree_selection_selected_foreach (selection, ++ selection_check_foreach_cb, ++ &closure); + +- gtk_combo_box_set_active (GTK_COMBO_BOX (request->impl->save_folder_combo), pos); +- g_signal_handlers_unblock_by_func (request->impl->save_folder_combo, +- G_CALLBACK (save_folder_combo_changed_cb), +- request->impl); +- } ++ g_assert (closure.num_selected == 0 || !(closure.all_files && closure.all_folders)); + +- if (pixbuf) +- g_object_unref (pixbuf); ++ if (num_selected) ++ *num_selected = closure.num_selected; + +-out: +- g_object_unref (request->impl); +- gtk_file_path_free (request->parent_path); +- gtk_file_path_free (request->path); +- gtk_tree_row_reference_free (request->row_ref); +- g_free (request->label_copy); +- g_free (request); ++ if (all_files) ++ *all_files = closure.all_files; + +- g_object_unref (handle); ++ if (all_folders) ++ *all_folders = closure.all_folders; + } + +-/* FIXME: GtkFileSystem needs a function to split a remote path +- * into hostname and path components, or maybe just have a +- * gtk_file_system_path_get_display_name(). +- * +- * This function is also used in gtkfilechooserbutton.c ++struct get_selected_path_closure { ++ GtkFileChooserDefault *impl; ++ const GtkFilePath *path; ++}; ++ ++/* Handles key press events on the file list, so that we can trap Enter to ++ * activate the default button on our own. Also, checks to see if '/' has been ++ * pressed. See comment by tree_view_keybinding_cb() for more details. + */ +-gchar * +-_gtk_file_chooser_label_for_uri (const gchar *uri) ++static gboolean ++trap_activate_cb (GtkWidget *widget, ++ GdkEventKey *event, ++ gpointer data) + { +- const gchar *path, *start, *end, *p; +- gchar *host, *label; +- +- start = strstr (uri, "://"); +- start += 3; +- path = strchr (start, '/'); +- +- if (path) +- end = path; +- else +- { +- end = uri + strlen (uri); +- path = "/"; +- } ++ GtkFileChooserDefault *impl; ++ int modifiers; + +- /* strip username */ +- p = strchr (start, '@'); +- if (p && p < end) +- { +- start = p + 1; +- } +- +- p = strchr (start, ':'); +- if (p && p < end) +- end = p; +- +- host = g_strndup (start, end - start); ++ impl = (GtkFileChooserDefault *) data; + +- /* Translators: the first string is a path and the second string +- * is a hostname. Nautilus and the panel contain the same string +- * to translate. +- */ +- label = g_strdup_printf (_("%1$s on %2$s"), path, host); +- +- g_free (host); ++ modifiers = gtk_accelerator_get_default_mod_mask (); + +- return label; +-} ++ if ((event->keyval == GDK_Return ++ || event->keyval == GDK_ISO_Enter ++ || event->keyval == GDK_KP_Enter ++ || event->keyval == GDK_space) ++ && ((event->state & modifiers) == 0) ++ && !(impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER || ++ impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)) ++ { ++ GtkWindow *window; + +-/* Inserts a path in the shortcuts tree, making a copy of it; alternatively, +- * inserts a volume. A position of -1 indicates the end of the tree. +- */ +-static void +-shortcuts_insert_path (GtkFileChooserDefault *impl, +- int pos, +- ShortcutType shortcut_type, +- GtkFileSystemVolume *volume, +- const GtkFilePath *path, +- const char *label, +- gboolean removable, +- ShortcutsIndex type) +-{ +- char *label_copy; +- GdkPixbuf *pixbuf = NULL; +- gpointer data = NULL; +- GtkTreeIter iter; +- GtkIconTheme *icon_theme; ++ window = get_toplevel (widget); ++ if (window ++ && widget != window->default_widget ++ && !(widget == window->focus_widget && ++ (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget)))) ++ { ++ gtk_window_activate_default (window); ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++} + +- profile_start ("start", (shortcut_type == SHORTCUT_TYPE_VOLUME) ? "volume" +- : ((shortcut_type == SHORTCUT_TYPE_PATH) ? (char *) path : NULL)); ++static gboolean ++list_button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) ++{ ++ GtkTreeView * tree = GTK_TREE_VIEW (widget); ++ GtkFileChooserDefault *impl = data; ++ GtkTreePath *path; + +- if (shortcut_type == SHORTCUT_TYPE_VOLUME) ++ if (event->type != GDK_BUTTON_PRESS || ++ !gtk_tree_view_get_path_at_pos (tree, (gint)event->x, (gint)event->y, ++ &path, NULL, NULL, NULL)) + { +- data = volume; +- label_copy = gtk_file_system_volume_get_display_name (impl->file_system, volume); +- pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl), +- impl->icon_size, NULL); ++ return FALSE; + } +- else if (shortcut_type == SHORTCUT_TYPE_PATH) +- { +- if (gtk_file_system_path_is_local (impl->file_system, path)) +- { +- struct ShortcutsInsertRequest *request; +- GtkFileSystemHandle *handle; +- GtkTreePath *p; +- +- request = g_new0 (struct ShortcutsInsertRequest, 1); +- request->impl = g_object_ref (impl); +- request->path = gtk_file_path_copy (path); +- request->name_only = TRUE; +- request->removable = removable; +- request->pos = pos; +- request->type = type; +- if (label) +- request->label_copy = g_strdup (label); +- +- if (pos == -1) +- gtk_list_store_append (impl->shortcuts_model, &iter); +- else +- gtk_list_store_insert (impl->shortcuts_model, &iter, pos); +- +- p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter); +- request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), p); +- gtk_tree_path_free (p); +- +- handle = gtk_file_system_get_info (request->impl->file_system, request->path, +- GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_HIDDEN | GTK_FILE_INFO_ICON, +- get_file_info_finished, request); +- +- gtk_list_store_set (impl->shortcuts_model, &iter, +- SHORTCUTS_COL_DATA, gtk_file_path_copy (path), +- SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_PATH, +- SHORTCUTS_COL_HANDLE, handle, +- -1); + +- shortcuts_update_count (impl, type, 1); +- +- return; +- } +- else +- { +- /* Don't call get_info for remote paths to avoid latency and +- * auth dialogs. +- */ +- data = gtk_file_path_copy (path); +- if (label) +- label_copy = g_strdup (label); +- else +- { +- gchar *uri; ++ impl->list_press_time = event->time; ++ impl->list_press_path = path; + +- uri = gtk_file_system_path_to_uri (impl->file_system, path); ++ return FALSE; ++} + +- label_copy = _gtk_file_chooser_label_for_uri (uri); ++static gboolean ++list_button_release (GtkWidget *widget, GdkEventButton *event, gpointer data) ++{ ++ GtkTreeView * tree = GTK_TREE_VIEW (widget); ++ GtkFileChooserDefault *impl = data; ++ GtkTreePath *path = NULL; ++ gboolean retval = FALSE; + +- g_free (uri); +- } +- +- /* If we switch to a better bookmarks file format (XBEL), we +- * should use mime info to get a better icon. +- */ +- icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl))); +- pixbuf = gtk_icon_theme_load_icon (icon_theme, "gnome-fs-share", +- impl->icon_size, 0, NULL); +- } +- } +- else ++ if (!impl->list_press_time || ++ !impl->list_press_path || ++ event->type != GDK_BUTTON_RELEASE || ++ !gtk_tree_view_get_path_at_pos (tree, (gint)event->x, (gint)event->y, ++ &path, NULL, NULL, NULL)) + { +- g_assert_not_reached (); ++ goto done; ++ } + +- return; ++ if (event->time - impl->list_press_time > LONG_CLICK_LENGTH && ++ !gtk_tree_path_compare (impl->list_press_path, path)) ++ { ++ retval = TRUE; ++ list_row_activated (tree, path, NULL, impl); + } + +- if (pos == -1) +- gtk_list_store_append (impl->shortcuts_model, &iter); +- else +- gtk_list_store_insert (impl->shortcuts_model, &iter, pos); ++ done: ++ if (path) ++ gtk_tree_path_free (path); + +- shortcuts_update_count (impl, type, 1); ++ impl->list_press_time = 0; + +- gtk_list_store_set (impl->shortcuts_model, &iter, +- SHORTCUTS_COL_PIXBUF, pixbuf, +- SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE, +- SHORTCUTS_COL_NAME, label_copy, +- SHORTCUTS_COL_DATA, data, +- SHORTCUTS_COL_TYPE, shortcut_type, +- SHORTCUTS_COL_REMOVABLE, removable, +- SHORTCUTS_COL_HANDLE, NULL, +- -1); +- +- if (impl->shortcuts_pane_filter_model) +- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model)); +- +- if (impl->shortcuts_combo_filter_model) +- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model)); +- +- if (type == SHORTCUTS_CURRENT_FOLDER && impl->save_folder_combo != NULL) +- { +- /* The current folder is updated via _activate_iter(), don't +- * have save_folder_combo_changed_cb() call _activate_iter() +- * again. +- */ +- gint combo_pos = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER); ++ if (impl->list_press_path) ++ { ++ gtk_tree_path_free (impl->list_press_path); ++ impl->list_press_path = NULL; ++ } + +- if (impl->has_search) +- combo_pos -= 1; ++ return FALSE; ++} + +- if (impl->has_recent) +- combo_pos -= 2; +- +- g_signal_handlers_block_by_func (impl->save_folder_combo, +- G_CALLBACK (save_folder_combo_changed_cb), +- impl); +- +- gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), combo_pos); +- g_signal_handlers_unblock_by_func (impl->save_folder_combo, +- G_CALLBACK (save_folder_combo_changed_cb), +- impl); +- } + +- g_free (label_copy); ++/* Creates the widgets for the file list */ ++static GtkWidget * ++create_file_list (GtkFileChooserDefault *impl) ++{ ++ GtkWidget *swin; ++ GtkTreeSelection *selection; ++ GtkTreeViewColumn *column; ++ GtkCellRenderer *renderer; + +- if (pixbuf) +- g_object_unref (pixbuf); ++ /* Scrolled window */ + +- profile_end ("end", NULL); +-} ++ swin = gtk_scrolled_window_new (NULL, NULL); ++ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin), ++ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); ++ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin), ++ GTK_SHADOW_IN); + +-static void +-shortcuts_append_search (GtkFileChooserDefault *impl) +-{ +- GdkPixbuf *pixbuf; +- GtkTreeIter iter; ++ /* Tree/list view */ + +- pixbuf = render_search_icon (impl); ++ impl->browse_files_tree_view = gtk_tree_view_new (); ++#ifdef PROFILE_FILE_CHOOSER ++ g_object_set_data (G_OBJECT (impl->browse_files_tree_view), "fmq-name", "file_list"); ++#endif ++ g_object_set_data (G_OBJECT (impl->browse_files_tree_view), I_("GtkFileChooserDefault"), impl); ++ atk_object_set_name (gtk_widget_get_accessible (impl->browse_files_tree_view), _("Files")); + +- gtk_list_store_append (impl->shortcuts_model, &iter); +- gtk_list_store_set (impl->shortcuts_model, &iter, +- SHORTCUTS_COL_PIXBUF, pixbuf, +- SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE, +- SHORTCUTS_COL_NAME, _("Search"), +- SHORTCUTS_COL_DAT